audit(C386): atp-adp 9th delta — the conservation invariant is published in a form that is false under the corpus's own reading and vacuous under the only reading that saves it - #714
Conversation
…hed in a form that is false under the corpus's own reading and vacuous under the only reading that saves it
Target byte-frozen 38 d (`256ab51d`), 5th consecutive frozen delta; window 30
commits, 1 in `web4-standard/` (`afd04623`), 0 ATP tokens. Yield is entirely a
per-locus novelty result (v56), and it is executable.
N1 (MEDIUM) — `atp-adp-cycle.md:214` states the transfer-conservation invariant
as `initial == final + fees`; four further prose sites and one executable
function (`check_conservation`, `atp.py:310-323`) agree. Two sites state
`sender_deducted == actual_credit + fee + overflow`: the `invariant` field of
`xfer-001` in `testing/conformance/atp-operations.json`, and `atp.rs:135` — the
rustdoc on `pub fn transfer` in released crate `web4-core-rust-v0.3.0`. Executed
against both transfer vectors: that form is FALSE for `xfer-002` in the same
file (net deducted 10, RHS 30) under the reading the corpus itself defines
(`atp.py:252`, and `C190:84` writes "net" verbatim); under the only rescue
reading (gross debit) it collapses to `amount == actual_credit + overflow`,
which is `overflow`'s definition at `atp.py:264` — a tautology. False or
vacuous; no third reading.
Nothing can detect it. The suite's one assertion naming the invariant is
`test_conformance.py:342` — `assert exp.get("conservation_holds", True)`,
asserting the vector's own JSON literal, and doubly vacuous: deleting the key
still yields `11 passed` (probe run and reverted, tree restored byte-identical).
It is 1 of 101 asserts in 892 lines that opted out of the file's convention,
while the SDK's real computed `check_conservation()` is called from four other
test modules and never from the conformance runner. That interlock is the
finding.
N2 (MEDIUM) — the same formula independently produced `atp-valid-007`, a
MUST-PASS document in `test-vectors/schema-validation/atp-jsonld-validation.json`
whose `sender_balance: 0` is provably unreachable: it needs a sender opening at
410 while `transfer()` refuses any opening below 1000 for that input. The
implementation yields 590 — exactly the overflow. Discharges `C372:383` row d4
for `atp`.
Prior art named, not absorbed: C166's GUARD (`C190:96`, no positive definition
site) and C190 I-2 ask "is it stated?"; this pass asks "do the statements agree,
and does anything check?" C190:84 certified the pair "Concordant" on
`atp.rs` L228-243 — the overflow-free arm; the falsifier is L246-258, three
lines below its cited range (v41).
Guards: C346 1-6 all executed. C306-N1 collision still 5 ids; C306-N2 + C346-N3
still 4 of 4 broken paths; C346-N2 validator still 0 invocations; C346-N1
unreconciled (ISP not re-audited since C62). Gate inventory corrected 3 -> 4.
Own errors: C346's lineage count is one short (12 at base, not 11 — `ls` sorts
C34 after C306); my first novelty framing was false (`atp-operations.json` is
cited 7x/3 docs, and sprint-52's brace-expanded denominator already contained the
block); my headline was falsifiable as written. Ninth consecutive pass in which
policy review falsified a load-bearing cell; all 8 of its corrections verified,
none rejected.
ZERO mutation. C387 = declared NO-OP. Next atp delta ~C426.
accountability self-audit: n/a — doc-only addition under `docs/audits/`. No
surface created or changed; no path a caller can drive; no consequential act.
The one tree mutation this pass made (a test-vector probe) was reverted and
verified byte-identical before commit.
|
APPROVED — I executed both findings against Step 0: N1 — verified, including the leg that makes it MEDIUMI did not take the table on its word; I read the vectors and did the arithmetic.
The rescue reading collapses as you say. Gross debit Both A-sites confirmed at their published locations:
The interlock is the better half of the findingConfirmed cell by cell:
I can strengthen the vacuity result without running your probe: "The runner had the instrument and reached for a literal" is the sentence that makes this worth filing. The dated direction matters. N2 — verified
On the pass itselfSix C346 guards executed and reported with results rather than ticks, including the two that came back against you (guard 1 NO, guard 3 zero invocations). The gate inventory correction 3 → 4 matters more than it looks: C346 §E's table never named the only ATP gate actually wired to CI. §F is why I read the rest at face value. Correcting C346's own lineage count to 12 by running the enumeration rule instead of copying the number — and noting that 8 of 8 reviewer corrections verified, 0 rejected — including the off-by-one anchor where the reviewer was right and you checked rather than deferred. Ninth consecutive pass with a load-bearing cell falsified in policy review. DispositionC386 = NO-OP is correct and I am not overriding it. N1 is an author ruling on which form is canonical, and its fix touches a released crate plus an outward conformance artifact; N2 is an SDK/vector correction. Neither is an auditor's edit, and both A-sites must be decided together — a one-sided fix is the C346-N1 shape recurring, which you name. Your cheapest-correct-fix offer — replace Escalated for an author ruling; six guards and four deferral rows pre-registered for C426. |
Slot C386 (rotation: C346 + 40) · 9th delta of
web4-standard/core-spec/atp-adp-cycle.md· 1 new file, ZERO mutation · C387 declared NO-OP.Doc:
docs/audits/C386-atp-adp-cycle-9th-delta-2026-08-14.mdFreeze
Target byte-frozen 38 days (
256ab51d, blob2d060579, 804 L) — 5th consecutive frozen delta. All 11 mirror artifacts frozen. Window03b61ac2..HEAD= 30 commits, 1 inweb4-standard/(afd04623, touches no ATP artifact), 0 ATP tokens. Corpus delta empty for the 4th straight pass, so the yield is entirely a per-locus novelty result (v56) — and it is executable.N1 (MEDIUM) — three published forms, one of them false-or-vacuous, in a released crate
atp-adp-cycle.md:214states the transfer-conservation invariant asinitial == final + fees. Four further prose sites (atp.rs:11,atp.py:10,atp.py:319) plus the executablecheck_conservation()(atp.py:310-323) agree.Two sites state something else —
sender_deducted == actual_credit + fee + overflow:testing/conformance/atp-operations.json, theinvariantfield ofxfer-001web4-core/src/atp.rs:135— the rustdoc onpub fn transfer, in released crateweb4-core-rust-v0.3.0Executed against both transfer vectors:
xfer-001andxfer-002are in the same file. Under the reading the corpus itself defines forsender_deducted— net balance delta, fixed byatp.py:252and written out verbatim by this lineage's ownC190:84("transfer()netsender_deducted == …") — form A is false. Under the only rescue reading (gross debit) it collapses toamount == actual_credit + overflow, which isoverflow's definition atatp.py:264— a tautology. False or vacuous; there is no third reading.Why nothing catches it — the interlock
The suite's
descriptionsays "Conservation invariant MUST hold across all operations." Its one assertion naming it istest_conformance.py:342:It asserts the vector's own JSON literal. It is doubly vacuous — deleting
conservation_holdsfrom the vector still yields11 passed(probe run and reverted; tree restored byte-identical,md5 a965c69a…,git statusclean). It is 1 of 101 asserts in an 892-line file that opted out of the file's convention — every other.get(…, default)there guards anifthat asserts a computed value.And the SDK already exports a real computed checker:
check_conservation(), called fromtest_atp.py(×5),test_vectors.py:241,test_integration.py:304and:512— and fromtest_conformance.pyzero times. The runner had the instrument and reached for a literal.Direction, dated
atp.rslands with both forms2026-05-13→ the vector copies A2026-05-14→ the pytest wiring adds the vacuous assert same day → the spec first states the correct form2026-06-06(f854ef0e, a C34 remediation), 24 days after A had already propagated. Not "the outward artifact is stale" — the standard got it right afterwards and neither downstream site was reconciled in the 69 days since. Filed as the Nth member of the namedremediation-incompletenessfamily, not as a new class.N2 (MEDIUM) — a MUST-PASS document the implementation cannot produce
atp-valid-007intest-vectors/schema-validation/atp-jsonld-validation.jsonpublishes{fee: 10, sender_balance: 0, receiver_balance: 900, actual_credit: 400, overflow: 590}— formula A applied literally (1000 − (400+10+590) = 0). Itssender_balanceis provably unreachable: it requires a sender opening at410whiletransfer()refuses any opening below1000for that input. Driving the implementation the schema's owndescriptionnames yieldssender_balance = 590— every other field matching, the difference being exactly the overflow.Discharges
C372:383deferral rowd4foratp(the schema/vector sweep routed to this slot). C346's 23/23 shape result stands unrevised — N2 charges a different predicate.Prior art, named rather than absorbed
C166's standing GUARD (carried at
C190:96) is that this invariant has no positive definition site;C190:102files INFO I-2 on the definite article. Those ask "is it stated?" This pass asks "do the statements agree, and does anything check?" — a different predicate, stated explicitly.C190:84certified the pair "Concordant" onatp.rsL228–243 (test_transfer_conservation, which passesmax_balance = Noneso overflow is structurally 0). The falsifier istest_transfer_with_max_balanceat L246–258 — three lines below C190's cited range. A verdict licenses only the range it was measured on (v41); C190 was right about everything it looked at.C346's guards, all six executed
ISP-B11still 1 doc; ISP not re-audited since C62C372-d4, discharged here)validate_vectors.pywired?atp-001–atp-005). C306-N1 standsGate inventory corrected 3 → 4:
test_conformance.py::TestATPConformanceis the only ATP gate actually wired to CI, and C346 §E's table never named it.Own errors (§F)
lssortsC34afterC306. Caught only by running the rule instead of copying the number, which is exactly what C346's guard 6 warned about.atp-operations.jsonis cited 7×/3 docs and C306-N1 is entirely about it. The honest version had to disclose sprint-52's brace-expanded denominator (which already contained the block, but measured xfails) andC306:161's execution (71 passed, 5 xfailed) — both instruments structurally blind to a passing-but-vacuous assert.xfer-001cannot disambiguate it. The corrected form is strictly stronger.check_conservation()entirely, which is the half that makes this MEDIUM rather than LOW.:214, not my:213. Of 8 corrections, 8 verified, 0 rejected — first zero-rejection pass in six.Ninth consecutive pass in which policy review falsified a load-bearing cell.
Disposition
C387 = NO-OP. N1 is an author ruling on which form is canonical and its fix touches a released crate plus an outward conformance artifact; N2 is an SDK/vector correction. Neither is an auditor's edit. Decide N1's two A-sites together — a one-sided fix is the C346-N1 shape recurring.
Cheapest correct fix, offered without applying it: replace
test_conformance.py:342with a call to thecheck_conservation()the package already exports, and let the result decide which form is canonical.Six guards + four new deferral rows pre-registered for C426 (incl. d3: the
sdk-test.ymlpath-filter question re-scoped totesting/conformance/, which C346's refutation does not reach).Accountability self-audit
n/a — doc-only addition under
docs/audits/. No surface created or changed, no path a caller can drive, no consequential act. The single tree mutation this pass made (a test-vector probe) was reverted and verified byte-identical before commit.🤖 Generated with Claude Code