Skip to content

Codex/epistemic consolidation - #64

Merged
Cubits11 merged 18 commits into
mainfrom
codex/epistemic-consolidation
Aug 21, 2026
Merged

Codex/epistemic consolidation#64
Cubits11 merged 18 commits into
mainfrom
codex/epistemic-consolidation

Conversation

@Cubits11

Copy link
Copy Markdown
Owner

What changed

Why

Verification performed

  • make test-kernel passes
  • make test-release passes
  • New/changed public API has a docstring and a working example

Compatibility check

  • No naming collision with the existing Claim envelope schema or other module namespaces
  • No breaking change to public API without a version-bump note

Definition of Done reference

Which item(s) from the Launch-Hardening Plan does this satisfy?

claude and others added 18 commits August 19, 2026 21:39
Measures cc-framework against the standard set by the flagship sibling
repository ghost-ark, records what was found, and plans the work to close
the gap. Scope is cc-framework only; no change is proposed to any other
repository.

The organizing finding: the mathematics is exact and nobody can use it.
The LP recovers Frechet-Hoeffding to 1.11e-16 worst case and reproduces
the correlation cliff in 20s, yet three sibling projects reimplemented
the calculus rather than depend on this repository. One wrote down why --
the most discoverable composition entry point imposes an ROC/detector
ontology on events that are deterministic predicates, so a consumer read
the source and wrote 214 lines of JavaScript instead.

Adds under docs/upgrade/:

- BASELINE_MEASUREMENTS.md  every number with the command that produced it
- FINDINGS_REGISTER.md      20 findings, 5 at severity S1
- COMMITTEE_SCORECARD.md    12 dimensions, each naming what moves it
- VERIFICATION_LADDER.md    tiers, and what each does not establish
- DOWNSTREAM_CONTRACTS.md   contracts C1-C7 for the three consumers
- EPISTEMIC_UPGRADE_PLAN.md ten workstreams with acceptance gates

Measured baseline at 3e22c39: 689 tests pass but only after installing
three dependencies the [test] extra does not declare; coverage 69.91%
with the report CLI at 0% and core/stats.py at 38%; mypy reports 279
errors in 47 files at its own declared strict scope while CI enforces
7 files; no claim scanner and no coverage gate run anywhere.

Also adds scripts/canonicalization_probe.py, an adversarial census over
the canonicalization kernel every signed artifact routes through, modelled
on ghost-ark's E1 provenance-kernel census. It finds two unintended-kernel
classes: two Unicode-distinct keys silently become one, with no exception
raised, at top level and nested. Widening the corpus from six hand-probed
classes to eleven surfaced the nested case, reproducing E1's lesson that
breadth finds more defects. Four positive controls pass, so strictness is
not the explanation. The probe also records that five of six number forms
diverge from RFC 8785, which makes an independent non-Python verifier
impossible until the profile is decided.

Provenance of the corpus is census: exact counts, no confidence intervals.
The probe exits non-zero while any unintended-kernel class remains, so the
S1 findings are falsifiable rather than asserted.

Verified: full suite 689 passed / 9 skipped; ruff check and format clean
on the new script; all internal document links and anchors resolve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VnVFub3xq2vwPjjz3MUqZV
…greement

Delivers upgrade workstream W5. Consumability 2.6 -> 6.8,
cross-implementation agreement 0.0 -> 6.5, on delivered evidence.

The excavation found that three sibling projects reimplemented this
repository's calculus rather than depend on it, and one wrote down why:
cc.core.composition_theory operates on ROC point sets and bounds the
Youden J statistic, which presumes each guardrail is a classifier with a
threshold and an operating curve. Their controls are deterministic
refusal rules. They wrote 214 lines of JavaScript instead.

What ships:

- src/cc/compose/  Named marginals in, sharp interval out. No ROC,
  Youden, TPR, FPR, threshold or operating-point concept anywhere in the
  public signature, pinned by a test that greps for that vocabulary so
  the surface cannot drift back. Detectors reach it through
  marginal_from_operating_point, which points inward. The result carries
  the independence baseline, the binding event, the marginal provenance
  and the non-claims, so a bound over assumed rates cannot serialize
  without the word "assumed" attached.

