Repository navigation
The 2026-10 adversarial audit and its response: S0 to S5, family version 0.6.0 - #72
Merged
Merged
Conversation
… reshaping) Nine independent finders over the rational engine's datapath, fixed-point profiles, design layer and generators, the three C ABIs, the test battery (including mutation testing), the family rules, build and CI, the docs' stated numbers, the bridge/async regression surface, and real-time safety under sanitizers; triage; then three-lens adversarial verification of every finding above nit level. 18 confirmed (4 major, 14 minor), 1 disputed, 16 nits, plus the record of what was checked and found sound and what the host-only audit could not cover. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
Seventeen mutants of the rational headers against the host battery: fourteen killed, three survived, all of them the tie direction of the fixed-point rounding point (the measured form of F13). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
Twelve proposed decisions and six pull requests in order: DspTap's chain.h first, then rational's correctness and test gaps, the three C ABIs, the async vocabulary pass under 0.6.0, the docs sweep, and the gates against recurrence; every audit finding and cohesion item mapped to its step. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
…he inequality it is DspTap 20a06ac: tap::dsp::chain resets the stages it is given and exposes them read-only, so a stage pulled and then chained can no longer write past the scratch sized for process-reached states (audit F01); its contract block states outputs_for(frames_needed(k)) >= k, not == k, and names no chain pull (F03). Here: rational/PLAN.md 2.5 says the same, stage.h's contract block carries the bound the chain relies on, and test_chain.cpp pins the audit's scenario (an up-by-8 stage pulled one frame, then moved into a chain, equals a chain of fresh stages bit for bit; the test fails against the previous chain) and that no chain hands out a mutable stage. Gate: 291 ctest entries green; every engine's printed hashes and measured lines identical before and after the bump (60 hashes). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
- stage.h: schedule_entry::advance widens to uint32_t; a mixed ratio of the charter with M >= 256 L (ratio<3, 1024>, ratio<2, 729>) once truncated its advances to a byte and ran silently wrong (F02). Stage.WideRatiosOfTheCharterRunTheSchedule pins the schedule sum, the chunking invariance and the accounting for both at a 40 dB custom spec. - The tie direction of the single rounding point is pinned at the stage (F13, the audit's three surviving mutants): the impulse test's oracle is now the test's own round-half-up of the one product, and ImpulseTiesRoundHalfUp drives amplitudes whose products are exact ties (Q15 8192 / 16384 / -32768 by table gain, Q31 2^29) through the unity, power-of-two-divided and Q31 paths; bridge gets the same test. - Reset tests exercise a decimator and a decimator chain mid-stream (F12). - compile_fail isolates L != M with ratio<1, 1>; four cases (F07). - design.h: the search-bound comment states 2.8x the longest pin and the exceptions name the bound; validate() names the relaxed passband; stage_taps_per_phase() validates and throws like design_stage (F08, F22). - FixedPoint.RelaxedQ15TablesStopbandsAreStated measures every relaxed Q15 design; the economy half-band at 147/160 attains -67.6 dB, stated in PLAN.md section 6, CLAUDE.md and the README (F05). - bare_metal_main.cpp: the selected-test floor is 80 against 99 (F11). - make_reference_vectors.py emits clang-format guards; the committed header regenerates byte-identical, token-identical to before (F23). - examples/multirate_chain.cpp, the example the layout promised; the cross-validation row struck with its reason (F18); rational.h's status, the plan's swapped deviations, the stale pre-lever numbers (F20, F28, F34); the wrap above SIZE_MAX / L documented (F35). Gate: 298 ctest entries green; every pre-change measured line and all 60 output hashes identical; clang -Werror and clang-tidy clean on the changed tests; the mutation harness re-run against this tree is recorded in the audit report's follow-up (M1, M2, M4a, M4b, M5a killed as before; M3 is an equivalent mutant, finalize_output's unity branch being unreachable for Q15, whose live rounding point the tie test now pins). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
…e error shape - <engine>.Family.ExportedSymbolsArePinned: nm on each built library against tests/family/symbols_<engine>.txt (14 / 17 / 23 entry points), anything else in the dynamic table a failure; shown red against a build without the hidden preset (883 symbols). The book's sentence and CLAUDE.md now name the test (F04). - TAP_SR_<ENGINE>_API on every declaration (dllexport while building, dllimport for a consumer, default visibility elsewhere); the shims' visibility pragmas go; the MSVC leg builds the C ABI and runs the CApi suites, the DLL emitted beside the test executable (F10). - async: a preset outside 0..2 returns NULL as the siblings' profile does, pinned (F09); bridge's and rational's headers state the thread contract (F24); async's PLAN counts fourteen functions in all (F33). Gate: 301 ctest entries green; hashes and measured lines unchanged; the headers compile as C11 consumers; the shims clean under clang -Werror. The MSVC leg is not reproducible here and is the one piece CI must show. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
async is brought to the family's vocabulary without touching its datapath or its ladder's numbers (the cohesion assessment's C1 to C4; A4, A5, A9, A11 of the audit response plan): - preset retires for profile in every identifier, comment and document; filter_spec::economy() is filter_spec::program() (one meaning per profile name across the family: async's tiers are image rejection through the interpolated bank, not Nyquist stopbands, so they keep their own names and the one collision goes). No alias (D7). - The async C ABI takes the siblings' shape: tap_sr_async_create(hz, target_latency_frames, profile, channels) and create_format(hz, target_latency_frames, profile, format, channels), profile and format before channels, unsigned channels; the tests, the notebooks' ctypes declarations and the header's contract follow. - test_asrc_* become test_lock / test_program / test_quality / test_quality_16k, bench_asrc becomes bench_converter; every reference, the book's include anchors among them, follows (the notebook filenames stay, the book links them). - async.h's umbrella comment is rewritten as the third of three engines (the charter, the boundaries as identity, the composition, the profiles); sample_traits.h and polyphase_filter.h name the siblings. - async/README.md takes the sibling shape: Quick start, The boundaries are identity, not policy, Position in the Tap family (three engines), Build, then its own measured sections; version 0.6.0 (F15). rational's README gains the family section; bridge's diagram shows three engines. - The old name leaves the present tense: bluetooth_bridge's label and comments, bridge's CMake options, ratio.h, the cross-validation and skeleton tests, the reference generator, the notebooks' sources, the book's Part 5; the composition's latency is 1.93 ms everywhere (F29). "formerly RatioTap" stays where it is history. - Version 0.6.0 in the three umbrella headers and the root project(), version_macros.cpp re-pinned, CApi.VersionIsBitPacked expects 0x000600. Gate: 301 ctest entries green; all 60 output hash values and every measured line identical to the pre-change run (the async hash labels read program where they read economy); async's shim and tests clean under clang -Werror; every changed source clang-format clean; every book include anchor resolves. The rendered titles in scripts/book_figures.py keep the old word until the figures are next regenerated (no matplotlib here); noted in the plan. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
- Root README: the profile table (one meaning per name across the family, the three ladders with their numbers), three engines in the build block, the test naming, the ratchet, the layout and the dependency rule (F17). - Root PLAN: the status line records the executed migration, the rational plan and the audit; D13 carries 0.5.0 and 0.6.0; the "Next" paragraph says the Q15 levers shipped and states the current numbers (F19, F30). - Doxyfile indexes the rational engine and describes the family (F14). - bridge's README selects its tests by the bridge label and lists the ratchet flags once; rational's README names macs_per_output_exact() (F16, F31); the composition's latency reads 1.93 ms there too (F29). - The Q31 figure carries its provenance in stage.h and the README (F06). - The book's C ABI chapter describes create_format's body (F32); the CI workflow comments say every engine (F26; F27 landed with S1). - F25 (the STYLE.md banner template) is a taphouse change, referred. Gate: the book's include anchors resolve; no "both engines" wording remains outside the history records; docs only, nothing built changes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
- scripts/retired_words.txt and scripts/check_retired_words.py: every tracked text file, notebook source cells included and outputs excluded, must carry no retired word (the bridge engine's pre-merge name in the present tense, the old async test and bench names, preset, async's retired economy(), the retired ratio label, a stale rational status line); the allowed senses and the history records are listed in the checker. A job in style.yml runs it. Shown red on its first run: it found two leftovers of S3 (a header comment and a notebook cell), fixed here. - <name>.Family.ReadmeQuickStartCompiles for the root README and each engine's: the first ```cpp block, extracted at configure time (tests/family/readme_snippet.cmake) with a prelude declaring the caller's buffers, built by its test under the engine's label. - Root CLAUDE.md: the one-meaning-per-profile-name rule (A4) and the rule that a change to an engine's shared vocabulary updates the root README's table and the siblings' READMEs in the same PR; the gates named under Style. The last two-engine phrases in cmake/retired_options.cmake, bridge/CLAUDE.md and async/docs/PERFORMANCE.md. Gate: 305 ctest entries green (the four quick-start tests among them); the vocabulary check clean over the tree. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
Eighteen of nineteen killed; the nineteenth is an equivalent mutant (finalize_output's unity branch is unreachable for Q15), and the live rounding points of both formats, mutated in the substrate, are killed by the tie test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
scripts/book_figures.py's two rendered strings say profiles; the figure is regenerated with the pinned matplotlib (requirements.lock, 3.11.2), which is why the SVG's path data moves too. The vocabulary checker's allowance for those two lines goes. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
…0.6.0 The three notebooks whose code cells changed in S3 (the async C ABI's argument order, the bridge demo's engine name) re-executed through the pinned environment (requirements.lock) against the shipping C++ on this branch; no measured behaviour changed, and the outputs now match their cells (the bridge demo prints bridge 0.6.0). The comparison and RBJ notebooks changed in prose only and keep their outputs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
The clang-format job on #72 wrapped the one overlong line S1 added. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
The identical tree, now reachable from main after the squash merge (d7ebe4b for 20a06ac), per the release flow. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
…2 bits for the wide ratios The M55 ratchet on #72 measured the price of S1's uint32_t advance: the 8-byte schedule entry cost the Q15 interpolators 8.7 % (up2 and up3), the 2/3 mixed stage 3.7 % and the float up-by-2 3.5 %, every checksum unchanged. The entry is now templated on the ratio: a byte wherever every advance fits one (ceil(M / L) <= 255, the whole vocabulary: the 4-byte entry the baselines measured) and 32 bits for the wide ratios of the charter (ratio<3, 1024>: 342), so no charter ratio is truncated (F02) and no pinned count moves. sizeof pinned by a probe: 4 for up_2, ratio_3_8 and ratio<3, 512>, 8 for ratio<3, 1024>. Host: 123 rational entries green. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
tap
pushed a commit
that referenced
this pull request
Oct 9, 2026
The clang-format job on #72 wrapped the one overlong line S1 added. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
tap
pushed a commit
that referenced
this pull request
Oct 9, 2026
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01G3HxzEGiZp7jStoMuYNuBK
This was referenced Oct 9, 2026
tap
pushed a commit
that referenced
this pull request
Oct 11, 2026
The thirteen streaming rows of rational/bench/baselines.json were the 2026-10-02 record (v0.10); three commits since moved them inside the ±3 % gate without re-recording, so the gate measured from a tree other than the one it guards. Re-recorded on all three targets from main at c120bc9 (arm-none-eabi-gcc 13.2.1, CodeLinaro 19.1.5, qemu 8.2.2 with the tree's plugin: the toolchains that reproduce the committed rows to the instruction, and bridge's twelve and async's eight rows --exact on M33, M55 and Hexagon, so only rational moves). The construct row, recorded 2026-10-10, is unchanged. The reason, traced by rebuilding the M55 workloads at every commit from 4eb1180 to e71d0b1: ab8fea3 (v0.11, the power-of-two row gain for the Q15 mixed ratios going down) is the one visible move, ratio23_q15_eco +355,117 on the M55 (+1.93 %, stated as +1.9 % in its commit), +7,346 on the M33 and -224 on Hexagon; d4fff5c (v0.13, the mirror-exact designer, the stage.h snap removed) added a construction-side constant per workload (M55 +76 by-2, +112 by-3 and 2/3, +196 transparent, +128 the chain; M33 +192 / +158 / +545 / +1,102; Hexagon +52 / +69 / +132 / +2,201); the DspTap bump to tap/DspTap#57 (82cd646) added +798 to the chain's construction on the M55. Every other commit re-measures identically; the sweep also shows #72's S1 sitting +3.5 ... +8.8 % until 391145d took it back, as that commit records. rational/PLAN.md carries the record (v0.15) beside the hand-kept table; the README table is regenerated. bridge/CLAUDE.md's ratchet sentence now says "beyond tolerance", the family rule in the root CLAUDE.md: a count that moves inside the gate is re-recorded when the record is corrected, as here, not on every change. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016GKzq1VSdcMYCRMhddiMaf
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this changes
The multi-agent adversarial audit of the tree after the
rationalengine and the C ABI reshaping (docs/AUDIT_2026-10.md: 18 confirmed findings, 4 major, 14 minor, 16 nits, mutation testing) and its response plan (docs/AUDIT_2026-10_PLAN.md), executed in six steps, one commit each:chain.hfix (the stages reset at construction and read-only through the chain; the accounting contract stated as an inequality) and pins the audit's overflow scenario here.uint32_tso every charter ratio runs (ratio<3, 1024>once ran silently wrong); the fixed-point rounding direction pinned at the stage by a constructed-tie test, in bridge too; decimators in the reset tests; a fourth compile-fail case; the relaxed Q15 designs measured and their numbers stated; the bare-metal floor; clang-format guards in the vector generator; the promised example; the stale numbers.TAP_SR_<ENGINE>_APIreplaces the visibility pragmas and the MSVC leg builds the C ABI; async refuses a bad profile; thread contracts in the siblings' headers.presetretired forprofile,economy()toprogram(), the async C ABI in the siblings' argument order,test_asrc_*renamed, the umbrella header and README in the sibling shape, the old engine name out of the present tense.Why
The maintainer's question was whether quality suffered when the new engine came in. The audit's answer: the datapaths did not slip (bit-identity, allocation-freedom, sanitizers, scipy legs, A/B streams all clean), the discipline around the code did (two latent bugs in new stage and substrate code, a contract equation that was false, a gate the book claimed that did not exist, and prose lagging the code at every seam between rounds of work), and the oldest engine still spoke the dialect it was written in. The plan fixes the defects, closes the test gaps, brings
asyncto the family's vocabulary without touching its numbers, and adds the gates that keep the seams from reopening.Verification
Built and ran on x86-64 (gcc 13, Release, every engine's WERROR on, C ABI on) at every step: 290 → 305 ctest entries, all green. All 60 output hashes and every
[ measured ]line are identical to the pre-change run at every step (the async hash labels readprogramwhere they readeconomy), so no datapath's output moved. Changed sources are clean underclang++ -Werrorwith the warning set and under clang-tidy; the C ABI headers compile as C11 consumers; the exported-symbol test was shown red against a library built without the hidden preset (883 symbols). Mutation testing after S1: 18 of 19 mutants killed, the nineteenth an equivalent mutant (dead code for its format), the live rounding points of both fixed-point formats mutated in the substrate and killed by the new tie test (the report's follow-up section). The book's include anchors resolve.Not run here, so CI is the first real gate for them: the Windows MSVC leg with the C ABI on (new), the Cortex-M33 / M55 / Hexagon legs (the new
Stage.WideRatiosOfTheCharterRunTheScheduledesigns two wide stages at a 40 dB custom spec, under a second on the host), the instruction-count ratchet (the widened field is off the hot path; if a count moves, re-record with the reason), the book and print builds, and the new retired-words job. The notebooks were not re-executed: no measured behaviour changed, but the async notebooks' ctypes cells now use the new argument order, so a re-execution is due when the environment is next at hand.Notes for the reviewer
filter_spec::economy()→program();preset→profilein every identifier;tap_sr_async_create(hz, target_latency_frames, profile, channels)andcreate_format(hz, target_latency_frames, profile, format, channels), profile and format before channels andunsignedchannels, as the siblings take them. No alias (D7). Any C caller of the async ABI outside this tree needs the new order; none was named.async's tiers keep their own names on purpose: they are image rejection through the interpolated bank, not Nyquist stopbands, and a name means one thing across the family.submodules/dsptapto tap/DspTap20a06acon branchccr-baf78007-zqpei0(tap/DspTap's PR for the chain fix). After that PR merges by rebase/squash, repoint the pin at the identical tree onmainbefore merging this one.scripts/book_figures.pykeeps the rendered titles that say "presets" until the figures are next regenerated; the retired-words checker allows those two lines.🤖 Generated with Claude Code
https://claude.ai/code/session_01Tg2PWk3CFfguD2qywBVnDV
Generated by Claude Code