Skip to content

charon v0.1: the ferry log — every verdict re-derived from bytes, chained, and attacked before it was announced - #60

Merged
fathomlab merged 10 commits into
feat/sworn-v02-next-levelfrom
feat/charon-v01
Sep 5, 2026
Merged

charon v0.1: the ferry log — every verdict re-derived from bytes, chained, and attacked before it was announced#60
fathomlab merged 10 commits into
feat/sworn-v02-next-levelfrom
feat/charon-v01

Conversation

@fathomlab

@fathomlab fathomlab commented Sep 2, 2026

Copy link
Copy Markdown
Contributor

charon v0.1: the ferry log — the lab's record over three formats, re-derived from bytes, chained, and attacked before it was announced

Stacked on #59 (base: feat/sworn-v02-next-level). Spec committed before the module; module; adversarial pass; repairs; log rebuilt; RESULT re-sworn against it.

What Charon is

styxx/charon.py — the log of crossings. Every line is a verdict re-derived from bytes by one of the three verifiers the lab already has: a sworn document at the commit its sidecar names (styxx.sworn), a capsule (styxx.capsule), an OATH certificate with its receipts (styxx.corpus_auditstyxx.certify). Charon reproduces; it never adjudicates, accuses no one, fetches nothing, signs nothing.

  • The receipt set is on every line, and the kind says what it means. 10 of 227 held-class lines rest on ten or more receipts (max 21): 8 OATH certificates, where a larger set makes HELD strictly easier, and 2 sworn documents, where the author named the leaf and volume buys nothing.
  • SKEW is not DRIFT. verify separates a core that moved with the instrument's bytes from one that moved under the same build, beside MOVED_VERIFIER, UNRESOLVED, HEAD_MISMATCH and TAMPER. verifier.modules carries the whole derivation path, Charon included.
  • The log: 243 lines — 213 certificates (every tracked one; the arXiv staging copies enter as UNRESOLVED lines, not absences), 18 sworn, 12 capsules. Head bcffbebc…. SAME_LINE 243, TAMPER 0 — a determinism check, not a stability result. The population is papers/charon/build_log.py, not a sentence.

The adversarial pass — run before any announcement

papers/charon/ATTACKS_charon_v01_battery_2026_09_02.md: three attackers, three lenses. Four sentences the instrument published about itself were false, and are repaired:

  1. "A line cannot be removed or reordered without the chain saying so." A forger who rebuilds seq/prev/entry_id produces a chain that checks. The chain binds order to the head--expect-head, HEAD_MISMATCH, and a report that says so without one.
  2. "Every line is a verdict re-derived from bytes." Capsule verdicts were copied from the embedded record. Both kinds now carry the live re-derivation; a test forges an embedded verdict and asserts it never reaches the line.
  3. "verify re-derives every line." It compared a class. It now compares the whole core and reports fields_changed, subject_moved, receipts_moved. REPRODUCED → SAME_LINE.
  4. "A moved verifier reads as SKEW." It saw one file of several on the derivation path.

Also repaired: chained header; refused headerless ingest; malformed lines as TAMPER not tracebacks; no absolute paths; refused missing log; resolved-vs-cited receipts; reproduced via styxx.sworn.verify_receipt; vacuous HELD excluded; a derive subcommand the page prints on every row. Unrepaired attacks are named with what the instrument prints instead.

What the log found

Seven lines record an artifact that did not reproduce at ingest or had nothing to reproduce against — each with its reason on the line:

  • arxiv/read_neq_write/source.md re-certifies OATH-FAILED where its certificate recorded OATH-HELD, with every byte and receipt digest matching. The verifier moved. This is the canonical arXiv/Zenodo submission source and it sits outside the directory REPLICATIONS.md runs the corpus audit over, which is why no audit reached it.
  • the universal-mind capstone, certified over a changed and therefore incomplete receipt set;
  • the black-box sycophancy finding, whose verdict class moved with no receipt missing;
  • the handoff capsule, whose tests_pass explanation string grew when the evidence channel shipped;
  • three arXiv staging certificates whose document was renamed at submission.