- conformance/cc-kernel-v1/  24 accept and 8 reject cases with pinned
  exact values, a 256-line normative SPEC.md, and a manifest with
  digests and a 1e-12 tolerance. Every accept case is cross-checked
  against the finite-atom LP at generation time; the build refuses to
  write a case the closed form and the LP disagree on.

- verifiers/node/cc_compose_verify.mjs  A zero-dependency Node
  implementation written from SPEC.md rather than from the Python.
  24/24 accept, 8/8 reject, and it reproduces an external consumer's
  published numbers.

- scripts/differential_compose.py  Randomized differential fuzz over
  both implementations, agreeing on the answer or on the refusal.
  23,000 cases across six seeds, zero disagreements.

- src/cc/cli/guard.py + cc-guard  The inference guards as a
  stdin/stdout JSON subcommand and as a pure-data decision table, so a
  non-Python caller needs no Python process. A downstream project asked
  in writing to route through the post-selection refusal and could not;
  now it can. Tests assert the table matches the code rule by rule, and
  that cc-guard agrees with cc.kernel.cliff.cliff_certificate in both
  directions.

- tests/acceptance/  The gate. An external consumer's published
  four-control result reproduced from cc.compose: interval [0, 0.01],
  independence baseline 1.2e-5, understatement factor 833x, all three
  published scenarios, and their sensitivity finding that improving a
  weak control moves the upper bound by 0.00pp.

The fuzzer found a real bug on its first run: countermonotone dependence
with exactly one event, where the Python raised IndexError and the Node
silently returned NaN. Both were wrong, differently, and the curated
corpus had not thought to ask. Both fixed and pinned as
reject-countermonotone-one-event.

Also fixes finding F-01: build, setuptools and wheel added to the [test]
extra, with a CI job that installs .[test] specifically so the extra
strangers are told to use is the extra that is tested.

Corrects finding F-12, which was wrong. It claimed the claim-boundary
manifest was validated by nothing; the original grep covered .github/
and Makefile but not tests/, where the validator is in fact called, and
it already checks that every supporting_files path exists. The
correction is recorded in place rather than edited away, and the
enforcement score is revised from 2.1 to 4.0. Two narrow gaps remain.

Honest limits, stated in the artifacts themselves: both implementations
were authored in the same project, so a wrong specification yields two
implementations wrong together. This is a differential-testing
instrument, not an independent replication. The one genuinely
non-same-author check is a single external oracle on a single scenario
family. Neither the corpus nor the fuzzer covers the constrained LP
path. No downstream project has adopted this yet.

Verified: suite 689 -> 815 passing, 0 failing, 9 skipped. Coverage
69.91% -> 70.13%; cc/compose/_bounds.py 97.09%, cc/cli/guard.py 97.56%.
Closed form agrees with the LP to 3.3e-16 over 600 randomized cases.
Ruff check and format clean on all new files. All internal document
links and anchors resolve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VnVFub3xq2vwPjjz3MUqZV
Delivers upgrade workstream W3. Canonicalization and provenance
integrity 3.8 -> 8.2. All five findings in this dimension are fixed:
F-03, F-04, F-05 at severity S1, and F-06, F-07 at S2.

A receipt identifies a document only up to the kernel of its
canonicalizer. The old kernel had two members it should not have had.
It applied NFC normalization to every mapping key and wrote the results
into a fresh dict, so two byte-distinct keys sharing a normal form
silently became one, with no exception, at top level and nested. The
receipt then attested faithfully to a document with a field missing.
It also emitted Python repr number forms, which diverge from RFC 8785
on five of six probed forms, so no verifier in another language could
agree on the bytes.

cc.canonical.v2 implements RFC 8785: ECMAScript Number::toString number
forms, UTF-16 code-unit key ordering, no normalization, and unpaired
surrogates refused. 15 of 15 probed number forms conform.

