Lane A complete (A.19-A.21): record emission, the exit gate, and one decoder - #14
Open
tom-snyder wants to merge 3 commits into
Open
Lane A complete (A.19-A.21): record emission, the exit gate, and one decoder#14tom-snyder wants to merge 3 commits into
tom-snyder wants to merge 3 commits into
Conversation
…decoder The last three packets of Lane A. A.19 populates the canonical record, A.20 reviewed it and returned FAIL, A.21 is the area exit gate and owns ruling G11. A.19 got the hard half right and the easy half wrong It correctly refused to read a clock -- the package contains none and a test enforces it. Then it copied advisory.staleness_seconds out of the cache, where the frozen contract defines that field as RECORD-ASSEMBLY TIME MINUS AsOf. Right source, wrong quantity, and the effect was the one the packet existed to prevent: a twenty-one-day-old cache reported as one hour old and inside its SLO. The test standing in for that property could not have caught it -- it asserted that an input value reappeared on the output, so its corpus was its own assertion. That is the same circularity that let an rpm corpus be truncated at the point of failure one packet earlier. Now AssembledAt is a REQUIRED parameter whose zero value is REFUSED rather than defaulted, because a zero default silently reinstates the bug. The replacement test states a watermark and an assembly instant twenty-one days later and asserts 1814400 -- arithmetic it does itself. The fixture's publisher-lag column is now a decoy constant resembling the contract quantity in no way, so any surviving copy-through fails loudly across the suite; four tests go red when the copy is reinstated. emit_test.go carries a new header section, NO TEST HERE MAY USE AN INPUT FIELD AS ITS OWN EXPECTED VALUE, naming both circularities. A real hole in the authorization guarantee The remediable_by_agent allowlist covered collector, detector kind, evidence class, fixed version and parse_degraded -- but not ECOSYSTEM. A repo-SCA finding with Ecosystem=deb emitted remediableByAgent=true. An OS package is not agent-fixable no matter which collector noticed it: S7 is about the thing, not about who found it. The exhaustive enumeration grew from 1512 points to 12096, with an assertion that the walked count equals the product so the space cannot be silently narrowed later. And Emission.RemediableByAgent()'s doc claimed a re-clamp the crossing bytes did not perform. Made true rather than qualified: the clamp now travels on a copy through MarshalJSON and Results(), tested on the SERIALISED bytes of Results that did not come from Emit -- hand-built, mutated after emission, and round-tripped through JSON then mutated. What went right, and it is substantial No second fingerprint is proved against the FROZEN conformance corpus and its independently-generated goldens -- and that proof caught a real detail: the corpus hashes the Debian locator as apt:openssl:amd64, so spelling the package manager "dpkg" fails the golden. R.16's harness doing its job across an area boundary, months after it was built. anvil/trust defaults to untrusted unconditionally, and the single anvil_generated string is trustworthy BY CONSTRUCTION rather than by assertion: the reasoning is joined from a closed vocabulary of eleven constant fragments plus integers Anvil computed, and any other part is refused with no record emitted. G11 closed, and closed structurally internal/ingest/decode is now the single implementation of every wire format Lane A reads, and bootstrap.advisoryRecord and delta.Record are Go type ALIASES for decode.Record -- so no conversion function exists that could drop a field on one side. A.21 correctly declined to merge DISPATCH, with a stated reason: the two callers legitimately disagree about what an unreadable document means, since A.8 skips an archive member while A.14 must error because a change was dropped. The exit gate reports what it could not prove The harness ends with "7 of 12 links proven end to end in this run" and "An UNPROVEN link is not a passing link. Read the list above before quoting" -- and names each gap: no dpkg/rpm/apk on a Windows host, so the host collector's REFUSAL is proven but its output is not; the accelerator is not in the chain at all because pulling a warm-start artifact needs a registry the harness must not contact; no production caller wires the chain together yet. All 25 area exit criteria are reported individually, several with explicit split verdicts -- satisfied at package level, unverifiable-here end to end -- rather than aggregated into one green tick. That was the instruction and it is the right shape: the report is what gets believed. Evidence: gofmt, vet, build clean; go test -count=1 ./... green across 24 packages; conformance harness byte-identical across two runs. Every fix verified RED against the pre-fix behaviour first. Two record-contract gaps reported, not decided, both mine to rule on: license_manual_note has no slot anywhere in internal/record though S8's compliance mechanics require it, and the named trust-validation step has none either. Lane A carries both on its own Emission type meanwhile, and says so.
refusals that arrive by the purl route CI went red on the Lane A exit gate, and it was red because the gate works. On ubuntu-latest dpkg exists, so host.Collect ran for real -- 1204 packages across three families -- and the harness then FAILED ITSELF: "a supported package manager is present on this host, so the fixture inventory is no longer the best available evidence." That is a tripwire firing when BETTER EVIDENCE BECOMES AVAILABLE, the same design as the sanitiser's importer tripwire. It is honoured here by wiring, not quietened. The fixture was two things wearing one name It was evidence for the host-inventory link AND the only host-shaped packages the synthetic corpus can decide. The tripwire correctly rejected the first; deleting the file outright would have destroyed the second, because no real machine anywhere has openssl 3.1.3-r0 with CVE-2026-1001 against it, and the comparator and emission links would have gone vacuous. So it is split: host.Collect supplies the host-inventory link, and corpus-probe-packages.json keeps the four synthetic rows under a name that says what they are, with a header stating it is NOT a recording of the collector. The branch is host.Collect's own error return, not a build tag or an env var, and the ledger line says WHICH inventory a run used -- because a run that proved the collector and a run that proved only a fixture are different claims, and that distinction is the entire point of the link. New tripwires point the other way too: a present package manager that enumerates ZERO packages fails the run (the silent-clean reading exit criterion 20 forbids), and so does collecting packages and then not submitting them all. Determinism was strengthened rather than preserved. chainOutput now compares the host source label and the collected rows, and the reason is not cosmetic: real packages match nothing in a synthetic corpus, so two DIFFERENT collections would have left every previously-compared field identical and the determinism claim would have been true about a chain that never saw the data. What CI now asserts is that host.Collect read a live package database twice and returned the same bytes. Measured rather than assumed: the probe fixture was temporarily grown to 1204 rows with realistic Ubuntu version strings -- epochs, tildes, plus-forms, "++" in names, empty arch -- and the whole chain ran TWICE in 0.12s with zero deltas and all 1204 identified, then the file was restored. The finding the harness reported instead of swallowing It logged, as a FINDING against internal/match rather than a failure of its own: a package refused for an unimplemented scheme did not appear in CoverageReport.EcosystemsRefused, because the refusal arrived by the purl route and only the ecosystem route fed that list. "The count is visible; the thing to implement next is not." EcosystemsRefused exists so an operator can see which ecosystems Anvil cannot yet handle. Dropping half its inputs made it quietly wrong in the direction that looks better. Both routes feed it now, through one function that decides what the identity token is. PurlType is a separate field rather than a reuse of Ecosystem, and that choice is load-bearing: {Ecosystem: "deb", Purl: "pkg:npm/..."} is refused on the purl type, so writing the type into Ecosystem would put "deb" -- an IMPLEMENTED scheme -- on the operator's implement-next list. That is worse than the empty list it replaced. A negative control asserts an implemented ecosystem never enters the list. The harness's logged finding is now an assertion, and it cannot be satisfied by the ecosystem route alone, because this corpus's refusal arrives by the purl one. Evidence: gofmt, vet, build clean; go test -count=1 ./... green across 24 packages here; no t.Skip added. On this host the ledger still ends "7 of 12 links proven end to end" with host inventory UNPROVEN naming the corpus probe -- which is correct, because Windows has no package manager. CI is where the real path exists and CI is the proof; it already caught this once.
The exit gate ends with a ledger naming which of its twelve links it PROVED and which it could not, plus "An UNPROVEN link is not a passing link. Read the list above before quoting." That ledger is the deliverable of A.21. Go only shows test log output on failure, so on a green CI run it was invisible -- a reader saw "ok" and had no way to know that seven of twelve links were proven and five were not. A gate whose verdict nobody can read is a gate that reports pass. This step prints it on the machine where it says the most: ubuntu-latest has dpkg, so host.Collect runs for real and the host-inventory link is PROVEN there, where on the Windows dev host it is UNPROVEN and names the corpus probe instead.
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.
Summary
The last three packets of Lane A.
A.19populates the canonical record,A.20reviewed it and returned FAIL,A.21is the area exit gate and owns ruling G11.This completes Lane A —
A.1throughA.21.A.19got the hard half right and the easy half wrongIt correctly refused to read a clock — the package contains none and a test enforces it. Then it copied
advisory.staleness_secondsout of the cache, where the frozen contract defines that field as record-assembly time minus AsOf. Right source, wrong quantity, and the effect was precisely what the packet existed to prevent: a twenty-one-day-old cache reported as one hour old and inside its SLO.The test standing in for that property couldn't have caught it — it asserted an input value reappeared on the output, so its corpus was its own assertion. Same circularity that let an rpm corpus be truncated at the point of failure one packet earlier.
AssembledAtis now required, with the zero value refused rather than defaulted, because a zero default silently reinstates the bug. The replacement test states a watermark and an assembly instant 21 days later and asserts1814400— arithmetic it does itself. The fixture's publisher-lag column is now a decoy constant resembling the contract quantity in no way, so any surviving copy-through fails loudly: four tests go red when the copy is reinstated. Andemit_test.gocarries a new header section — NO TEST HERE MAY USE AN INPUT FIELD AS ITS OWN EXPECTED VALUE — naming both circularities.A real hole in the authorization guarantee
The
remediable_by_agentallowlist covered collector, detector kind, evidence class, fixed version andparse_degraded— but not ecosystem. A repo-SCA finding withEcosystem=debemittedremediableByAgent=true. An OS package isn't agent-fixable no matter which collector noticed it: S7 is about the thing, not about who found it.The exhaustive enumeration grew from 1,512 points to 12,096, with an assertion that the walked count equals the product so the space can't be silently narrowed later.
And
Emission.RemediableByAgent()'s doc claimed a re-clamp the crossing bytes didn't perform. Made true rather than qualified — tested on the serialised bytes of Results that did not come fromEmit: hand-built, mutated after emission, and round-tripped through JSON then mutated.What went right, and it's substantial
No second fingerprint is proved against the frozen conformance corpus and its independently-generated goldens — and that proof caught a real detail: the corpus hashes the Debian locator as
apt:openssl:amd64, so spelling the package managerdpkgfails the golden.R.16's harness doing its job across an area boundary, long after it was built.anvil/trustdefaults tountrustedunconditionally, and the oneanvil_generatedstring is trustworthy by construction: the reasoning is joined from a closed vocabulary of eleven constant fragments plus integers Anvil computed, with anything else refused and no record emitted.G11 closed structurally
internal/ingest/decodeis now the single implementation of every wire format Lane A reads, andbootstrap.advisoryRecord/delta.Recordare Go type aliases fordecode.Record— so no conversion function exists that could drop a field on one side.A.21correctly declined to merge dispatch, with a stated reason: the two callers legitimately disagree about what an unreadable document means, sinceA.8skips an archive member whileA.14must error because a change was dropped.The exit gate reports what it could not prove
It names each gap: no dpkg/rpm/apk on a Windows host, so the host collector's refusal is proven but its output is not; the accelerator isn't in the chain at all, because pulling a warm-start artifact needs a registry the harness must not contact; no production caller wires the chain together yet.
All 25 area exit criteria are reported individually, several with explicit split verdicts — satisfied at package level, unverifiable-here end to end — rather than aggregated into one green tick.
Testing
Every fix verified RED against the pre-fix behaviour first.
Two record-contract gaps, reported not decided
license_manual_notehas no slot anywhere ininternal/record, though S8's compliance mechanics require the manual-override field carrying the quoted operative sentence. The named trust-validation step has none either. Lane A carries both on its ownEmissiontype meanwhile, and says so — but the frozen contract is where they belong, and that's mine to rule on.