Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
430eae1
Make three over-claiming trace tags true (issues #64, #71)
claude Aug 28, 2026
0499d26
params.lock format version 2: record each parameter's shape (issues #…
claude Aug 28, 2026
b9ec45d
Refuse a manual-test document with no readable verdict (issue #34)
claude Aug 28, 2026
6644aeb
Drive three tests through the real path they claimed to cover (#114, …
claude Aug 28, 2026
95bf9d7
Make three tests able to fail (#125, #55, #50)
claude Aug 28, 2026
3a5f515
Make three fixture tests independent of what they check (#134, #135, …
claude Aug 28, 2026
d5e8834
Regenerate the test plan for wave 1's two tag demotions
claude Aug 28, 2026
81792a9
Three failure modes documented as impossible (#126, #109, #116)
claude Aug 28, 2026
9828eda
Refuse a float WAV with non-finite taps at load (#52, #53)
claude Aug 28, 2026
a7b97aa
Reject three hostile .nam shapes at load, not on the audio thread (#4…
claude Aug 28, 2026
0ea98a9
namir-platform: asm soundness, thread priority, and the fallback targ…
claude Aug 28, 2026
ab68cd2
Fix the gate's envelope detector, closing FR-GATE-020 (#123, #124)
claude Aug 28, 2026
e594a6d
Engine handover, bypass and block validation (#56-#63)
claude Aug 28, 2026
2346917
namir-library: stop the scanner destroying what it cannot see (#65-#73)
claude Aug 28, 2026
66c876c
Bound the notice list vertically, the half of #42 nobody had looked at
claude Aug 28, 2026
bb9d6c9
Make generated fixtures reproducible across platforms (#133, #136, #1…
claude Aug 28, 2026
3c99364
Declare the new corpus assets, regenerate the plan
claude Aug 28, 2026
84875af
Record where five decisions had drifted from the built behaviour
claude Aug 28, 2026
dab593c
namir-core contracts, and a duplicate params.lock key (#128-#131, #118)
claude Aug 28, 2026
ef531f0
namir-state: clear a reference, resolve an embed, refuse an oversized…
claude Aug 28, 2026
1e48edc
Bound activation storage before allocating it (#48, #51, #54, #127)
claude Aug 28, 2026
e914e11
namir-worker: three timing promises kept, one corrected (#106-#111)
claude Aug 28, 2026
63afed5
Save and recall a preset from the interface (#100, #84-#98)
claude Aug 28, 2026
7378f71
Hoist the preset location rule into namir-platform
claude Aug 28, 2026
5404f30
Bypass without prepare_crosscutting, and stop NaN poisoning the meter…
claude Aug 29, 2026
d236e00
A failable virtual device, and the stream stop it proved missing (#24…
claude Aug 29, 2026
1b632d4
Probe that block splitting changes nothing, and what it caught (#30)
claude Aug 29, 2026
0b3e388
Read compound Verify methods, and build FR-STATE-040's missing half (…
claude Aug 29, 2026
2875a40
Regenerate the test plan for compound Verify methods and FR-IO-070
claude Aug 29, 2026
085bd85
Record how a compound Verify method is covered (#27)
claude Aug 29, 2026
1864c12
Give the gesture workaround a tripwire, and stop the manifest lying (…
claude Aug 30, 2026
c45f2d2
Open the window without sRGB when no framebuffer offers it (#143)
claude Aug 30, 2026
37c7dc0
Crossfade the global bypass, and make a first load audible in its own…
claude Aug 30, 2026
dde8488
CI: open and render the interface with no display (#143)
claude Aug 30, 2026
636997c
Wait for the three axes rather than assuming two seconds (#145 CI)
claude Aug 30, 2026
0f31586
Preserve a reference this build could not read (review finding 4)
claude Aug 30, 2026
65d51d3
Index a symlinked directory once, and refuse an IR that resamples to …
claude Aug 30, 2026
58027e0
Run the five unwired gates in CI, and give headless-window teeth
claude Aug 30, 2026
b746690
Make the log ceiling a property of the file, and refuse Win32 device …
claude Aug 30, 2026
a2e28db
Show the recalled name, guard an overwrite, probe as the app opens
claude Aug 30, 2026
ba436e2
Narrow the producer hold, and bound the lock wait (review submit note)
claude Aug 30, 2026
b8bcc21
Hold a resampled handover until its incoming slot has primed (review …
claude Aug 30, 2026
c442eec
Bound the reads, wait for the index, correct a stale latency claim (r…
claude Aug 30, 2026
58bd85a
Wait for the recalled IR, not just the recalled parameter (Windows CI)
claude Aug 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -141,9 +141,49 @@ jobs:
- name: xtask rt-logging (FR-ERR-030)
run: cargo run -p xtask -- rt-logging

# M15 review, finding 3. Five `xtask` subcommands were wired into `xtask/src/main.rs` and
# into no CI step at all: the three steps that follow this comment, `assets` (below
# `params-lock`, beside the other generate-and-diff checks) and `schema` (below `identity`).
# Four of the five -- `network-free`, `error-catalogue`, `feature-guard`, `assets` -- have
# been unwired since M14 built them; `schema` is new on this branch. Each is the *entire*
# mechanism behind a claim made elsewhere in the repository: `crates/namir-fixtures/src/lib.rs`
# carries a plain `// trace: NFR-LIC-050` whose only check is `assets`, `deny.toml` names
# `xtask network-free` as FR-ERR-060's first-party half, and `crates/namir-core/src/error.rs`
# cites `error-catalogue` in eight places. `ci-commands` could not catch this: both its limbs
# compare README.md against this file, so a subcommand named in neither is invisible to it --
# which is why the README's gate block gained the same five lines in this change. They are in
# this job for the reason every step above is: line-based scans over checked-in source, with
# no OS-specific behaviour to matrix over.
#
# FR-ERR-060/NFR-SEC-030's first-party half. `deny.toml`'s `[bans]` list is the *dependency*
# half (the `network-free` job below runs it); this one refuses any `std::net` name under
# `crates/`, which no dependency ban can see because a first-party crate needs no dependency
# at all to open a socket.
- name: xtask network-free (FR-ERR-060, NFR-SEC-030)
run: cargo run -p xtask -- network-free

# FR-ERR-020's second conjunct -- "every error path in the code maps to an entry" -- which
# had no artifact before M14 and no gate before this step.
- name: xtask error-catalogue (FR-ERR-020)
run: cargo run -p xtask -- error-catalogue

# §22 R-17: `--all-features` in any build or release command silently links `clack-host`
# into the shipped cdylib, and `host-ext-tests` must stay non-default. The row's own
# mitigation said "nothing mechanical guards the linkage itself"; this is the mechanism, and
# until now it ran nowhere.
- name: xtask feature-guard (§22 R-17)
run: cargo run -p xtask -- feature-guard

- name: xtask params-lock (FR-PARAM-020)
run: cargo run -p xtask -- params-lock

# NFR-LIC-050's whole mechanism: every checked-in asset under `crates/` is in
# `crates/namir-fixtures/assets.lock` with a declared provenance and a matching hash. A
# captured `.wav` committed beside the generated fixtures renders as `unrecorded`, which
# fails this check -- but only if something runs it, which nothing did until now.
- name: xtask assets (NFR-LIC-050)
run: cargo run -p xtask -- assets

# M7: NFR-LIC-030's attribution-file freshness gate. Pure static/text check over
# `cargo metadata`'s resolve graph, same reasoning as the two steps above for living in this
# job rather than its own -- no OS-specific behaviour to matrix over.
Expand All @@ -158,6 +198,14 @@ jobs:
- name: xtask identity (NFR-DOC-040, NFR-LIC-070)
run: cargo run -p xtask -- identity

# FR-STATE-040's `S` half (issue #27), as a build-time check over the hand-authored
# `namir-state` corpus and the sample `xtask preset` writes. `namir-state`'s own
# `tests/schema.rs` runs the same validator under `cargo test --workspace`; this step is the
# form FRS §1.5's `S` names, and the requirement's compound `M plus S` method resolves only
# when both halves are there.
- name: xtask schema (FR-STATE-040)
run: cargo run -p xtask -- schema

# M14 Phase 5: NFR-BUILD-020's *second* half. `identity` above asserts that README.md still
# contains the build, run and test commands -- they cannot silently disappear from it. It
# compares them against literals in `xtask/src/identity.rs` and against nothing in this file,
Expand Down Expand Up @@ -241,6 +289,72 @@ jobs:
run: cargo run -p xtask -- traceability
continue-on-error: true

# M15 (issue #143): does the interface actually open and paint on a machine with no display?
#
# Every other `namir-ui` test is headless by construction -- they drive `egui::Context::run_ui`
# and assert over the shapes `render` painted, which never touches a windowing stack. That is a
# deliberate design (the crate's own tests say so) and it leaves one thing unasserted: that a
# window opens at all. Until #143 it did not, on any machine without a physical display, and
# nothing here would have said so -- `baseview` asked `glXChooseFBConfig` for an sRGB-capable
# framebuffer, which a software X server offers on none of its configs, and the open panicked.
#
# This runs the crate's existing unattended smoke example, which renders a fixed number of frames
# and closes itself, against Xvfb. It is the step that makes #143's fallback a thing CI checks
# rather than a thing someone verified once.
#
# Required, not informational: a headless-window check permitted to fail asserts nothing, and the
# whole value of #143 is turning "needs a human at a screen" into "runs on every push". It has
# NOT been executed on a GitHub-hosted runner -- only under `Xvfb :99 -screen 0 1280x1024x24` on
# Mesa 25.2.8/llvmpipe, where the example panicked before #143 and renders its 90 frames and
# exits 0 after it. If the runner's GL stack differs, this job is where that surfaces.
#
# `libgl1-mesa-dri` is the llvmpipe software rasteriser: the runner has no GPU, so without it
# there is a GLX server and no driver to render through. The build-time X and ALSA headers are
# already satisfied on this image by the build + test job, which compiles the same workspace.
headless-window:
name: headless window smoke (FR-UI-010, issue #143)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable

- uses: Swatinem/rust-cache@v2

- name: Install Xvfb and a software GL driver
run: sudo apt-get update && sudo apt-get install -y xvfb libgl1-mesa-dri

# `xvfb-run -a` picks a free display rather than hard-coding :99, so this cannot collide with
# anything else the runner starts. The screen is 24-bit because `EguiWindowSettings`' default
# asks for a 24-bit depth buffer.
#
# Two panic messages on stderr before it succeeds are expected, not a failure: #143's
# fallback learns the framebuffer is unavailable by catching `baseview`'s panic, that library
# having no fallible open.
#
# **The assertion is the frame count, not the exit status alone** (M15 review, note b). This
# step asserted only that the example exited 0, and that was not the property it was here to
# check: `EguiWindow::open_blocking` runs the window on its own thread and joins it with
# `unwrap_or_else(eprintln!)`, and `open_with_srgb_fallback` catches only the *first*
# attempt's panic -- so a `namir_ui::render` that panicked on every single frame would unwind
# that thread, be reported to stderr, return normally, print "window closed cleanly" and
# exit 0. A required job that a totally broken interface passes is not a gate.
#
# So the example counts the frames whose `render` returned, exits 1 unless it drew all of
# them, and prints the count; and this step additionally requires that line, with the number
# read out of the example's own `FRAMES_BEFORE_CLOSE` rather than copied here -- a check that
# hard-codes 90 goes quietly green if the constant changes to something smaller. `pipefail`
# is what keeps `| tee` from masking the example's own status.
- name: Open and render the interface with no display (issue #143)
run: |
set -euo pipefail
example=crates/namir-ui/examples/manual_window_smoke.rs
frames=$(sed -n 's/^const FRAMES_BEFORE_CLOSE: u64 = \([0-9][0-9]*\);$/\1/p' "$example")
test -n "$frames"
echo "expecting $frames rendered frames"
xvfb-run -a --server-args="-screen 0 1280x1024x24" cargo run -p namir-ui --example manual_window_smoke 2>&1 | tee smoke.log
grep -qx "manual_window_smoke: rendered $frames of $frames frames; window closed cleanly" smoke.log

# Covers D-18.1's "cargo-deny licence audit" (NFR-LIC-020). deny.toml already exists at the
# repo root; this job just runs it in CI instead of by hand.
license-audit:
Expand All @@ -265,6 +379,25 @@ jobs:
with:
command: check sources

# M15 review, note (a): the **fourth** sub-check, and the last one nothing ran. `cargo deny
# check` -- the command README.md documents, annotated there as an "advisory ... audit" --
# runs advisories, bans, licenses and sources; CI ran the last three across three steps and
# never the first, and `deny.toml` has no `[advisories]` section, so a RUSTSEC advisory could
# enter Cargo.lock with every gate green. `xtask ci-commands` reported the two files in
# agreement while that was true, because its token-prefix rule read the narrower `check
# licenses` as exercising the broader documented `check`; that rule now refuses a sub-check
# invocation for a bare `cargo deny check` and instead requires the union of the sub-check
# steps to cover all four, which is what this step completes.
#
# No `[advisories]` section is added with it: cargo-deny's own defaults are what the
# documented bare command has always run, and this repository's practice of recording
# `cargo deny check ... green on advisories, bans, licenses and sources` by hand at each
# dependency adoption (`docs/02-architecture.md` §17, §21) is the evidence that the standing
# state is clean. This step is what keeps it so without anyone typing the command.
- uses: EmbarkStudios/cargo-deny-action@v2
with:
command: check advisories

# M7: D-18.2/FR-ERR-070.5's network-free build gate, deferred here by design since M1 (see this
# file's own header comment above) until there was a whole product to check against. FR-ERR-070's
# own *Verify* method is S -- "a build-time check that no network-capable dependency is linked
Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -29,3 +29,6 @@ trace.etl
# running the validator against it. A ~7 MB cdylib copy, reproducible from a build; running that
# job locally leaves one behind.
staging/

# Written by the headless-window smoke step (.github/workflows/ci.yml) when run by hand.
smoke.log
11 changes: 9 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,7 +201,7 @@ Cargo.toml comments), `rtrb` for both SPSC rings, and — decided at M9's P0 pas
`clack-host` as a `namir-clap` **dev**-dependency for the in-process CLAP host harness, adopted
precisely because `clack-extensions`' own `__doc_utils.rs` instantiates a plugin through
`PluginEntry::load_from_clack` with no `unsafe` at all. Checked this pass: the only `unsafe` blocks
anywhere under `crates/` are one in `gui.rs`, five in `denormal.rs` and five in
anywhere under `crates/` are one in `gui.rs`, five in `denormal.rs` and six in
`thread_priority.rs` — plus that file's `unsafe extern "system"` declaration block, which edition
2024 requires of any `extern` block — and none at all in any bench or integration test, where there
should be none. Any new `unsafe` block outside those three files is a bug, not a style choice —
Expand Down Expand Up @@ -303,7 +303,14 @@ in the roadmap for the full investigation). Before trusting a benchmark number:
method asks for. The only `NeuralAmpModelerCore` comparison in the
tree is S-1's, under `spikes/`, excluded from the workspace and not runnable under `cargo test`.
The tool reported the requirement plainly covered from M3 until M9a's sweep demoted both sites to
`trace-partial:`. Read D-23.1 (`docs/02-architecture.md` §23) for the full rule before tagging
`trace-partial:`. **That illustration is itself now out of date, and is kept because the reasoning
it teaches is the point.** M14 Phase 4b (changelog 0.34) rendered two generated A2 fixtures through
the pinned reference build and asserted the comparison in-process, so FR-NAM-030's tags live in
`crates/namir-nam/tests/golden_reference.rs` and are plain — closed by building the missing
evidence, not by promoting a tag. So the sentence above about S-1 being the only
`NeuralAmpModelerCore` comparison in the tree no longer holds. What has *not* changed is the shape
of the lesson: no trainer-produced A2 export has ever been loaded, so a misreading of the schema
shared between generator, parser and reference target is still invisible to every test here. Read D-23.1 (`docs/02-architecture.md` §23) for the full rule before tagging
anything non-obvious.
- **Expect `trace-partial:` to be the common case, not a rarity.** M9a swept every Must against
D-23.1's two questions and demoted 54 tags from plain `trace:` in one comment-only pass — no test
Expand Down
36 changes: 24 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,20 +93,32 @@ its own — is:
cargo fmt --all -- --check
cargo clippy --workspace --all-targets -- -D warnings
cargo test --workspace --no-fail-fast
cargo run -p xtask -- layering # crate dependency-graph and platform-cfg lint
cargo run -p xtask -- rt-logging # no audio-thread module names the logger
cargo run -p xtask -- params-lock # params.lock matches the parameter registry
cargo run -p xtask -- attribution # THIRD-PARTY-NOTICES.md is current
cargo run -p xtask -- identity # brand mark, README and TRADEMARK.md are current
cargo run -p xtask -- ci-commands # this file's commands are the ones CI runs
cargo run -p xtask -- traceability # requirement coverage and generated test-plan diff
cargo deny check # licence, advisory and dependency-ban audit
cargo run -p xtask -- layering # crate dependency-graph and platform-cfg lint
cargo run -p xtask -- rt-logging # no audio-thread module names the logger
cargo run -p xtask -- network-free # no first-party crate names a socket API
cargo run -p xtask -- error-catalogue # every error code is a named entry in a catalogue
cargo run -p xtask -- feature-guard # no --all-features; host-ext-tests stays non-default
cargo run -p xtask -- params-lock # params.lock matches the parameter registry
cargo run -p xtask -- assets # every checked-in test asset declares its provenance
cargo run -p xtask -- attribution # THIRD-PARTY-NOTICES.md is current
cargo run -p xtask -- identity # brand mark, README and TRADEMARK.md are current
cargo run -p xtask -- schema # state and preset documents match the format document
cargo run -p xtask -- ci-commands # this file's commands are the ones CI runs
cargo run -p xtask -- traceability # requirement coverage and generated test-plan diff
cargo deny check # advisory, licence, dependency-ban and source audit
```

`params-lock`, `attribution`, `identity` and `traceability` take `--write` to regenerate their
artifact instead of verifying it. `traceability` also takes `--allow-uncovered`, which is the form
CI gates on until requirement coverage reaches zero gaps; the plain form runs alongside it as an
informational step.
`params-lock`, `attribution`, `assets`, `identity` and `traceability` take `--write` to regenerate
their artifact instead of verifying it — except that `assets` never writes the provenance column,
which is a human declaration a tool cannot mint. `traceability` also takes `--allow-uncovered`,
which is the form CI gates on until requirement coverage reaches zero gaps; the plain form runs
alongside it as an informational step. `schema` takes zero or more paths and checks the checked-in
corpus when given none.

`cargo deny check` runs four sub-checks — advisories, bans, licenses and sources — and CI runs each
of them as its own `cargo-deny-action` step rather than the bare command. `xtask ci-commands`
requires those steps to cover all four between them, because a `cargo deny check <sub-check>` step
runs *less* than the command documented here, not more.

A pre-commit hook running the fast half of the gate (`cargo fmt --check` plus
`cargo check --workspace --all-targets`) is available; opt in once per clone with:
Expand Down
95 changes: 0 additions & 95 deletions crates/namir-app/examples/list-devices.rs

This file was deleted.

Loading
Loading