The remedy is not the one the plan proposed. The plan said normalization
must detect collision and fail closed. The better fix, taken instead, was
to stop normalizing: RFC 8785 makes normalization the producer's
responsibility, and a canonicalizer that mutates content is not a
canonicalizer. Two keys differing in Unicode form are two keys, which is
what JSON says they are, so there is nothing left to collide. The
detection survives as assert_no_confusable_keys, an opt-in producer lint
deliberately kept off the hash path -- the original mistake was exactly
that a content-altering rule lived inside canonicalization.

One declared narrowing of RFC 8785: integers beyond the IEEE-754 safe
range are refused rather than emitted, because JCS is defined over
doubles and Python's int is unbounded. Emitting bytes that cannot
survive a round trip through a conforming parser would produce a receipt
nobody else can check. The narrowing is documented rather than left as
an undocumented difference.

cc.canonical.v1 is retained read-only and remains bug-compatible.
Verification dispatches on the profile each receipt declares, so
pre-migration receipts stay verifiable; recomputing one under RFC 8785
would report a mismatch for a report that is intact, which is the
opposite of what a receipt is for. A test asserts v1 still carries its
defects, so it cannot be silently "fixed" out from under history.

strict_json_loads refuses repeated keys at any nesting depth and is
wired into the report CLI reader, the claim-governance report and
artifact readers, and the Merkle transparency-log line reader.

Migration was verified, not assumed. Every regenerated capsule artifact
was diffed with hashes, hash-derived ids, and the profile identifier
scrubbed; all eleven were byte-identical under that scrub. No content,
no claim text, and no non-claim changed -- only hashes moved.

Two existing tests were rewritten because they asserted the defect as a
feature. test_merkle_log_normalizes_unicode_nfc_like_reporting required
that a composed and a decomposed spelling produce the SAME leaf hash;
under RFC 8785 they are two strings and must not. Its replacement
asserts the corrected behavior and records why.

One probe intent was corrected: int-vs-float-same-value moved from
distinct to equivalent. The original declaration described Python's type
system rather than JSON's, which has exactly one number type.
Correcting a declaration that was wrong about the domain is legitimate;
correcting one to flatter a measured result is not. Recorded in the
probe source and the profile document rather than edited away.

Honest limits, stated in the artifacts: no fuzzing of the canonicalizer,
so the census establishes that the declared classes behave as declared
and nothing about the rest of the input space. No cross-language
differential on receipts yet -- the conformance corpus covers the
composition kernel, but nothing re-canonicalizes a CC report in another
language and compares digests, so "cross-language verifiable" describes
v2's design rather than a demonstrated result. No external reviewer has
attacked either profile.

Census under v2: 12 sound, 1 fail-closed, 1 sound-by-rejection; zero
unintended-kernel, zero rejection-asymmetry, zero over-discrimination,
with four positive controls passing.

Verified: suite 816 -> 873 passing, 0 failing, 9 skipped. Capsule
replays byte-identically. Node conformance agreement and differential
fuzz both still pass. Ruff check and format clean on every touched file.
All document links and anchors resolve.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VnVFub3xq2vwPjjz3MUqZV
The Evidence Commons needs an instrument that emits evidence cards. This is
that instrument, scoped to cc-framework: the emitter and its schema, not an
Atlas, a site, or any surface that renders them.

A card is a claim plus everything needed to DISAGREE with it: how it was
operationalized, the command that reproduces it, what would falsify it, what
it assumes, and what it explicitly does not claim.

The design constraint is negative. A card is not a trust score, and nothing
here computes one. Three labels travel with every card and they are
orthogonal:

  evidence_state     local-only | aws-synth-only | aws-live | illustrative
  verdict            pass | fail | unverifiable | not-run
  publication_state  draft | released | superseded | retracted

None implies another. A pass that is local-only says nothing about deployed
behaviour. A retracted card may still carry a pass: the run happened and the
claim was withdrawn anyway. That orthogonality is enforced rather than
documented -- tests assert the card exposes no status/score/is_ok/badge/health
property, that the site manifest carries no aggregate, that the schema defines
none, that render_labels returns all three or raises, and that all 64 label
combinations are constructible. If a future change couples two labels, the
last of those fails.

