Skip to content

sworn conformance v0.1: the tests become bytes a second verifier can be held to - #63

Merged
fathomlab merged 11 commits into
mainfrom
leg/sworn-conformance-vectors
Sep 5, 2026
Merged

sworn conformance v0.1: the tests become bytes a second verifier can be held to#63
fathomlab merged 11 commits into
mainfrom
leg/sworn-conformance-vectors

Conversation

@fathomlab

Copy link
Copy Markdown
Contributor

Leg 3, item 2 of papers/PLAN_the_next_level_2026_09_02.md: conformance vectors for sworn output, under the plan's own label — the precondition for any second verifier; no claim. Base is feat/charon-v01 (stacked on #60#59); independent of #61 and #62.

What this is

Every call the two sworn test files (tests/test_sworn.py, tests/test_sworn_attacks.py) make into styxx.sworn is recorded as bytes — the document, the manifest, a tree snapshot with modes, and the exact receipt core the verdict must reproduce — and addressed by one digest, so that a verifier in another language can be shown where it disagrees, byte by byte, before anyone is asked to trust it.

The ladder

  1. papers/sworn/SPEC_sworn_conformance_vectors_v01_2026_09_05.md — frozen alone before any code, with conformance/** -text in the same commit (1e94721).
  2. styxx.sworn.SnapshotTree — a tree snapshot with modes that reproduces every GitTree reason but git_unavailable without a git binary; pure, additive, beside MemoryTree; 26 tests (1bc1b31).
  3. conformance/sworn/ — the recorder (a pytest plugin that pins the clock and the git dates), the generator (gen_vectors.py, with --check and --replay), the set (3618 vectors in 20 families, 3977 blobs, 3 calls listed as unvectored with their reasons), observer.json outside the digest, a README, and tests/test_sworn_conformance.py (72 tests, nothing skipped: every blob hashes to its key, every id re-derives, every vector replays through styxx.sworn, every rule has both shapes, every closed set is produced or listed, every file is -text and CR-free, and the committed set regenerates to its own digest) (b02f3fc).
  4. RESULT_sworn_conformance_v01_ships_2026_09_05.md, sworn, 13 spans, every count and the set digest bound to leaves of conformance/sworn/index.json at the commit that carries them; a dated ERRATA on the SPEC for what it could not foresee (3d94013).

The rules that matter

  • The pinned core follows the code, not the prose. core_sha256 = sha256(utf8(jcs(core))) over the verifier's output minus verifier minus coverage; the receipt's own digest is build-bound and is never a vector's number.
  • Nothing is dropped silently; a moved core refuses regeneration. A future edit to styxx/sworn.py re-keys the sixteen receipt_check vectors by construction and moves the set digest; the generator reports them dropped and added, and a new set is a new commit with a new RESULT — never in place.
  • The fuzz family is included in full (1786 seeded documents), because a capped fuzz set with the same seed is a different set.

Verification

  • tests/test_sworn.py, tests/test_sworn_attacks.py, tests/test_sworn_eol.py: 463 passed, no verdict changed. tests/test_sworn_conformance.py: 72 passed, 0 skipped. gen_vectors.py --check: stable across three runs on this box.
  • python -m styxx.sworn check re-derives the RESULT's receipt VERIFIED (digest match, verdict reproduces, same build).
  • Full suite on this branch (Windows, Python 3.12): 3934 passed, 11 skipped, 4 xfailed.
  • python -m ruff check styxx: clean. The wheel does not ship conformance/.

What it does not say

That agreement on these vectors makes a verifier correct. That the vectors cover the format — they cover what two test files exercise, written by the builder. That the fuzz family is adversarial. That any second verifier exists. CI (Linux, 3.9–3.12) has not yet run this branch; the set's cross-platform digest stability rests on the pinned clock and git dates making fixture commit ids identical, which is the thing to watch.

Owed

A committed family from tests/test_sworn_dogfood.py; a refusal attribute on the verifier's SystemExit if a second verifier needs codes at the source; the verdict_core() split of verify(); the Python-versus-JavaScript semantics the vectors pin and item 5 must implement. The set is ~8.5 MB in the tree; a JS consumer should load families independently.

🤖 Generated with Claude Code

darkflobi and others added 4 commits September 5, 2026 05:56
…verifier can be held to, frozen before any code

Leg 3, item 2 of papers/PLAN_the_next_level_2026_09_02.md, under the plan's own label: the
precondition for any second verifier; no claim. The spec rules ten things before any code
exists: the pinned core follows the code (thirteen keys, verifier and coverage excluded, the
receipt's build-bound digest never a vector's number); inputs are bytes in six modes; the clock
and the git dates are pinned at generation; the coverage floor is pinned and the observer is
not; nothing unvectorable is dropped silently; a moved core refuses regeneration; one digest
pins every byte transitively with provenance outside it; `requires` says what a verifier needs;
the layout wears no suffix another sweep claims; and the verifier stays pure, with a
SnapshotTree that reproduces every GitTree reason but git_unavailable without a git binary.
It widens the plan row's source list to both sworn test files and says why. It licenses
nothing: the RESULT that follows the set carries every count as a sworn span.

Same commit: .gitattributes gains `conformance/** -text`, because this box has
core.autocrlf=true and the vectors carry CRLF, lone CR, BOM, NUL and invalid UTF-8.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…tTree reason but git_unavailable without a git binary

Built to papers/sworn/SPEC_sworn_conformance_vectors_v01_2026_09_05.md, C10, frozen at
1e94721. MemoryTree carries bytes and no modes, so it can never say not_a_blob,
receipt_too_large or commit_absent; GitTree says them but needs a git binary. SnapshotTree sits
in section 3 of styxx/sworn.py beside MemoryTree, is a dict of {path: {mode, size, sha256,
bytes}} at one snapshot commit, and imports nothing and calls nothing: no git, no filesystem,
no clock. Its handle commit follows MemoryTree's rule (None means no commit) and verify()
overwrites it with the document's commit as for every handle; a handle commit that is not the
snapshot's, or is not a full lowercase hex id, is commit_absent; a tree, symlink or gitlink
entry is not_a_blob whatever bytes it carries; an entry whose bytes were not embedded is
receipt_too_large; from_memory() lifts a MemoryTree to the same snapshot. Everything that reads
git to build one is left to the recorder the next commit adds.

tests/test_sworn.py gains TestSnapshotTree (26 cases): every MemoryTree vector TestReceipts
pins replays through from_memory to the same portable core (the verdict minus verifier minus
coverage); a 040000, a 120000 and a 160000 entry are not_a_blob; the four handle-commit shapes
(None, another commit, not hex, uppercase, short) resolve as the spec rules; an entry over the
cap with no bytes is receipt_too_large and one at the cap is served; a prereg digest is found
among embedded blobs and not among unembedded ones nor under a symlink; on the git_repo fixture
a snapshot built by ls-tree -r -t -l agrees with GitTree on all nine cases and with MemoryTree
on the seven it can express; and the class is exported and its source names neither subprocess
nor the filesystem. The three sworn test files pass with no verdict changed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
… files and replayed through styxx.sworn under one digest

Built to papers/sworn/SPEC_sworn_conformance_vectors_v01_2026_09_05.md, frozen at 1e94721. Three
modules under conformance/sworn/. recorder.py is a pytest plugin, loaded with -p, that pins
sworn._now and the git author and committer dates to the spec's clock (C3), wraps verify,
to_sidecar, load_sidecar, verify_receipt and Manifest.from_dict, records each top-level call's
inputs as bytes and its outcome, passes nested calls through unrecorded, and lists what it cannot
carry instead of dropping it (C5); it is the only file that reads git, and the verifier never
imports it. gen_vectors.py runs the two sources under the recorder, folds the records into
vectors addressed by sha256 of jcs({mode, inputs}), merges identical inputs across tests, assigns
each vector a family by its lowest source's test class and the v0.2 rules and battery rows its
sources pin, replays every vector through styxx.sworn before writing, refuses a nondeterministic
id or a moved core in the manner of papers/sworn/reissue_receipts_v1.py (C6), and writes
index.json, vectors/<family>.json, blobs.json and observer.json through one LF writer (C7, C9).
replay.py is the reference for what a second verifier does, entrypoint by entrypoint, and is
what both the generator and the test call. README.md says how to consume and regenerate the set
and what passing does not mean.

The set itself is generated, never hand-edited; its counts are leaves of conformance/sworn/index.json
and the RESULT that follows binds them. The fuzz family is carried in full. Three recorded calls
are listed under index.unvectored.skipped rather than carried: the manifest holding a NaN, a
sidecar holding a lone surrogate that no UTF-8 text can carry, and the receipt check against
this repository's own history. Every reason in REASONS and every verdict in VERDICTS is produced
by some vector except the three C5 names, and six refusal codes in the table are produced by no
test and are listed as such. The receipt_check inputs embed the issuing build's verifier block
by construction; that is recorded as ERRATA E1 on the spec in the commit that carries the RESULT.

tests/test_sworn_conformance.py loads the committed set at import, so a missing set is a
collection error and nothing skips: every blob hashes to its key; every family file hashes to
its index entry and set_sha256 re-derives; every id re-derives from its mode and inputs; every
vector replays, per family, with zero skips; every v0.2 rule has a positive and a negative vector
and every battery row a vector that shows its verdict; every reason and verdict is produced or
listed, and the unvectored lists are exactly C5's; every tracked file under conformance/ resolves
text unset and holds no CR; no file wears a suffix another sweep claims; and gen_vectors.py --check
regenerates the committed set to its own digest.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ery count a leaf of the index at b02f3fc

papers/sworn/RESULT_sworn_conformance_v01_ships_2026_09_05.md with its sidecar and verdict
receipt, SWORN-HELD with nothing failed, unresolved or malformed, checked VERIFIED and rendered
byte-identical. Every span binds to a leaf of conformance/sworn/index.json at
b02f3fc, the commit that carries the set: the label, the vector
and family and blob counts, the fuzz family's size, the core and refused outcome counts, the
vectors that need a tree, the receipt checks, the skipped count, the one unproduced verdict, the
pinned clock and set_sha256. The document ships under the plan's own label, the precondition
for any second verifier; no claim, and says so. The set is never regenerated in place after
this commit.

Same commit: a dated ERRATA section appended to the frozen SPEC, editing nothing above it, with
five entries: receipt_check inputs name the issuing build by construction, so C7's invariance
holds for every other vector; a lone-surrogate sidecar is a third input the set cannot carry;
battery rows carry one shows sentence rather than a positive and a negative; refusal codes no
test produces are listed under index.unvectored.refusal_codes; SnapshotTree's handle commit
defaults to none, MemoryTree's rule. And the CHANGELOG [Unreleased] entry for sworn conformance
v0.1 at the top of the file, in the house shape, ending in what it does not say and what is owed.

No .gitattributes line is added: papers/sworn/** is already -text, and tests/test_sworn_eol.py
and tests/test_sworn_dogfood.py pass over the new triple. No INDEX row: papers/sworn/ has one.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…which index field

CI refused this set on Linux with two digests and nothing else, which cannot be acted on. The
refusal now prints every family whose file hash moved with its counts, whether blobs.json moved,
and any non-family index field that differs. The check still passes here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@fathomlab
fathomlab changed the base branch from feat/charon-v01 to main September 5, 2026 21:37
darkflobi and others added 2 commits September 5, 2026 17:49
…latforms agree

CI refused this set on Linux: same 3618 vectors, same 3977 blobs, every vector replaying, and a
different set_sha256. The drift report named the two things that moved — the worked_examples family
and blobs.json — and that family holds the only fixture whose bytes come off the working tree.
papers/closed-model-frontier/stage2_result.json is LF in git and CRLF in a Windows checkout, so the
set embedded whichever copy the generating machine held.

The file is untouched: three committed certificates cite it and a receipt is history. The fixture
now reads it with content identity modulo newlines, which is what corpus_audit._receipt_sha_matches
and charon._content_sha256 already do to every receipt in the corpus; every assertion in that class
reads a JSON leaf, so no verdict moved (348 sworn tests pass unchanged).

Regenerated once under the SPEC's own C6 path. The digest moved from cb5d5148… to 96dfe159…, which
is the digest the Linux run had already produced — the platforms agree rather than one having been
declared correct. SPEC ERRATA records the cause, the repair, and the rule it adds to C7: a vector's
bytes may never come off the working tree unnormalised.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e one both platforms produce

13 spans, SWORN-HELD. The only number that moved is the set digest itself; the counts, the families
and the boundary sentences are unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fathomlab pushed a commit that referenced this pull request Sep 5, 2026
…ing copy's bytes, so sworn.py is pinned

After the worked-examples repair the set still refused to regenerate here, and the drift report named
four families — cli, gaming, receipt_v1, rules — all of them receipt_check vectors, which is the
class the SPEC's ERRATA E1 already says embeds the issuing build. Decoding one named the field:
verifier.sworn_sha256, which styxx.sworn computes over THIS FILE'S WORKING-COPY BYTES. This
worktree had sworn.py CRLF; git holds it LF, which is what Linux checks out and what the committed
set was generated against.

So every sworn receipt, and every conformance vector that embeds one, depended on the line endings
of the checkout that produced it. styxx/sworn.py is now `-text` pinned: the blob does not move (the
staged diff is empty), and a checkout can no longer change the hash every receipt carries. The
working copy here was normalised to match, and the set regenerates to 96dfe159… — the digest #63
produces and the one Linux produced before either repair.

Also in this commit: conformance/sworn/replay_js_result.json is renamed replay_js_report.json,
because the conformance suite forbids `result` in a file name under conformance/ (a suffix another
sweep claims) and this branch had been failing that test.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
darkflobi and others added 4 commits September 5, 2026 18:04
… are classified, not quoted

py3.9, 3.10 and 3.11 refused a set that py3.12 accepted, and the drift report named one field:
index.unvectored. Two of its three skipped entries carried a CPython exception message verbatim --
the wording of a NaN refusal and of a lone-surrogate encode error -- and that wording moves between
versions. Every site that records why a call could not be vectored now classifies the exception
type into a sentence this lab wrote, so the same input yields the same word on every interpreter.

Same shape as the worked-examples repair, so the SPEC's ERRATA states the rule once for both:
nothing a set pins may come from outside the format, neither the checkout's line endings nor the
interpreter's prose. The digest moved to 85e2d3b9…; the RESULT binds it and is re-sworn next.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…atforms produce

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…-vectors

# Conflicts:
#	.gitattributes
#	CHANGELOG.md
@fathomlab
fathomlab merged commit d68a265 into main Sep 5, 2026
7 checks passed
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