Two repairs outside charon

  • styxx.capsule: layer 2 compares verdict classes, not strings. The v0.13 UNCOVERED band appends , N uncovered — a coverage report, not a verdict change — and six sound capsules read as failures. A class change still fails; the string difference is advisory. This also unblocks scripts/zenodo_capsule_arc.py, which refused to deposit on exactly those four capsules.
  • styxx.sworn: GitTree._index sizes with --batch-check and streams. Reading every blob of a tree into one buffer per commit grew a re-derivation to 13 GB and died.

Verification

  • full suite: 4509 passed, 11 skipped, 4 xfailed (1 deselected: the local-only release-caveat guard that scans gitignored bundles; green on CI)
  • tests/test_charon.py 27, tests/test_capsule_uncovered_suffix.py 3, ruff clean on every touched file

Corrected in place, and how. This line said 22 until we gated this PR body against its own diff
(python -m styxx.diffgate pr60_body.md --repo . --base feat/sworn-v02-next-level --head feat/charon-v01).
The gate extracted 2 checkable claims from 63 sentences and verified both; it could not check this
one, because a test count in this shape is outside its closed template set. But its unparsed_claims
band flagged the sentence as claim-shaped, we counted by hand, and it was wrong: 27, not 22. That is the
extraction hole this lab has measured at 0.23 and 0.16 precision, reproduced on our own prose in the
hour we shipped it — and it is the argument for sworn output, where the author binds the number instead
of hoping a reader's parser finds it.

  • RESULT re-sworn at 16e30ef: 26 spans, SWORN-HELD

Also in this branch

papers/closed-model-frontier/DESIGN_provenance_law_2026_09_02.md (sworn): leg 4 of the plan — 12 gates, 4096 combinations, 12 named verdicts, every gate with a power basis, contaminated prior cited by digest. Licenses nothing until signed.

What it does not say

That any verdict is true. Who wrote any line. That a rebuilt or truncated log is detectable without a head pinned outside it. That receipt shopping is prevented — it is printed. That anything is immutable or tamper-proof. Thirty-four *.seal.json artifacts have no deriver and appear on no line. The attacker was the builder.

🤖 Generated with Claude Code

darkflobi and others added 7 commits September 2, 2026 14:02
…s what a verdict can mean, with a total gates table and its contaminated prior cited by digest

Leg 4 of PLAN_the_next_level. A design, not a preregistration: the proposed gates block parses
under styxx.protocol, every one of 4096 gate combinations reaches one of 12 named verdicts, every
gate carries a power basis, and the exploratory token-kind receipt is cited by blob digest as the
contaminated prior. Fresh corpus disjoint from the 140 + 82 repositories already judged; two seat
families gated alone; integer cells sized to 30; additivity as the test that separates a
form-independent factor from an interaction; one-repository concentration as an INVALID. Sworn,
9 spans, at d35ed81. Licenses nothing until signed and renamed.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Every verdict this lab ever issued, re-derived from bytes, hash-chained, with the size of the
receipt set printed beside every HELD; SKEW (the verifier moved) distinguished from DRIFT (the
bytes moved); reproduces, never adjudicates; no signatures, no fetch, no immutable.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ned, with the receipt-set size on every line

styxx/charon.py, built to SPEC_charon_v01_2026_09_02.md. Three derivers wrap the three
verifiers the lab already has (styxx.sworn at a named commit, styxx.capsule, styxx.corpus_audit
over styxx.certify); Charon reproduces and never adjudicates. Every entry is a JCS-digested core
chained to the line before it; timestamps are outside the digest. verify names SKEW (the verdict
moved and the verifier's bytes moved) apart from DRIFT (the verdict moved under the same build),
UNRESOLVED (bytes unavailable, never an accusation) and TAMPER (the chain broke); exit 1 only on
TAMPER. The page is one static file with no script and no request.

The first log: papers/charon/charon.log.jsonl — 18 sworn documents at their commits, 12
capsules, 210 tracked certificates (anc/ staging copies excluded); verify: 240 REPRODUCED, 0 of
anything else; head 7eec6b2f. Two capsules record reproduced=false at ingest with the reason on
the line: the UNCOVERED suffix a later verifier added to the verdict string, and the retired
path-claim branch changing the gate record — the instrument moved since they were minted, and
capsule.py compares verdict strings where the corpus auditor compares classes. Recorded, not
repaired here.

tests/test_charon.py: 13, incl. tamper by edit and by removal, SKEW vs DRIFT vs MOVED_VERIFIER
under a monkeypatched verifier, UNRESOLVED on an absent commit, LF everywhere, no <script.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…roduced-at-ingest split; the page colours OATH classes

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…s the 49th arc

Every count bound to charon_verify_result.json or to a line of the log itself: 240 lines, 240
REPRODUCED, 0 TAMPER, receipt sets up to 21 with 10 of 227 held-class lines on ten or more,
18/18 sworn documents reproduced at ingest, 6 OATH capsules and 1 diffgate capsule not (the
verifier moved: the UNCOVERED suffix, the retired path branch), 3 certificates not — two known
drift flags and one new: the staged arXiv copy arxiv/read_neq_write/source.md re-certifies
OATH-FAILED where it recorded OATH-HELD, outside the papers/ tree the corpus audit walks.
INDEX row added; charon leaves NOT_ARCS; CHANGELOG entry.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…log rebuilt at schema v1

papers/charon/ATTACKS_charon_v01_battery_2026_09_02.md — three attackers, three lenses, run
against the module at 6b61f12 before any announcement, as the standing rule requires. Four
sentences the instrument published about itself were false and are now narrower and true:

1. the chain binds order and content TO THE HEAD, not against rebuilding. A forger who recomputes
   seq/prev/entry_id down the file produces a chain that checks. verify/status now take
   --expect-head, HEAD_MISMATCH is a status, and a report without an expected head establishes
   internal consistency only — which the report now says.
2. capsule verdicts were COPIED from the embedded record, not re-derived; verify_capsule computed
   a live verdict and returned the embedded one. Both capsule kinds now carry the live
   re-derivation, with the embedded string as counts.recorded_verdict; a test forges an embedded
   verdict and asserts it never reaches the line.
3. verify compared the verdict class and one module's bytes; a line whose receipts, subject digest
   and commit had all moved came back REPRODUCED. It now compares the whole core and reports
   fields_changed, subject_moved and receipts_moved. REPRODUCED is renamed SAME_LINE — the old
   word collided with the artifact-level `reproduced` flag.
4. SKEW saw one file. verifier.modules now carries the whole derivation path — Charon included —
   and SKEW detection is bounded by that set, which the module states.

Also repaired: a chained header (an edited header is TAMPER); ingest onto a headerless log
refused; a BOM, a non-JSON line or a missing key is a reported problem, never a traceback; no
absolute path is ever written; a missing log is refused instead of printing a clean zero; CRLF and
file digest reported; resolved receipts hashed onto OATH lines beside the cited ones; sworn
`reproduced` runs styxx.sworn.verify_receipt rather than comparing one string; vacuous HELD
excluded from held counts; `derive` prints the exact core a line carries and the page prints that
command on every row.

styxx/capsule.py: layer 2 compares verdict CLASSES, not strings. The v0.13 UNCOVERED band appends
", N uncovered" to a verdict — a coverage report in the headline, not a verdict change — and six
sound capsules read as failures because of it. A class change still fails; the string difference
is reported as advisory. tests/test_capsule_uncovered_suffix.py pins both, incl. a forged class.

styxx/sworn.py: GitTree._index sizes with --batch-check and streams the bodies it keeps, from its
own feeder thread. Reading every blob of the tree into one buffer per commit grew a re-derivation
to 13 GB and died — the red team hit it and could not finish a re-verification.

The log is rebuilt at schema v1 by papers/charon/build_log.py, which IS the population: git
ls-files over the three suffixes, the arXiv staging certificates entering as UNRESOLVED lines
rather than absences, and one exclusion — the sworn RESULT that describes the log, because a
snapshot cannot contain its own description (the rule the corpus census already pays). 243 lines,
head bcffbebc; SAME_LINE 243, TAMPER 0. The v0 log stays in history at a5cf9ec.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nces the attackers found wrong

The RESULT is rewritten against the rebuilt log and re-sworn at 16e30ef: 26 spans, SWORN-HELD.
Every sentence the battery contradicted is corrected rather than softened:

- the handoff capsule's divergence is its tests_pass explanation string, which grew when the
  evidence channel shipped — not "the retired path-claim branch", which an earlier draft asserted
  and the bytes do not support;
- the three certificates are one whose verdict moved, one whose receipt changed (and is therefore
  incomplete), and one whose verdict moved — not "one incomplete" as a separate line; three more
  had no document at all and are UNRESOLVED lines;
- arxiv/read_neq_write/source.md is the canonical submission source, not a staged copy, and it
  sits outside the directory REPLICATIONS.md runs the corpus audit over — a property of the
  invocation, not of the code;
- "every verdict this lab ever issued" becomes "the record over three verdict-bearing formats";
  thirty-four seal.json artifacts have no deriver and appear on no line;
- receipts.n means different things by kind, and only the 8 OATH lines among the 10 held-on-ten
  are the shape the dogfood warned about;
- 243 SAME_LINE is a determinism check, not a stability result: verify ran under the builds ingest
  ran under, minutes later, on the same tree.

The ten OATH capsules now reproduce; six of them read as failures until the capsule verifier was
taught to compare classes, and that loosening is stated as one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@fathomlab fathomlab changed the title charon v0.1: the ferry log — every verdict re-derived from bytes, chained, with the receipt-set size on every line charon v0.1: the ferry log — every verdict re-derived from bytes, chained, and attacked before it was announced Sep 3, 2026
darkflobi and others added 3 commits September 3, 2026 12:02
…ree digest is content identity modulo newlines

CI caught it where Windows could not: the resolved receipt digests on an OATH line disagreed
between the two checkouts, because a raw hash of working-tree bytes is CRLF on Windows and LF on
Linux. Under that rule a stranger re-deriving this log on Linux would have seen all 213 OATH lines
move, and the promise the log makes — that a stranger re-runs it and gets the same lines — would
have been false on half the world's checkouts.

_content_sha256 normalises CRLF to LF before hashing, which is the doctrine
corpus_audit._receipt_sha_matches already states for certificates: a hash that depends on line
endings is pinning the wrong thing. Applied to an OATH certificate's document, its resolved
receipts, and a capsule file. NOT applied to a sworn document — that format refuses newline
normalisation by design and its bytes are pinned by .gitattributes — nor to digests from git
plumbing or embedded base64, which are already stable. Disclosed as the auditor discloses it:
this certifies content identity, not byte identity.

A consequence on every OATH line: receipts.sha256 and receipts.cited.sha256 now differ, because
every receipts_sha256 in this corpus was recorded from a Windows tree. Both sets are on the line
and the certificate still reproduces, because the auditor compares content.

tests/test_charon.py builds the same certificate under LF and under CRLF and asserts the two lines
carry identical subject and receipt digests. SPEC errata E15. Log rebuilt: 243 lines, head
1647a26a, SAME_LINE 243.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
26 spans, SWORN-HELD at dd78bc2. New head 1647a26a, new log digest, and one added sentence: a
working-tree digest is content identity modulo newlines, so an OATH line reads the same on either
checkout while the certificate cited what a Windows tree gave it — both sets are on the line.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
… check file was left at 48

The INDEX row landed with the charon RESULT; papers/build_index.py regenerates this file and it
was not re-run. No claim moves; the check reads ok either way.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@fathomlab
fathomlab merged commit c9661c8 into feat/sworn-v02-next-level Sep 5, 2026
7 checks passed
fathomlab added a commit that referenced this pull request Sep 5, 2026
…-derived from bytes and chained

charon v0.1: the ferry log — re-targeted to main after #60 merged into its own base
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