Two fields most claim registries treat as optional are mandatory here:
falsifier and non_claims. Both are now required in the claim-boundary manifest
itself, enforced by the validator, so every claim in this repository carries a
falsifier because one cannot be added without it.

not-run is the default verdict. A card cannot acquire a passing verdict by
being written confidently; a pass is reachable only via --run, which executes
the commands. The committed cards are always the not-run scaffold, asserted by
a test: verdicts are host-specific and a repository shipping someone's laptop
results as published evidence is doing the thing this object exists to
prevent.

unverifiable is not fail, and the distinction earned itself on the first run.
make test-kernel exited non-zero because its dependency-install step could not
reach the network -- the kernel tests never executed. The first version of the
harness mapped any non-zero exit to fail and so reported a failure nobody
observed. It now attributes a fail only to pytest exit code 1, whose meaning
is documented; everything else is unverifiable with the reason recorded.
Per-command outcomes are preserved rather than collapsed, so a card shows
[pass=1, unverifiable=1] instead of hiding that the tests passed.

Also in this change:

- The manifest's supporting_tests_or_commands held bare test paths. A path is
  not a command, so seven were prefixed with `pytest `. The validator now
  checks that path-like tokens in commands resolve on disk, closing one of the
  two residual gaps recorded in F-12.
- Under --run, commands execute only if they match a small allowlist. A card
  generator that shells out arbitrary strings from a data file is a
  code-execution surface, not an evidence tool.
- The git revision records a -dirty suffix when the working tree differs. A
  card bound to a revision the tree does not match is bound to the wrong
  thing.
- Cards bind supporting files by digest, so editing one makes them stale.
  That is the feature working, and the ordering is documented.

Current state: 8 claims, evidence_state local-only=7 aws-synth-only=1, verdict
not-run=8, publication_state draft=8. The single synthetic lane is the
enterprise reference, whose card says on its face that emulated evidence is
never live evidence. Nothing here is aws-live.

Scope note: this repository emits cards and hosts no renderer. Pricing,
go-to-market, and venture planning are out of scope for a research repository,
matching the boundary the sibling institutional repository enforces with a
test.

Verified: suite 873 -> 907 passing, 0 failing, 9 skipped. All 8 committed
cards validate against schemas/cc.evidence_card.v1.json. Manifest validator
clean. Canonicalization census, Node conformance agreement, and the
conformance corpus all still pass. Ruff check and format clean on every new
and touched file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01VnVFub3xq2vwPjjz3MUqZV
Adds docs/research/future-expansion/, a method package for converting a
narrative or intuition into research objects that can be tested, replicated,
or discarded.

- README.md: purpose, operating loop, non-negotiable rules, cited research
  foundations, contents, mapping onto existing CC-Framework governance
  surfaces, and a porting manifest for the two sibling project tracks.
- source-ledger.md: a worked Week 1 artifact classifying one real narrative
  source statement by statement, with testable translations, disallowed
  inferences, the three method heuristics that survive translation, and a
  properly controlled falsification exercise for its only checkable claims.
- eight-week-plan.md: the eight-week schedule with per-week gates, two
  project tracks, and an appendix mapping each week's artifact onto the
  claim boundary manifest, non-claims, evidence roles, confirmatory
  protocol, receipts, and decay semantics already in this repository.
- prompt-library.md: eleven prompts that produce research artifacts rather
  than predictions.

Documentation only. Adds no claim to the claim boundary manifest, changes no
kernel or evidence behavior, and states explicitly that it is not evidence.

Verified with mkdocs build --strict, scripts/check_artifact_boundary.py
--static, and the full pytest suite (689 passed, 9 skipped).
…im Observatory

A 15-second film about the moment a seductive story is forced to become a
test. It is Chamber 00 of the existing Claim Observatory world: the room
before the Arrival Hall, where an intuition stops being a feeling and is
written down in a form that can lose.

Beats: a notebook under warm oracular light; a hard cut to cold as the ember
field quantizes into an 84-cell grid of coincidences that would all have felt
like proof; four tablets (claim, falsifier, control, non-claim) snapping into
a re-centering ledger; a protocol frozen over an empty result slot; the slot
filling with INCONCLUSIVE rather than a green tick; the five accents
compressing into a ledger rule under the wordmark.

- film.html: the film, one self-contained file. Every visual state is a pure
  function of time via window.__seek(t), so renders are reproducible rather
  than recorded. No downloaded fonts, no external assets.
- render_film.py: deterministic frame capture and H.264/VP9 encode, with a
  --verdict hook that displays a real verifier result verbatim.
- DIRECTORS_CUT.md: beat sheet, color law, voiceover, sound spec, production
  rules, poster frame, and the two lockups.
- README.md: how to watch, render, and place the Ghost-Ark cut.
- make film / make film-ghost-ark.

Two rules the film holds itself to. It uses no green at any point, because
World Bible V3 forbids a green checkmark as final truth; confirmatory cyan
carries that role and appears exactly once. And it renders no verdict it was
not given: with none injected it falls back to an illustrative INCONCLUSIVE
and stamps ILLUSTRATION on its own footage.

The repository README gains a hero built on the film's poster frame. The
rendered masters follow in the next commit.
… It"

Adds the 15.000s master and its poster frame: 1920x1080, 60fps, H.264 High,
yuv420p, faststart. The poster is frame 456 - the frozen protocol over an
empty result slot, which is the film's emotional center and the frame the
repository README now leads with.

Also fixes ffmpeg discovery. The Playwright bundle is built only for VP8
screen recording and has no libx264, so the encode failed after a clean
900-frame capture. find_ffmpeg() now probes each candidate for libx264 and
prefers one that has it, and --encode-only reuses frames already on disk so
an encoder problem never costs another full capture.
The release loop needs somewhere for curiosity to land. This adds that page and
the positioning that governs what may be said around it.

visual_identity/canonical_page/index.html carries the five required elements:
the film with a timecoded transcript, a condensed source ledger, a visible
"what this does not establish" strip, one real interactive check, and the
invitation to bring one claim that matters.

The check is real. It embeds calibration.json from the deterministic claim
governance capsule and the SHA-256 recorded in that capsule's manifest, then
recomputes the digest in the visitor's browser with WebCrypto. Editing one
character fails it closed. Nothing is simulated, no verdict is hard-coded, and
the fixture path, the command, and the limitation are printed underneath it:
integrity only, not validity and not safety.

tests/unit/docs/test_canonical_page_fixture.py guards the drift. If the capsule
is regenerated and the page is not updated, the page would show a legitimate
artifact failing closed - an honest-looking screen making a false statement.
The test fails first instead.

docs/product/PUBLIC_POSITIONING.md fixes the lockup, the bio, and the name
boundaries, including the strict rule that Ghost-Ark stays out of commercial
material and is referenced only as a labelled research case study. It also
records what is not sold: no validation, no compliance, no seal of approval.
Its own non-claims note that publishing a ninety-day plan is not evidence of
executing it, and that no superlative in it is licensed for public use.

Also adds a cubits11 cut of the film and moves the written thesis to its
flagship wording: a story can start a question, evidence must finish the answer.
…ur own guards

Turns scattered artifacts into one program: an inventory of what has actually
been built, a graph of how the pieces relate, the concept underneath all of it,
and the machinery for making it encounterable.

docs/research/epistemic-program/
- inventory.md: every artifact and the question it attempted to answer, with a
  mandatory limit column. A surprising fraction of this repository exists to
  prevent a conclusion rather than to produce one.
- research-graph.md: the invariant loop (claim, decompose, bind, reproduce,
  mutate, observe, bound, expose), eight nodes around CLAIM -> EVIDENCE, and
  where each artifact attaches. Intellectual connection without organizational
  merger: Ghost-Ark stays separate.
- evidence-scope-inflation.md: the core concept. A digest match licenses one
  inference and readers routinely make three more.
- challenges.md: open adversarial challenges, and the result of CH-001.
- visibility-manifold.md, distribution-packet.md, claim-intake.md,
  release-freeze.md: one object into seven surfaces, the first packet, what
  actually happens when someone brings a claim, and what ships.

CH-001 is the substantive finding. Attacking this repository's own drift guard
in a detached worktree: forging an evidence artifact and repairing the manifest
and page passes the drift guard but is caught by capsule regeneration. Moving
the forgery upstream to the declared input and regenerating the whole chain
passes everything - 4 + 5 tests green, governance verdict pass, a new valid
receipt, and the page displaying BYTES MATCH over a false-positive rate we
invented.

So the guard chain establishes deterministic reproducibility from declared
inputs, which is not measurement. Closing that gap needs an anchor outside the
repository, and there isn't one. The finding is fed back into the artifacts
rather than only written up: the canonical page's limits strip and limitation
text, a new entry in docs/research/NON_CLAIMS.md, and the drift guard's own
docstring now state it.

Also adds render_check_clip.py, which drives the real page in a browser and
captures the ten-second BYTES MATCH -> FAIL CLOSED clip frame by frame, so the
clip cannot drift from the artifact it depicts.
Packet 001 listed five posts and contained no copy. This writes them out in
publishable form: the demonstration, integrity is not truth, the self-attack,
name it before you see it, and the invitation.

Each carries a claim, its evidence, and its limit, and each ends at an object a
stranger can operate or break rather than at another piece of copy. Draft 03 is
the one to lead with once CH-001's write-up and the page's updated limitation
are both live.
…, not truth

CH-002 asked whether an outside reviewer can distinguish a measured input from
an asserted one without trusting the author. The answer is no, for a reason
worth stating plainly: any repository-local check is a function of repository
contents, and deterministic regeneration lets the author construct a state the
check accepts by editing an input and rebuilding. No inversion required. CH-001
is that argument executed.

The uncomfortable part is that the exploited property is the one we want.
Reproducibility guarantees a change propagates consistently through every
artifact, hash, and receipt - for honest and dishonest inputs alike.

Also records a cheap partial defence and why it is deliberately not implemented.
realized_fpr is exactly 1/24 and the shipped failure matrix has exactly 24 rows,
so a derivability check would have caught CH-001's 1/90 forgery. But no column
of that matrix has rate 1/24, so what the field denotes is not established.
Implementing the check would encode an unverified assumption about its meaning -
the same error class this program is about, committed while defending against
it. Establish the denotation first.

Names the three anchors that would actually close it, ranked by cost, and
records that none is implemented.
These predate this branch and are on main, but CI runs `ruff check .` on every
push, so the branch inherits a red build for them. All four fixes are mechanical
and semantics-preserving: one blank line, an import block split, and two set
comparisons flipped from `a <= b` to `b >= a`.

`ruff check .` is now clean across the repository.
…thesis

The full suite failed on tests/unit/core/models/test_models_base.py::
test_modelbase_migrate_best_effort. ModelBase.migrate() is documented as never
throwing on arbitrary old dicts; given {'updated_at': ''} it raises, because it
passes values straight into model_validate and updated_at has a timestamp
validator.

Verified pre-existing: reproduces identically on main in a detached worktree,
and src/cc/core/models.py is unmodified on this branch. It is nondeterministic
in CI because the failing example lives in a gitignored .hypothesis database.

Recorded rather than fixed. The obvious repair - swallow invalid values for
known fields - is silent repair, which this repository rejects everywhere else.
The defect is plausibly in the contract, not the code, so the write-up states
both options and recommends narrowing the contract instead. Applying that
unilaterally would be a semantic change to the core model layer made only
because it was inconvenient to this session's build.
# Conflicts:
#	examples/claim_governance_capsule/expected/cc_report.json
#	examples/claim_governance_capsule/expected/claim_envelope.json
#	examples/claim_governance_capsule/expected/claim_governance_audit.json
#	examples/claim_governance_capsule/manifest.expected.json
@Cubits11
Cubits11 merged commit 549295b into main Aug 21, 2026
18 of 28 checks passed
@Cubits11
Cubits11 deleted the codex/epistemic-consolidation branch August 21, 2026 01:25
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.

2 participants