Skip to content

Anchor witnessed release manifests in Bitcoin via OpenTimestamps - #182

Open
MaxGhenis wants to merge 2 commits into
codex/thesis-ledger-factsfrom
feat/ots-anchors
Open

Anchor witnessed release manifests in Bitcoin via OpenTimestamps#182
MaxGhenis wants to merge 2 commits into
codex/thesis-ledger-factsfrom
feat/ots-anchors

Conversation

@MaxGhenis

Copy link
Copy Markdown
Contributor

What

Every release manifest under releases/manifests/ gets a sibling OpenTimestamps proof, ots/<stem>.json.ots, over its exact bytes — the same bytes the two RFC 3161 authorities witness and the pinned producer key signs. A completed proof carries a Bitcoin block attestation, so the existence time of the journal state a manifest commits to (state.jsonlSha256, state.lineCount, state.immutablePrefixSha256, previousManifestSha256) is bounded by a system the operator does not control.

releases/README.md already names the gap this fills: internal verification cannot distinguish the original history from a freshly witnessed replacement fork, so verifiers must retain an external checkpoint. These proofs are that checkpoint, automated.

Contents

  • ots/ — proofs for all fifteen current manifests (0000–0014), stamped 2026-08-19. Attestations are pending until the calendars' aggregate Bitcoin transactions confirm; the scheduled job upgrades them in place.
  • scripts/ots_anchor.py — stdlib-only tool: run (stamp missing, upgrade pending; idempotent), verify (every proof binds to its manifest's current bytes; --require-bitcoin for strictness), status. Stamping happens on a temporary copy so nothing is ever written under releases/.
  • tests/test_ots_anchor.py — 8 tests against a fake ots reproducing the observed opentimestamps-client 0.7.2 output contract; no network in CI.
  • ots/README.md — what the proofs do and do not establish, and the verification procedure.
  • .github/workflows/ci.yml — the new files join the enumerated lint and test lists.

Gate compliance

  • No changes under ledger/ or releases/ — the append gate sees +0 appended vs base, release 14; verified locally with check_thesis_facts_append.py --base-ref origin/codex/thesis-ledger-facts and verify_release_chain.py --full (both green, OpenSSL 3).
  • ots/** is outside both the data and gate surfaces in scripts/receipt_pins.py, so daily proof commits and in-place upgrades can never collide with resolver append PRs or the release-history immutability sweep.
  • No dependency or uv.lock changes; the ots binary is provided by the scheduled workflow (pinned opentimestamps-client==0.7.2), not by this package.

Verify

python3 scripts/verify_release_chain.py --full
ots verify -f releases/manifests/0014-bd12e9e3e79a5529.json ots/0014-bd12e9e3e79a5529.json.ots

Without a local Bitcoin node, add --no-bitcoin before verify to validate the byte binding and print the attested block height and merkle root for manual checking. While attestations are pending the second command reports Pending confirmation in Bitcoin blockchain.

Follow-up

The daily schedule arrives as a separate PR to main (scheduled workflows only run from the default branch); it checks out this branch and runs scripts/ots_anchor.py run.

🤖 Generated with Claude Code

Each releases/manifests/<stem>.json already carries dual RFC 3161
receipts and a producer signature over its exact bytes. ots/<stem>.json.ots
now timestamps those same bytes through OpenTimestamps, so the journal
state a manifest commits to has an existence bound outside this
repository's control. Proofs live outside releases/ because the append
gate keeps that tree closed to anything but exact release bundles, and
OpenTimestamps upgrades rewrite proofs in place.

scripts/ots_anchor.py stamps missing proofs and upgrades pending ones
idempotently; all fifteen current manifests are stamped, with Bitcoin
attestations pending until the calendars' aggregate transactions confirm.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
MaxGhenis added a commit to ThesisInstitute/chronicle.institute that referenced this pull request Aug 31, 2026
The journal branch now carries an OpenTimestamps proof over every
release manifest's exact bytes (PolicyEngine/chronicle#182), upgraded
daily by a scheduled job (PolicyEngine/chronicle#183). The verify page
gains a section with the two-command procedure, and the about page notes
that anteriority no longer depends on trusting the operator's git
history.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Fable+Sol gate result on the updated head (545cfe5): changes requested. I agree with the peer; the tool needs these fixes before it carries over into the main-hosted rework that supersedes this PR (see the comment on #183):

  1. Incomplete inventory. The base now has manifests 0000–0019; proofs exist only for 0000–0014, so verify exits 1 on this very head. The two-manifest test fixture cannot see inventory drift. Stamping 0015–0019 needs network and is being done from a networked session.
  2. Committed proofs are still pending on disk. All 15 .ots files structurally contain only PendingAttestation entries. ots --no-bitcoin verify resolves the calendar upgrade in memory and prints the Bitcoin block, which is why the status I reported earlier read "attested". The upgrade must be persisted with ots upgrade, and status / --require-bitcoin must inspect the local proof structure (the opentimestamps library deserializes it), not calendar-resolved output.
  3. Substring classification of CLI output is unsafe. A pending calendar URI containing the attestation class name, or a calendar 404 message containing the manual-verification phrase, flips the classification. Parse the proof; use exit codes only as a secondary signal.
  4. upgrade_proof deletes .bak before checking the result, so a failed upgrade can leave no valid copy.
  5. The releases/ write prohibition is not enforced against symlinks (ots/ or a proof path pointing into releases/). Reject non-regular destinations and install into the verified real directory.

Disposition: not merging here. The rework PR against main will carry the tool with these fixes, the 15 proofs upgraded in place, and proofs for 0015–0019.

@MaxGhenis

Copy link
Copy Markdown
Contributor Author

Superseded by #229 (anchoring from main: tool, tests, workflow, and proofs on the trusted branch; the journal branch read credential-free as input only). The fifteen proofs from this PR carry over there upgraded in place, now with Bitcoin attestations on disk, plus proofs for manifests 0015–0019. This PR stays open until #229 merges, then closes.

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