Skip to content

Contract gaps: trust validation step, licence note, zstd payload, handoff fixes - #17

Merged
tom-snyder merged 3 commits into
mainfrom
fix/contract-gaps
Oct 3, 2026
Merged

tom-snyder merged 3 commits into
mainfrom
fix/contract-gaps

Conversation

@tom-snyder

Copy link
Copy Markdown
Member

Phase 4's plan node contractgaps: six open items in the record and the store, each closed with a test or stated as a limit before the contract freezes. The table is also appended to internal/record/CONTRACT.md as the 2026-10-03 amendment.

Item Outcome
Licence manual-override note The record slot existed since 2026-08-23, but emission still carried the note out of band. It now travels inside the record, beside the excerpt it licenses.
Trust-validation step New anvil/trust.validationStep: required, non-blank, exactly when some label in the result is verified; refused otherwise. Enforced in ValidateResultTrust and, for the default, in the wire schema (checked with jsonschema 4.26.0).
Payload codec audit_record.payload is zstd from github.com/klauspost/compress v1.20.1 (pure Go, BSD-3-Clause), pinned in go.sum, with its three applicable licence bodies archived and re-hashed in third_party/klauspost-compress/. payload_sha256 hashes the canonical JSON. Decoding refuses corrupt frames, hash mismatches and anything over 256 MiB decompressed.
A voluntary hand-back burned an attempt Queue.HandBack returns the attempt. ReleaseLease(ready) still keeps it, because that is how a failed attempt goes back.
expired settable outside the reaper Dispose refuses it.
An exported, ungated packet path Queue.PacketPath is unexported. A lease holder still gets its own path on the Handle.

Every new check was seen failing with its fix reverted. Gate 3 classifies the zstd import as inert: go list -deps of the package names no network package.

Testing

gofmt -l, go vet ./..., go test -count=1 ./... and go test -race -count=1 ./... are green on Debian 13 with Go 1.26.5, with Trivy off PATH. With Trivy installed (it now is on the development machine), the Lane A chain harness fails on purpose: its tripwire says the repo collector must now be proven for real rather than through a recorded report. The anvil scan branch honours that.

…ath around the packet gate

Three of the sealing, claims and masking review's findings, closed with a
test each and each test seen failing with its fix reverted:

- Queue.HandBack ends a lease without an attempt and returns the attempt
  the claim counted. Two hand-backs with max_attempts=2 used to strand a
  never-attempted row as ready-but-exhausted (finding F10). ReleaseLease(ready)
  still keeps the attempt, because that is how a failed attempt goes back.
- Dispose refuses 'expired'; the claim-timeout reaper is its only writer
  (finding F13).
- Queue.PacketPath is unexported. ReadPacket and WritePacket were gated, but
  an exported map from any fingerprint to its packet file was a read around
  the gate. The lease holder still gets its own path on the Handle.
…side the record

anvil/trust.validationStep names the validation behind every 'verified'
label in a result. It is required, non-blank, exactly when a label is
'verified' and refused otherwise, in ValidateResultTrust and in the wire
schema (for the default, checked with jsonschema 4.26.0). Record emission
used to carry the step and the licence manual-override note out of band on
Emission; both now travel in the record, and Emission keeps only the feed
SLO the contract has no field for. Emission names the step only when a
verified string travels in the result, which the new check caught.
audit_record.payload has been specified as zstd(canonical SARIF JSON) since
the store schema was written, but nothing wrote it and no library was chosen.
EncodePayload and DecodePayload use github.com/klauspost/compress v1.20.1
(pure Go, BSD-3-Clause), added on 2026-10-03 with the owner's approval.

payload_sha256 is the SHA-256 of the canonical JSON, not of the compressed
bytes, so it identifies the record whatever the encoder. Decoding refuses a
corrupt frame, a hash mismatch and anything over 256 MiB decompressed; the
bomb test builds a real 300 MiB payload that compresses to 33 KB. Encoding
is deterministic. The three licence bodies that apply to the linked packages
are archived in third_party/klauspost-compress/ with PIN.md, and tests
re-hash them and fail if go.mod or go.sum moves the pin. Gate 3 classifies
the zstd import as inert: its dependency graph holds no network package.
@tom-snyder
tom-snyder merged commit 009b468 into main Oct 3, 2026
6 checks passed
@tom-snyder
tom-snyder deleted the fix/contract-gaps branch October 3, 2026 18:46
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant