From 0cae3f92bab6bffb24d6fd0307d48fc8b992b183 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 16:29:35 -0300 Subject: [PATCH 01/15] V30 Gate 1: Open roadmap and gating Open the V30 draft spec family over active V29 canon, refresh the specifications roadmap and contributor docs for V30 branch posture, and add Gate 1 validation for roadmap, workflow, and active/draft checks. Wire gate and canon quality workflows to validate V29 active / V30 draft posture while preserving V29 promotion readiness checks. Validated with check:v30-gate1, V29 promoted spec family, V29 canonical inputs, V29 promotion readiness, V30 draft spec family, V29/V30 posture drift, strict V30 spec quality, @bitcode/protocol tests, and git diff hygiene. --- .github/pull_request_template.md | 4 +- .github/workflows/bitcode-canon-quality.yml | 10 +- .github/workflows/bitcode-gate-quality.yml | 2 + BITCODE_SPEC_V30.md | 910 ++++++++++++++++++ BITCODE_SPEC_V30_DELTA.md | 178 ++++ BITCODE_SPEC_V30_NOTES.md | 67 +- BITCODE_SPEC_V30_PARITY_MATRIX.md | 102 ++ README.md | 41 +- SPECIFICATIONS_ROADMAP.md | 45 +- package.json | 1 + packages/protocol/README.md | 12 +- protocol-demonstration/README.md | 8 +- .../check-v30-gate1-roadmap-and-gating.mjs | 216 +++++ 13 files changed, 1535 insertions(+), 61 deletions(-) create mode 100644 BITCODE_SPEC_V30.md create mode 100644 BITCODE_SPEC_V30_DELTA.md create mode 100644 BITCODE_SPEC_V30_PARITY_MATRIX.md create mode 100644 scripts/check-v30-gate1-roadmap-and-gating.mjs diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index b1cc48f46..e1ab7c91e 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,7 +1,7 @@ ## Title -Use the version and gate prefix for gate PRs: `V29 Gate N: Concise Topical Title`. -Use the version and promotion prefix for version promotion PRs: `V29: Promote Canon`. +Use the version and gate prefix for gate PRs: `V30 Gate N: Concise Topical Title`. +Use the version and promotion prefix for version promotion PRs: `V30 Canonical Promotion: Concise Topical Title`. ## Closure diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index f7fa14f5b..c07148f3c 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -20,7 +20,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Validate active canon and V29 posture + - name: Validate active canon and draft posture run: | POINTER="$(cat BITCODE_SPEC.txt)" if [ "$POINTER" = "V28" ]; then @@ -32,6 +32,7 @@ jobs: node scripts/check-bitcode-canonical-inputs.mjs --current-target V29 node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V29 --draft-target V30 node scripts/check-bitcode-spec-family.mjs --version V29 --mode promoted --current-target V29 + node scripts/check-bitcode-spec-family.mjs --version V30 --mode draft --current-target V29 else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 @@ -64,7 +65,7 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Run V29 strict conformance for spec-title changes + - name: Run strict conformance for spec-title changes run: | case "$SPEC_TITLE" in spec:\ V29*|spec:\ v29*) @@ -75,7 +76,10 @@ jobs: node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 fi ;; + spec:\ V30*|spec:\ v30*) + node scripts/check-bitcode-spec-family.mjs --version V30 --mode draft --current-target V29 + ;; *) - echo "Skipping strict spec-title conformance; title is not a V29 spec change." + echo "Skipping strict spec-title conformance; title is not a V29/V30 spec change." ;; esac diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index c01f8f057..a2735fe28 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -75,9 +75,11 @@ jobs: node scripts/check-v29-gate10-local-staging-promotion-readiness.mjs --skip-branch-check elif [ "$POINTER" = "V29" ]; then node scripts/check-bitcode-spec-family.mjs --version V29 --mode promoted --current-target V29 + node scripts/check-bitcode-spec-family.mjs --version V30 --mode draft --current-target V29 node scripts/check-bitcode-canonical-inputs.mjs --current-target V29 node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V29 --draft-target V30 node scripts/check-v29-gate10-local-staging-promotion-readiness.mjs --promotion-mode --skip-branch-check + node scripts/check-v30-gate1-roadmap-and-gating.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md new file mode 100644 index 000000000..cf08d4820 --- /dev/null +++ b/BITCODE_SPEC_V30.md @@ -0,0 +1,910 @@ +# Bitcode Spec V30 + +## Status + +- Version: `V30` +- V30 state: draft target opened; V30 owns Protocol/BTD hardening over the promoted V29 Terminal transaction-depth canon +- Current canonical/latest target: `V29` +- Prior canonical anchor: `BITCODE_SPEC_V29.md` +- Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` +- Generated structured artifact inventory: none for V30 yet; V30 gate work must create `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, and `BITCODE_SPEC_V30_PROVEN.md` only as promotion evidence +- Source parity state: V30 source parity is draft-opened for Protocol/BTD package hardening, Bitcoin/PSBT rigor, BTD receipt boundaries, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness boundaries, telemetry hooks, and promotion automation +- State: draft target opened +- Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` +- Draft target source: `protocol-demonstration/src/canon-posture.js` declares `DRAFT_TARGET_VERSION = 'V30'` +- Primary scope: Protocol/BTD hardening over the promoted V29 commercial Reading, Finding Fits, AssetPack, settlement, delivery, and promotion baseline +- Prior active canon: `BITCODE_SPEC_V29.md` +- Notes companion: `BITCODE_SPEC_V30_NOTES.md` +- Delta companion: `BITCODE_SPEC_V30_DELTA.md` +- Parity companion: `BITCODE_SPEC_V30_PARITY_MATRIX.md` +- Generated proof appendix: none until V30 promotion +- Scope: V30 draft system specification for Protocol/BTD hardening after V29, including package API extraction, Bitcoin/Taproot/PSBT rigor, BTD-AssetPack mint/read receipts, testnet ledger/database projection hardening, source-to-shares proof cleanup, bridge-readiness research boundaries, telemetry/proof hooks, and promotion readiness +- Last fully realized canonical target preserved in source: `V29` + +V30 begins from promoted V29. +V29 made the Terminal transaction cockpit deep enough for operators to follow Reading, Finding Fits, AssetPack preview, settlement, rights transfer, delivery, repair, authority, and promotion readiness. +V30 hardens the Protocol and BTD rails beneath that cockpit so the commercial implementation can support enterprise shippability without ambiguous receipt, settlement, proof, bridge, package, or projection boundaries. + +## Version executive summary + +V30 is a Protocol/BTD-hardening version. +It does not create a new protocol supply law, a new `$BTD` denomination, or a versioned implementation route family. +It turns V29's promoted commercial Reading system into a stronger settlement, receipt, and proof substrate: + +- package APIs are narrower, explicit, and reusable outside one route or interface; +- Bitcoin fee, Taproot/PSBT, signer, broadcast, replacement, reorg, and finality semantics are typed enough to test and audit; +- BTD-AssetPack mint/read receipts bind source-safe preview, paid unlock, right transfer, delivery, and ledger state without protected-source leakage; +- ledger, database, object storage, and proof projections have deterministic roots, repair posture, and drift classes; +- source-to-shares measurement, settlement conservation, and contribution accounting are clean enough to support later Exchange work; +- bridge-readiness research is documented without becoming chain-of-record truth; +- Protocol/BTD telemetry and proof hooks are complete enough for V32 provation depth and V34 deployment depth. + +V30 closes only when the Protocol/BTD rails can safely support commercial Reading, Finding Fits, AssetPack preview, settlement, right-transfer, and delivery and when every V30 gate is specified, implemented, tested, documented, and promotion-ready. + +## Canonical Bitcode executive summary + +Bitcode is a protocol and commercial implementation for measuring technical knowledge, exchanging source-bearing AssetPacks, and settling rights through proof-backed Reading. +The active V29 canon remains: + +- a Deposit supplies source material to the Bitcode depository; +- a Read Request is synthesized into a reviewed Need before any Finding Fits run; +- `ReadNeedComprehensionSynthesis` uses PTRR agents and ThricifiedGenerations to synthesize a precise Need; +- `ReadFitsFindingSynthesis` searches the depository for all threshold-passing fit deposits, uses those fits as synthesis context, and produces a source-safe AssetPack preview; +- protected AssetPack source remains hidden before settlement; +- BTC is the fee asset; +- BTD range/read-license/right transfer and delivery are ledgerized; +- paid settlement unlocks the full AssetPack as a pull request against the Reader's repository. + +V30 does not redefine those laws. +V30 makes their protocol rails more precise, typed, auditable, and production-hardened. + +## V30 source-of-truth hierarchy + +The V30 source-of-truth hierarchy is: + +1. `BITCODE_SPEC.txt`, which remains `V29` until V30 promotion. +2. `BITCODE_SPEC_V30.md` during V30 drafting. +3. `BITCODE_SPEC_V30_NOTES.md`. +4. `BITCODE_SPEC_V30_DELTA.md`. +5. `BITCODE_SPEC_V30_PARITY_MATRIX.md`. +6. generated V30 artifacts under `.bitcode/` when produced. +7. `BITCODE_SPEC_V30_PROVEN.md` only after promotion. +8. source implementation, tests, internal docs, public docs, and QA evidence that realize this file family. + +Older specifications are provenance only. +They must not be used as hidden current-system law. + +## V30 full-system, re-implementation, and audit rule + +V30 must be re-implementable and auditable from its specification family without reading conversation history. +Every Protocol/BTD state, pipeline admission boundary, proof root, ledger/database projection, disclosure rule, fee/right transfer state, and promotion gate must identify: + +- canonical object; +- required inputs; +- outputs and stored artifacts; +- deterministic, inferred, external, or policy-derived fields; +- proof obligations; +- failure and repair posture; +- implementation and validation surfaces. + +## V30 totality and precision enforcement rule + +V30 fails closed when a Protocol/BTD feature only displays a happy-path summary while hiding missing proof, ledger, database, wallet, or delivery state. +Each gate must preserve exact abstraction names: + +- executions are the base runtime records; +- pipelines compose phase-wise behavior; +- agents are PTRR agents; +- PTRR steps are the four formal agent steps; +- sub-steps are ThricifiedGenerations; +- pipeline inference points are ThricifiedGenerations; +- tools are registry-backed tool calls; +- prompts are prompt-part and prompt-template registry compositions. + +No source identifier may introduce a versioned route, gate, or work-in-progress name unless explicitly accepted as a bounded compatibility artifact. + +## V30 system goals, non-goals, and design principles + +Goals: + +- harden Protocol and BTD package APIs into stable commercial primitives; +- make Bitcoin fee, Taproot, PSBT, signer, broadcast, replacement, reorg, and finality semantics exact enough for testnet operation; +- bind BTD-AssetPack mint/read receipts to source-safe preview, paid unlock, delivery, and rights transfer; +- make ledger/database/object-storage projection repair deterministic, proof-rooted, and source-safe; +- clean source-to-shares measurement, contribution, and settlement conservation proof surfaces for later Exchange work; +- document bridge-readiness and wallet/provider research without treating any bridge as current `$BTD` chain-of-record truth; +- add Protocol/BTD telemetry and proof hooks that V32, V34, and V35 can prove, deploy, and operate. + +Non-goals: + +- no Exchange market-depth implementation; +- no website Conversations product-depth implementation; +- no new `$BTD` supply law; +- no value-bearing mainnet approval; +- no broad provider completion beyond Protocol/BTD-owned hooks; +- no direct runtime dependency on `protocol-demonstration/`. + +Design principles: + +- typed receipts before prose summaries; +- no protected source leakage before settlement; +- typed events over raw JSON as the operator and API contract; +- ledger truth and database projection remain synchronized but distinct; +- failures must name the blocking primitive and the repair path. + +## V30 system architecture and layer boundaries + +V30 preserves the V29 architecture: + +- `packages/*` own protocol, BTD, pipeline, agent, prompt, tool, storage, and interface primitives; +- `packages/pipelines/asset-pack` owns Reading pipelines and AssetPack synthesis logic; +- `packages/pipeline-hosts` owns Vercel Sandbox and host-lane execution harnesses; +- `packages/btd` owns BTD range, measuremint, BTC fee, wallet, access, ledger, reconciliation, and terminal-journal primitives; +- `uapi` owns commercial API routes and operator UI surfaces; +- `protocol-demonstration` remains a standalone minimal reference and proof witness outside the workspace import graph. + +Layer boundaries: + +- Commercial interfaces may call commercial APIs and packages; they must not import demonstration runtime code. +- API routes may orchestrate pipelines; pipeline packages must remain reusable outside a single route. +- Ledger records and journals are source-of-truth for settlement/finality; Supabase/PostgreSQL projections must not contradict them. +- Source-safe previews may expose measurements, roots, score bands, policy ids, fee quote roots, and settlement posture; they may not expose protected source before payment. + +## V30 package API and receipt hardening canon + +V30 treats `packages/protocol`, `packages/btd`, `packages/api`, `packages/pipelines/asset-pack`, and `packages/pipeline-hosts` as the commercial Protocol/BTD hardening substrate. +The formal package boundaries are: + +- `@bitcode/protocol` owns active/draft canon posture, spec-family checks, generated-proof helpers, and promotion-governance helper APIs; +- `@bitcode/btd` owns BTD range/read-license/right-transfer state, Bitcoin fee operation posture, receipt roots, settlement conservation, access policy, and reconciliation primitives; +- `@bitcode/api` owns JSON-safe route adapters over package primitives, never hidden policy logic; +- `@bitcode/pipeline-asset-pack` owns source-safe AssetPack preview, Finding Fits synthesis contracts, and postprocess evidence roots; +- `@bitcode/pipeline-hosts` owns runtime harness evidence, host capability manifests, and readback/projection evidence. + +The commercial protocol package owns the active/draft posture while V30 is in flight: + +- `ACTIVE_CANON_VERSION = 'V29'`; +- `DRAFT_TARGET_VERSION = 'V30'`; +- spec-family, canonical-input, canon-posture-drift, and proven-generation helpers are exported through the package index; +- package tests and V30 checks fail closed on direct demonstration-source imports. + +V30 must reduce ambiguous cross-package behavior. +Any BTD, fee, receipt, or reconciliation object used by more than one interface must become a package-owned type, builder, parser, validator, and test fixture before the gate that depends on it closes. + +## V30 canonical domain model + +The V30 domain model extends V29 operationally: + +- `Deposit`: source supply with repository, branch, commit, depositor boundary, depository asset id, measurement, embedding document, and proof roots. +- `ReadRequest`: Reader-authored request with repository target, constraints, non-goals, desired artifact kinds, and context. +- `ReadNeed`: reviewed synthesis of the request, including requirements, exclusions, proof expectations, pricing vector, feedback lineage, and acceptance root. +- `FindingFitsResult`: all threshold-passing fit deposits, search roots, ranking roots, blockers, no-worthy-fit posture, and selected synthesis context. +- `AssetPackPreview`: source-safe measurements, quality score, disclosure policy, access policy, fee quote, range projection, and protected-source lock. +- `SettlementUnlock`: BTC fee proof, BTD range/read-license/right transfer, paid disclosure decision, delivery admission, and reconciliation state. +- `BtcFeeQuote`: deterministic BTC fee quote with quote root, measurement root, purpose, network, sats, pricing version, expiration, and lifecycle state. +- `WalletSignerSessionRecovery`: signer-session posture proving whether the Reader wallet can sign a PSBT without server custody. +- `BtcFeeOperationPosture`: operational state over quote, signer, PSBT, broadcast, finality, replacement, reorg, failure, and blocked readiness. +- `BtdAssetPackMintReceipt`: typed receipt binding AssetPack id, BTD range, depositor ownership, source-safe preview root, mint measurement root, settlement conservation root, and ledger projection root. +- `BtdReadReceipt`: typed receipt binding Reader, read request, accepted Need, Finding Fits result root, source-safe preview root, paid/unpaid disclosure state, read-right state, and delivery admission. +- `BtdRightsTransferReceipt`: typed receipt binding BTC fee finality, BTD owner or license transition, range projection, paid unlock, delivery proof, and reconciliation status. +- `SourceToSharesProof`: deterministic contribution and settlement accounting proof over fit deposits, measurements, range slices, fee quote, conservation checks, zero-cell/refit tail state, and no-overpayment/no-underpayment invariants. +- `BridgeReadinessResearchPosture`: non-chain-of-record research record for Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future bridge paths, carrying feasibility, risk, current non-admission, and rereview triggers. +- `TerminalTransaction`: URL-addressable activity combining execution, pipeline, agent, tool, prompt, ledger, database, delivery, and proof state. +- `TerminalTransactionReadModel`: typed operator projection of a selected `TerminalTransaction`, including route state, active detail section, low-detail summary, section availability, expandable audit posture, and source-safe raw-payload boundary. + +## V30 gate plan + +V30 closes through ten gates: + +1. **Gate 1: V30 Roadmap And Gating** opens the V30 family, makes `SPECIFICATIONS_ROADMAP.md` truthful after V29 promotion, and wires V30 checks. +2. **Gate 2: Protocol Package API Boundaries** narrows shared package APIs and removes route-local policy duplication. +3. **Gate 3: Bitcoin Taproot PSBT Fee Rigor** hardens fee, signer, PSBT, Taproot/script, broadcast, replacement, reorg, finality, no-custody, and network-boundary semantics. +4. **Gate 4: BTD AssetPack Mint And Read Receipts** defines typed mint, read, and rights-transfer receipts. +5. **Gate 5: Testnet Ledger Projection Hardening** hardens ledger/database/object-storage projection, repair classes, and staging-testnet readback. +6. **Gate 6: Source-To-Shares Proof Cleanup** cleans contribution measurement, settlement conservation, zero-cell/refit tail, ancestry, and no-overpayment/no-underpayment proof. +7. **Gate 7: Bridge Readiness Research Boundaries** records bridge research without admitting any bridge as chain-of-record truth. +8. **Gate 8: Protocol Telemetry And Proof Hooks** adds source-safe telemetry and proof hooks for receipts, fee states, projection, and source-to-shares facts. +9. **Gate 9: Interface Integration And Regression Proof** proves current interfaces consume package-owned objects without V29 behavior regression. +10. **Gate 10: V30 Promotion Readiness** validates local/staging proof, generated artifacts, V30 promotion workflow support, and post-promotion V30 active / V31 draft posture. + +## V30 whole Bitcode operator chain + +The V30 Terminal operator chain is: + +```text +Readiness + -> Deposit or select deposited source + -> Request Read + -> Synthesize and review Need + -> Request Finding Fits + -> Review source-safe AssetPack preview + -> Prepare BTC fee and settlement + -> Wallet signs or blocks explicitly + -> Ledger/database/right-transfer reconciliation + -> Paid delivery as pull request + -> Terminal journal, proof, and repair follow-through +``` + +Each transition must be observable as an execution, pipeline, PTRR agent, PTRR step, ThricifiedGeneration, tool call, ledger journal row, database projection, or repair receipt where applicable. + +## V30 Terminal transaction read-model canon + +Terminal transaction reading is route-owned. +When Terminal has a selected transaction, `/terminal?transactionId=` is the recoverable address. +`transactionDetail` selects a typed detail section and defaults to source-safe Shippables when omitted. + +The Terminal transaction read model must contain: + +- selected transaction identity, activity type, lens, status, participant, repository, branch, timing, and proof posture; +- route state with canonical hrefs for each section and with the former `runId` carrier removed on write; +- low-detail default summary, metrics, and posture chips sufficient for ordinary operation without opening raw JSON; +- section read models for Shippables, identity, Wallet/BTC, closure, proofs, history, journal, activity stream, and console; +- explicit section availability: available, empty, or blocked with an operator-readable reason; +- expandable detail metadata preserving row counts, metric counts, payload availability, and target DOM section ids; +- a source-safe disclosure boundary: protected AssetPack source is never displayed before settlement, and raw payloads remain audit detail rather than the default operator contract. + +The model is deterministic from execution history, detail readback, route query state, and data mode. +It must tolerate partial live readback by preserving a fallback selected-run projection while naming empty or blocked sections. + +## V30 Terminal UX quality and browser-proof canon + +The Terminal transaction cockpit is a protocol-facing operator interface. +It must be readable by default, keyboard reachable, responsive, and browser-proven. + +The cockpit must expose: + +- one named `main` landmark for the Terminal route; +- a keyboard-reachable skip link to the selected transaction workspace; +- a named transaction workspace region for activity selection, filtering, and selected-result digest; +- a named selected activity detail region for the low-detail detail hero, route-owned section controls, and source-safe detail surfaces; +- explicit loading, empty, failed, blocked, and source-safe preview states with `status` or `alert` semantics where appropriate; +- contained table overflow so phone and tablet viewports do not acquire document-level horizontal overflow; +- route-owned detail controls whose current, available, empty, and blocked states are understandable before raw payload expansion. + +The browser-proof contract is package-local to Terminal and exported by `uapi/app/terminal/terminal-ux-browser-proof.ts`. +It identifies the required landmarks, viewports, state semantics, route checks, and evidence files. +The focused Jest test proves the contract and state semantics. +The focused Playwright spec proves the cockpit in a real browser in deterministic mock mode across key route and responsive states. + +Gate 9 acceptance does not change Reading law, source disclosure law, settlement law, or organization authority law. +It makes the current V30 Terminal cockpit commercially operable enough that later local/staging promotion readiness can debug failures from the UI rather than from browser network logs alone. + +## V30 local and staging promotion readiness canon + +V30 promotion is admissible only when the version branch can prove both source +closure and promotion automation without relying on unstated operator memory. +Gate 10 owns that closure. + +The promotion-readiness contract has five parts: + +- all V30 gate scripts are invoked by gate-quality CI while `BITCODE_SPEC.txt` + remains `V29`; +- gate-quality and canon-quality workflows also accept the promoted state after + the V30 promotion workflow commits `BITCODE_SPEC.txt -> V30`; +- the canonical promotion command supports `--version V30`, validates the V30 + draft family, runs local proof suites, prepares V30 hand-authored status + truth, prepares runtime canon posture for V30 active / V30 draft, generates + `BITCODE_SPEC_V30_PROVEN.md`, writes `.bitcode/v30-*` proof artifacts, and + then validates the promoted V30 family; +- the version-promotion workflow runs only for a `version/v30` pull request into + `main`, validates the same proof surface, and commits the generated promotion + artifacts back to the version branch; +- local and staging-testnet QA evidence remains source-safe: environment + readiness, pipeline readback, Terminal browser proof, ledger/database + reconciliation posture, protocol package posture, and promotion dry-run are + named without committing secrets. + +`packages/protocol/src/canon-posture.js` and +`packages/protocol/data/state.json` are commercial runtime posture carriers. +They must align to V29 active / V30 draft during Gate 10 work and be rewritten +to V30 active / V30 draft by promotion automation. +The Gate 10 checker is promotion-mode aware: it must accept the V29/V30 package +posture before the generated canon commit and the V30/V30 package posture after +the generated canon commit. + +Gate 10 does not itself promote `BITCODE_SPEC.txt`. +It closes when `version/v30` can be pull-requested to `main` and the V30 +promotion workflow has enough scripted proof to produce the standalone +canonical promotion commit. + +## V30 Wallet/BTC operation canon + +Wallet and BTC fee state is an ordinary Terminal transaction surface, not an opaque settlement footnote. +The canonical wallet/BTC operation model is owned by `packages/btd` and projected by Terminal. + +The operation model must contain: + +- quote lifecycle: quoted, accepted, expired, superseded, and failed; +- deterministic quote root over quote id, purpose, network, sats, measurement root, issue time, and expiration; +- signer recovery: missing, prepared authorization required, stored authorization requiring live reconnect, expired, revoked, failed, network mismatch, capability missing, server-custody rejected, or live authorized; +- PSBT handoff: accepted quote prepares a PSBT; the wallet signs; the signed PSBT broadcasts; +- finality states: prepared, signed, broadcast, confirmed, replaced, reorged, and failed; +- blocked-readiness receipts naming the blocker id, summary, required action, quote id, wallet session id, receipt id, and no-server-custody posture; +- Terminal read rows and metrics for state, network, sats, confirmations, quote root, wallet session, payer wallet, PSBT handoff, txid, server custody, and next action. + +No server component may custody the Reader private key. +Server-side routes may prepare receipts, validate proofs, serialize quote/posture evidence, and persist registry rows only when explicitly requested. +They must not claim signature, broadcast, finality, settlement unlock, or rights transfer without matching receipt and readback evidence. + +The Terminal Wallet/BTC section is source-safe before settlement. +It may reveal quote roots, state labels, txids, and readiness blockers. +It may not expose protected AssetPack source, wallet secrets, provider tokens, or private signing material. + +## V30 settlement reconciliation repair canon + +Settlement reconciliation is an ordinary Terminal workflow, not an after-action database debug task. +The canonical report is produced from: + +- ledger observed facts: fee receipts, ledger anchors, journal entries, BTD ranges, ownership events, read licenses, and finality state; +- database projected facts: the Supabase readback rows that claim those ledger facts are durable in the application projection; +- private metaphysical canonical facts: protected source metadata, need/fit context, access policy documents, encrypted storage pointers, disputes, and telemetry context represented only by roots; +- settlement conservation checks: BTC debit/credit and fee/payment roots that must conserve before unlock; +- delivery evidence: post-settlement pull-request visibility and recovery posture. + +Drift is classified before repair: + +- `missing_database_projection`: the ledger has a fact that the database projection has not read back; +- `ledger_root_mismatch`: the database projection points at a different root than the ledger observation; +- `ledger_finality_mismatch`: the projected finality differs from the observed finality; +- `database_orphan_projection`: the database projects a fact that has no matching ledger observation; +- `settlement_conservation_drift`: BTC debit/credit or fee/payment accounting does not conserve. + +Repair actions are canonical and auditable: + +- `retry_database_readback`; +- `project_ledger_fact`; +- `update_finality_state`; +- `quarantine_database_projection`; +- `pause_settlement_unlock`; +- `recover_delivery`. + +The reconciliation state is one of aligned, retryable, repairable, approval required, or blocked. +Confirmed ledger facts that are missing from the database require operator-approved projection repair. +Reorged or failed finality, database-only orphan projection, or settlement conservation drift blocks unlock and delivery. +Delivery recovery is allowed only when settlement is otherwise aligned and the full AssetPack delivery target is not visible. + +Terminal must show drift classes, blockers, repair actions, proof roots, observed facts, projected facts, canonical facts, journal entries, and repair receipts before raw payloads. +The Vercel Sandbox harness must store the reconciliation report as settlement evidence when it claims ledger readback. +The API may persist schema-compatible repair receipts while richer repair actions and proof roots remain report evidence until the registry schema is formally expanded. + +## V30 canonical subsystem surfaces + +### Depositing and asset supply + +- Current canonical objects and emitted artifacts: Deposit, depository asset, repository snapshot, source measurement, embedding document, source proof root, ownership boundary, deposit journal row. +- Current algorithms and derivation rules: repository inventory binds source branch/commit; deposit admission creates searchable lexical/vector evidence; depositor ownership stays separate from later Reader rights. +- Current invariants and fail-closed conditions: invalid deposit, missing repository commit, unavailable source material, or absent depositor boundary blocks Finding Fits. +- Current proof obligations: source measurement root, embedding policy root, repository snapshot root, and depositor boundary proof. +- Current source-bearing implementation basis: `uapi/app/terminal`, commercial API routes, `packages/pipelines/asset-pack`, `packages/btd`, Supabase migrations, and readback scripts. +- Current validating commands and parity basis: V30 gate checks, V29 readback verifier until replaced, package tests, UAPI tests, and staging-testnet SQL/readback evidence. +- Current accepted boundaries: broader provider families remain staged unless Terminal requires a narrow GitHub-adjacent hook. + +### Reading and prompt/inference ownership + +- Current canonical objects and emitted artifacts: ReadRequest, ReadNeed, prompt registry ids, PTRR agent ids, PTRR step ids, ThricifiedGeneration ids, raw output posture, parsed typed output, and acceptance root. +- Current algorithms and derivation rules: the Reader's request is not admitted to Finding Fits until `ReadNeedComprehensionSynthesis` synthesizes a Need and the user accepts it. +- Current invariants and fail-closed conditions: prompt contract incompleteness, parsed-envelope inadmissibility, missing Need review, or feedback lineage mismatch blocks Finding Fits. +- Current proof obligations: prompt template, interpolated prompt, input context, output schema, raw response posture, parsed output, usage, model identity, and acceptance root. +- Current source-bearing implementation basis: Reading pipeline contracts, bounded structured inference, read-review API route, Terminal Read UX, and tests. +- Current validating commands and parity basis: pipeline contract tests, route tests, prompt rendering/audit checks, local live OpenAI validation, and V30 gate checks. +- Current accepted boundaries: full-profile async push completion can deepen in V30 gates but cannot bypass source-safe preview or settlement boundaries. + +#### V30 Reading pipeline observability canon + +Reading pipeline observability is contract-projected, not ad hoc. +The asset-pack package owns the inventory for `ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis`, and live harness events must project back to that inventory whenever they are emitted. + +The observable contract levels are: + +- execution; +- phase; +- PTRR agent; +- PTRR step; +- ThricifiedGeneration; +- prompt; +- tool; +- raw output; +- parsed output. + +For every live Reading stream event that can be associated with a contract, Terminal-visible telemetry carries: + +- pipeline name; +- phase id; +- PTRR agent id; +- PTRR step id and step name; +- ThricifiedGeneration id and failsafe; +- prompt template id and generation prompt ids; +- tool id, input type, and output type when the event is tool-backed; +- declared return type and output schema; +- prompt template/interpolated prompt presence; +- reasoning, judgment, raw model response, and parsed typed output presence. + +The Vercel Sandbox harness must export both the observability inventory and an observability coverage summary in its evidence artifact. +Coverage readback is not a settlement proof by itself; it is the operational proof that Terminal can debug a live Reading run without relying on browser network logs. +Failure to observe prompt, raw-output, parsed-output, or tool telemetry in a run that reaches those stages is a blocked-readiness signal for Gate 4+ QA. + +### Fit, recall, ranking, and verification + +- Current canonical objects and emitted artifacts: FindingFits query root, lexical search result, vector search result, fit deposit list, candidate score, ranking root, blocker list, and verification decision. +- Current algorithms and derivation rules: `ReadFitsFindingSynthesis` discovery searches the depository for all fits above threshold, ranks them, and uses fit deposits as contextual knowledge for AssetPack synthesis. +- Current invariants and fail-closed conditions: no-survivor asset pack, no-worthy-fit, mock/frontier source leakage, missing embedding policy, or missing candidate source root blocks implementation. +- Current proof obligations: search provider/tool ids, vector embedding policy, threshold, source roots, ranking roots, and selected-context root. +- Current source-bearing implementation basis: depository search tools, embedding configuration, AssetPack pipeline agents, and pipeline host harnesses. +- Current validating commands and parity basis: depository search tests, embedding tests, tool telemetry tests, staging readback, and Terminal stream tests. +- Current accepted boundaries: non-GitHub deposit providers are future unless required for a specific Terminal-owned repair. + +### Selection and materialization + +- Current canonical objects and emitted artifacts: AssetPack synthesis output, source-safe preview, delivery plan, branch artifact, pull-request delivery, branch artifacts and assetPackEvidence. +- Current algorithms and derivation rules: implementation uses discovered fit deposits as context; protected source is written only behind the paid unlock boundary; delivery materializes as a pull request after settlement. +- Current invariants and fail-closed conditions: unpaid preview cannot expose protected source; delivery cannot proceed without settlement unlock; branch identity must match ReadRequest repository context. +- Current proof obligations: synthesis prompt/output, preview policy, fee quote root, settlement unlock, delivery branch, PR id/url, and assetPackEvidence. +- Current source-bearing implementation basis: AssetPack pipeline postprocess, GitHub/VCS routes, pipeline host runner, Terminal delivery readback, and BTD package primitives. +- Current validating commands and parity basis: synthesis tests, source-leakage tests, route tests, PR delivery mocks/live checks, and V30 gate checks. +- Current accepted boundaries: full mainnet value delivery remains approval-gated. + +#### V30 AssetPack disclosure rights canon + +AssetPack disclosure is a first-class review object, not an incidental UI summary. +The preview before payment may show Need measurements, Finding Fits measurements, candidate ids, roots, score band, fee quote, range projection, access policy hash, and delivery target. +It must not show protected source content, the full patch, source-bearing manifest entries, or licensed read payload before the paid unlock is proven. + +The disclosure review contract carries: + +- `AssetPackSourceSafePreview`, which remains the source-safe preview envelope; +- `AssetPackDisclosureReview`, which binds preview id, AssetPack id, read-right state, source visibility, reader action, policy fields, range projection, roots, and protected-source leakage findings; +- owner-read, licensed-read, denied, and pending-settlement distinctions from BTD access primitives; +- paid unlock state from settlement readback; +- leakage review that fails closed when patch markers, source-code markers, or forbidden source-bearing fields appear in preview metadata. + +Terminal must render disclosure review as an ordinary Reading stage surface. +Collapsed view shows visibility, reader action, policy root, review root, visible/withheld counts, leakage state, and source unlock state. +Expanded views may show the review metadata and roots, but they still may not reveal protected source before settlement. + +Gate pull request titles are part of the same operator-quality posture. +Gate PRs into version branches must begin with the uppercase version and gate prefix, for example `V30 Gate 5: AssetPack Disclosure Rights And Preview Depth`, so gate history stays auditable from GitHub alone. + +### Identity, authorization, and sensitive flow + +- Current canonical objects and emitted artifacts: wallet identity, signer session, GitHub connection, organization role, read-license, access-policy decision, permission proof. +- Current algorithms and derivation rules: registry-derived permissions decide whether an operator can read, pay, unlock, deliver, repair, or administer a transaction. +- Current invariants and fail-closed conditions: authorization denial, stale signer session, missing org role, or sensitive data projection mismatch blocks action. +- Current proof obligations: wallet signature proof, provider installation proof, role/license readback, policy id/hash, and denial reason. +- Current source-bearing implementation basis: wallet API, VCS API, BTD access primitives, Terminal permission UI, MCP/ChatGPT action gates. +- Current validating commands and parity basis: wallet tests, access tests, API route tests, Terminal permission tests, and staging auth readback. +- Current accepted boundaries: broad enterprise RBAC depth can expand inside V30 only when tied to Terminal transaction operation. + +#### V30 organization interface authority canon + +Organization permission authority is a BTD primitive, not a per-interface convention. +The canonical decision is `BtdOrganizationInterfaceAuthorityDecision`. +It binds actor id, organization id, organization role, organization permission grants, interface surface, action, wallet binding, registry read-access decision, settlement state, explicit confirmation state, repair approval state, target anchor, source visibility, and proof roots. + +Gate 7 defines the current action set: + +- `read_transaction` +- `request_read` +- `review_need` +- `request_finding_fits` +- `review_asset_pack_preview` +- `pay_btc_fee` +- `unlock_asset_pack_source` +- `deliver_asset_pack` +- `repair_projection` +- `administer_organization` + +Each action has a minimum organization role, optional explicit permission grants, wallet-binding requirement, registry read-access requirement, settled-payment requirement, explicit-confirmation requirement, repair-approval requirement, and source-visibility result. +Protected-source actions fail closed unless role/grant, wallet binding, owner-read or licensed-read registry access, settlement, and interface admission all agree. +Source-safe preview actions may remain visible without protected source. + +The same authority primitive must be used by: + +- Terminal, as the ordinary permission explainer for selected activity detail; +- API routes, as the JSON-safe route decision for interface owners; +- MCP, as organization-scoped action authority over read-license and delivery operations; +- ChatGPT App, as connected-interface write admission over confirmed delivery writes; +- the sandbox harness, as emitted evidence for live Reading/AssetPack completion readback. + +Authority proof roots include role root, permission root, read-access root, interface root, and aggregate authority root. +Terminal renders those roots with blockers and decision rows so operators can understand why a transaction can or cannot pay, unlock, deliver, repair, or administer without opening network logs. + +### Disclosure and projection + +- Current canonical objects and emitted artifacts: disclosure policy, projection policy, redaction decision, preview metadata, owner-read/licensed-read/denied state. +- Current algorithms and derivation rules: source-safe preview reveals measurements and rights posture, not protected AssetPack source; paid unlock changes the disclosability boundary. +- Current invariants and fail-closed conditions: public projection overexposure, missing projection policy, or unpaid source access blocks display and delivery. +- Current proof obligations: disclosure boundary proof, projection policy hash, redaction decision, and access readback. +- Current source-bearing implementation basis: BTD access/projection primitives, Terminal preview components, API route serializers, and tests. +- Current validating commands and parity basis: disclosure tests, UI tests, readback queries, and source leakage scans. +- Current accepted boundaries: public docs may summarize posture but must not expose private source. + +### Settlement and exact accounting + +- Current canonical objects and emitted artifacts: BTC fee quote, PSBT, payment observation, settlement unlock, BTD range, source-to-shares, journal entry, ledger anchor, reconciliation report. +- Current algorithms and derivation rules: Share-to-Fee pricing is deterministic from measurement weights and measurement volume; BTC fee payment gates protected-source unlock and read-license/right transfer. +- Current invariants and fail-closed conditions: settlement conservation drift, missing payment proof, stale fee quote, unaccepted quote, missing signer capability, reorg, replacement, broadcast failure, or custody ambiguity blocks finality. +- Current proof obligations: quote root, signer recovery state, PSBT state, txid or blocked-readiness receipt, ledger anchor, source-to-shares report, and reconciliation result. +- Current source-bearing implementation basis: `packages/btd` fee/range/journal/reconciliation primitives, UAPI settlement routes, Terminal Wallet/BTC section, and Supabase projections. +- Current validating commands and parity basis: BTD tests, settlement route tests, Terminal wallet/BTC tests, staging ledger/database readback, and V30 gate checks. +- Current accepted boundaries: value-bearing mainnet stays outside V30 unless separately approved. + +### Proof contract, witnesses, and replay + +- Current canonical objects and emitted artifacts: proof family, member, theorem, witness artifact, replay step, generated proof appendix, validation report. +- Current algorithms and derivation rules: every promoted V30 claim needs a generated or executable witness, and every failure must preserve enough context for replay. +- Current invariants and fail-closed conditions: stale promoted status truth, missing witness, inconsistent proof root, or ungreen promotion validation blocks promotion. +- Current proof obligations: proof-family report, canonical input report, canon-posture drift report, promotion dry-run, generated appendix, and gate closure checks. +- Current source-bearing implementation basis: spec-family checker, canonical-input checker, promotion scripts, gate-quality workflows, and protocol-demonstration proof runtime. +- Current validating commands and parity basis: `check:spec-family`, V30 gate scripts, canon-posture drift checks, demonstration tests, package tests, and promotion workflow. +- Current accepted boundaries: V30 promotion automation may be hardened across gates but must be complete before `version/v30` merges to `main`. + +## V30 proof-family canon + +### Exact proof-family inventory matrix + +| proofFamily | proofArtifactPath | memberIds | theoremIds | replayStepIds | witnessArtifactPaths | Current source basis | +| --- | --- | --- | --- | --- | --- | --- | +| Inference-synthesis | `.bitcode/v30-inference-synthesis-proof.json` | prompt, model, parsed-output | prompt-complete, typed-output | render, infer, parse, persist | pipeline telemetry, route tests | Reading pipeline contracts | +| Prompt-completeness | `.bitcode/v30-prompt-completeness-proof.json` | prompt parts, templates, interpolations | no-hidden-prompt, context-bound | compose, render, record | prompt render outputs | prompt registry and tests | +| Static-code-analysis | `.bitcode/v30-static-code-analysis-proof.json` | source scans, route scans, import scans | no-versioned-routes, no-demo-import | scan, report | lint/typecheck outputs | scripts and CI | +| Verification-decisions | `.bitcode/v30-verification-decisions-proof.json` | Fit verification, preview verification | threshold, blocker, no-worthy-fit | search, rank, decide | depository search reports | asset-pack pipeline | +| Selection-and-materialization | `.bitcode/v30-selection-and-materialization-proof.json` | selected fits, delivery branch | paid-before-source, pr-delivery | synthesize, settle, deliver | AssetPack evidence, PR receipt | pipeline host and VCS routes | +| Authorization-and-sensitive-flow | `.bitcode/v30-authorization-and-sensitive-flow-proof.json` | wallet, org, license, policy | authorized-action, redaction | sign, authorize, project | wallet/access readbacks | BTD and UAPI | +| Settlement-source-to-shares | `.bitcode/v30-settlement-source-to-shares-proof.json` | fee, range, license, source shares | conservation, right-transfer | quote, pay, mint, reconcile | source-to-shares, fee receipt | BTD settlement primitives | +| Disclosure-boundary | `.bitcode/v30-disclosure-boundary-proof.json` | preview, paid unlock, denied state | no-prepay-source, paid-source | preview, unlock, read | projection-policy, leakage scans | access/projection code | +| Proof-contract | `.bitcode/v30-proof-contract.json` | families, theorems, witnesses | complete-family, replayable | generate, validate, promote | spec/proven artifacts | spec-family tools | + +### Inference-synthesis + +- proofArtifactPath: `.bitcode/v30-inference-synthesis-proof.json` +- members: Reading Need synthesis, Finding Fits discovery, AssetPack synthesis, preview validation, settlement unlock inference. +- theoremIds: prompt-complete, typed-output, model-bound, telemetry-persisted. +- replayStepIds: render prompts, call model or mock, parse type, persist execution telemetry. +- witnessArtifactPaths: pipeline telemetry rows, prompt render artifacts, route test reports, staging readback. +- current member closure criteria: each inference point is a ThricifiedGeneration under a PTRR agent step with a schema-bound output. +- current member verdict shape: pass, fail, blocked, or accepted-boundary with evidence path. +- current theorem-by-theorem closure reading: no theorem is closed without prompt, input, raw output posture, parsed output, model id, and usage state. +- current theorem-to-replay grouping: prompt composition, model call, parse, persist, and UI projection. +- minimum artifact/replay binding set: execution id, pipeline id, phase id, PTRR agent id, PTRR step id, ThricifiedGeneration id, prompt id, model id, output schema id. +- current proof-object fields: proofFamily, memberId, theoremId, replayStepId, evidencePath, verdict, blocker. +- generated-artifact and test bindings: `.bitcode/v30-spec-family-report.json`, pipeline tests, route tests, and Terminal stream tests. +- fail-closed conditions: missing prompt, missing typed parse, hidden model id, or missing telemetry blocks promotion. + +### Prompt-completeness + +- proofArtifactPath: `.bitcode/v30-prompt-completeness-proof.json` +- members: prompt part registry, prompt template registry, agent prompt registry, step prompt registry, sub-step prompt composition. +- theoremIds: every inference has a prompt template; every interpolated prompt is recorded; every schema is named. +- replayStepIds: collect prompt parts, compose prompt, interpolate context, record prompt payload. +- witnessArtifactPaths: rendered prompt files, telemetry rows, prompt tests. +- current member closure criteria: no inference occurs without a registered prompt path. +- current member verdict shape: pass, fail, blocked, accepted-boundary. +- current theorem-by-theorem closure reading: prompt completeness is required before parsed-envelope admissibility. +- current theorem-to-replay grouping: registry lookup, composition, interpolation, telemetry projection. +- minimum artifact/replay binding set: prompt ids, prompt part ids, context root, template text, interpolated text. +- current proof-object fields: promptId, templateId, contextRoot, inferenceId, schemaId, verdict. +- generated-artifact and test bindings: prompt inventory, prompt rendering tests, pipeline contract tests. +- fail-closed conditions: prompt contract incompleteness blocks the step. + +### Static-code-analysis + +- proofArtifactPath: `.bitcode/v30-static-code-analysis-proof.json` +- members: route version scan, import boundary scan, source casing scan, lint, typecheck. +- theoremIds: no versioned active source, no demonstration runtime import, no casing drift. +- replayStepIds: scan files, compare rules, emit report. +- witnessArtifactPaths: CI logs, local command output, `.bitcode` reports. +- current member closure criteria: all required scans pass or name accepted compatibility exceptions. +- current member verdict shape: pass, fail, blocked. +- current theorem-by-theorem closure reading: source shape must match active canon posture. +- current theorem-to-replay grouping: route scan, import scan, lint/typecheck. +- minimum artifact/replay binding set: command, exit code, checked paths, violations. +- current proof-object fields: ruleId, path, result, evidence, blocker. +- generated-artifact and test bindings: gate-quality workflow and local gate scripts. +- fail-closed conditions: active versioned route, stale draft posture, or direct demo import blocks closure. + +### Verification-decisions + +- proofArtifactPath: `.bitcode/v30-verification-decisions-proof.json` +- members: candidate fit verification, preview verification, settlement readiness verification. +- theoremIds: threshold-admitted, no-worthy-fit-is-honest, blocked-readiness-is-explained. +- replayStepIds: search, rank, verify, decide. +- witnessArtifactPaths: search result rows, ranking roots, verification reports. +- current member closure criteria: every Fit decision has candidates, thresholds, roots, and reasons. +- current member verdict shape: worthy_fit, no_worthy_fit, blocked_readiness. +- current theorem-by-theorem closure reading: the decision must be derivable from stored candidates and Need measurements. +- current theorem-to-replay grouping: recall, ranking, scoring, verifier judgment. +- minimum artifact/replay binding set: Need id, deposit ids, scores, threshold, ranking root, verifier output. +- current proof-object fields: decision, candidates, roots, reasons, output schema. +- generated-artifact and test bindings: depository-search tests, staging readback, Terminal preview tests. +- fail-closed conditions: fabricated candidate, missing source root, or absent blocker reason. + +### Selection-and-materialization + +- proofArtifactPath: `.bitcode/v30-selection-and-materialization-proof.json` +- members: selected deposits, AssetPack synthesis, branch artifact, delivery PR. +- theoremIds: context-bound-synthesis, paid-before-source, delivery-target-matches-read. +- replayStepIds: select, synthesize, preview, unlock, deliver. +- witnessArtifactPaths: assetPackEvidence, delivery receipts, PR metadata. +- current member closure criteria: materialized source is never visible to Reader before paid unlock. +- current member verdict shape: preview_locked, unlock_ready, delivered, blocked. +- current theorem-by-theorem closure reading: selection and delivery must read back from settlement and source roots. +- current theorem-to-replay grouping: fit selection, synthesis, settlement unlock, VCS branch, PR creation. +- minimum artifact/replay binding set: fitDepositAssetIds, sourceRoot, settlementUnlockId, branch, pullRequest. +- current proof-object fields: selectedIds, previewPolicy, unlockDecision, deliveryReceipt, blocker. +- generated-artifact and test bindings: pipeline host tests, VCS tests, readback verifier. +- fail-closed conditions: unpaid source exposure, mismatched target repo, missing PR receipt. + +### Authorization-and-sensitive-flow + +- proofArtifactPath: `.bitcode/v30-authorization-and-sensitive-flow-proof.json` +- members: wallet identity, signer session, provider connection, org role, read-license, policy decision. +- theoremIds: action-authorized, secret-not-projected, redaction-applied. +- replayStepIds: authenticate, authorize, project, redact. +- witnessArtifactPaths: wallet proof, connection rows, policy readback, redaction logs. +- current member closure criteria: sensitive data is only shown to authorized principals and only at the admitted boundary. +- current member verdict shape: authorized, denied, blocked, redacted. +- current theorem-by-theorem closure reading: an action cannot execute from UI intent alone. +- current theorem-to-replay grouping: identity proof, role/license lookup, policy decision, projection. +- minimum artifact/replay binding set: principal id, role/license ids, policy id/hash, decision. +- current proof-object fields: principal, policy, decision, reason, projectedFields. +- generated-artifact and test bindings: wallet/access tests, API tests, Terminal permission tests. +- fail-closed conditions: authorization denial or projection mismatch blocks action. + +### Settlement-source-to-shares + +- proofArtifactPath: `.bitcode/v30-settlement-source-to-shares-proof.json` +- members: fee quote, payment observation, BTD range, source-to-shares, read-license, journal. +- theoremIds: fee-conservation, range-conservation, license-transfer. +- replayStepIds: quote, prepare PSBT, observe payment, mint/transfer, reconcile. +- witnessArtifactPaths: `.bitcode/source-to-shares.json`, fee receipt, journal rows, ledger anchors. +- current member closure criteria: settlement must conserve BTC fee, BTD range, source shares, and right transfer. +- current member verdict shape: prepared, signed, broadcast, confirmed, blocked, reconciled. +- current theorem-by-theorem closure reading: no paid source unlock without fee and right-transfer readback. +- current theorem-to-replay grouping: quote root, payment path, ledger observation, BTD state, reconciliation. +- minimum artifact/replay binding set: fee quote root, txid or blocked receipt, range id, license id, journal id. +- current proof-object fields: quote, payment, range, license, reconciliation, blocker. +- generated-artifact and test bindings: BTD tests, settlement route tests, staging readback. +- fail-closed conditions: settlement conservation drift, stale quote, or chain reorg. + +### Disclosure-boundary + +- proofArtifactPath: `.bitcode/v30-disclosure-boundary-proof.json` +- members: preview, projection policy, redaction, paid unlock, denied state. +- theoremIds: no-prepay-source, paid-reader-source, denied-state-no-source. +- replayStepIds: project preview, redact source, evaluate unlock, read source. +- witnessArtifactPaths: `.bitcode/projection-policy.json`, preview payloads, leakage scan reports. +- current member closure criteria: source-bearing content crosses visibility boundary only after paid unlock. +- current member verdict shape: preview, locked, unlocked, denied, blocked. +- current theorem-by-theorem closure reading: disclosure posture must be explainable from policy, payment, and license state. +- current theorem-to-replay grouping: preview, settlement, license, projection. +- minimum artifact/replay binding set: preview id, projection policy hash, settlement unlock id, license id. +- current proof-object fields: visibility, policy, redactions, unlock, blocker. +- generated-artifact and test bindings: disclosure tests, UI tests, source leakage scans. +- fail-closed conditions: public projection overexposure or unpaid protected-source access. + +### Proof-contract + +- proofArtifactPath: `.bitcode/v30-proof-contract.json` +- members: spec-family report, canonical input report, canon-posture drift report, promotion proof appendix. +- theoremIds: complete-family, valid-draft, valid-promotion. +- replayStepIds: validate family, validate inputs, validate posture, generate proven, promote. +- witnessArtifactPaths: `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `BITCODE_SPEC_V30_PROVEN.md`. +- current member closure criteria: promotion cannot run unless all gate checks and generated proof inputs are green. +- current member verdict shape: draft-valid, promotion-ready, promoted, blocked. +- current theorem-by-theorem closure reading: generated canon must match the hand-authored spec family and source posture. +- current theorem-to-replay grouping: check, generate, dry-run promote, commit promote. +- minimum artifact/replay binding set: spec family files, generated reports, proof-source commit, promotion command. +- current proof-object fields: version, report, currentTarget, pointer, promotionCommit, verdict. +- generated-artifact and test bindings: spec-family checker, canonical-input checker, promotion workflow. +- fail-closed conditions: stale promoted status truth, missing generated appendix, or failed gate check. + +## V30 generated canon + +### Inherited V19 reproducible-canon artifacts + +V30 continues the reproducible-canon requirement: generated reports must be deterministic, path-addressable, and promotion-bound. + +### Inherited V20 operator-quality artifacts + +V30 continues operator-quality proof: Terminal workflow claims must be backed by UI, accessibility, responsive, error-state, and browser evidence where applicable. + +### Exact generated-artifact inventory matrix + +| artifact | required in draft | required at promotion | purpose | +| --- | --- | --- | --- | +| `.bitcode/v30-spec-family-report.json` | yes | yes | validates the hand-authored V30 family shape | +| `.bitcode/v30-canonical-input-report.json` | yes | yes | records canonical input closure for active V29 plus V30 draft | +| `.bitcode/v30-canon-posture-drift-report.json` | gate-dependent | yes | proves runtime/docs active/draft posture | +| `BITCODE_SPEC_V30_PROVEN.md` | no | yes | generated proof appendix for promoted V30 | + +### V30 specifying generated artifacts + +The minimum V30 generated set is `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, future `.bitcode/v30-canon-posture-drift-report.json`, and `BITCODE_SPEC_V30_PROVEN.md`. + +### Shared generated-artifact fields + +Every generated artifact must include artifact id, schema id, version, current target, source commit, command, generated timestamp, verdict, inputs, and blockers. + +### Artifact-specific generated payload fields + +Spec-family reports include required file lists and section counts. +Canonical-input reports include active pointer, family paths, generated artifact paths, and proof appendix posture. +Canon-posture reports include active canon, draft target, runtime carrier paths, and drift failures. +Promotion reports include proof-source commit and promotion command. + +### Artifact confidentiality and disclosability taxonomy + +Generated artifacts are internal by default, reviewer-visible when they contain no secrets, public only when explicitly projected, buyer-visible only after paid unlock, and never allowed to leak protected source or secrets. + +### Minimum generated appendix rendered contents + +`BITCODE_SPEC_V30_PROVEN.md` must render aggregate proof verdict, exact proof-family inventory, exact per-family member inventory, exact per-family theorem inventory, exact replay-step inventories and theorem bindings, witness artifact inventories, generated artifact inventories, scenario and run coverage matrices, proof-source commit, and fail closed when any required proof input is absent. + +### Canonical regeneration and fail-closed posture + +Generated canon must be regenerable from repository state. +Promotion must fail closed when any required report, witness, test, proof family, or source posture is stale. + +## V30 validation canon + +V30 validation is layered: + +- spec-family and canonical-input checks for the V30 draft; +- canon-posture drift checks for V29 active and V30 draft; +- V30 gate-specific scripts; +- package lint, typecheck, and Jest suites; +- UAPI route/component tests; +- Terminal browser, accessibility, responsive, and error-state checks; +- local non-mocked OpenAI/Supabase/Vercel Sandbox validation for gates that touch live pipeline behavior; +- staging-testnet readback where ledger/database synchronization or delivery is claimed. + +## V30 promotion canon + +V30 promotes only through `version/v30` into `main`. +Promotion must: + +1. pass every V30 gate check; +2. pass active V29 and draft V30 posture checks before promotion; +3. generate `.bitcode/v30-*` canonical reports; +4. generate `BITCODE_SPEC_V30_PROVEN.md`; +5. update runtime posture carriers from active V29/draft V30 to active V30/next draft; +6. commit `BITCODE_SPEC.txt` changing from `V29` to `V30`; +7. keep main protected by pull request and verified-signature rules. + +## V30 appendices and canonical supporting material + +The appendices below are binding draft structure for V30. +They name the proof, artifact, validation, source, workflow, and fail-closed surfaces that every later gate must keep synchronized. + +## Appendix A. Canonical type and surface catalog + +Canonical V30 type families: + +- Reading: ReadRequest, ReadNeed, FindingFitsResult, AssetPackPreview, SettlementUnlock. +- Pipeline: execution, pipeline, phase, PTRR agent, PTRR step, ThricifiedGeneration, tool call, prompt record, parsed output. +- Terminal: TerminalTransaction, journal row, stream row, detail accordion, repair action. +- BTD: range, source-to-shares, access policy, read-license, BTC fee quote, payment observation, ledger anchor, reconciliation report. +- Delivery: branch artifact, AssetPack evidence, pull request, delivery repair receipt. + +## Appendix B. Proof family closure catalog + +Each proof family named in the proof-family canon must have members, theorems, replay steps, witness artifacts, generated artifacts, and fail-closed conditions before V30 promotion. + +## Appendix C. Generated artifact contract catalog + +The V30 generated-artifact contract is exactly the generated canon section above plus Appendix K source-bearing artifact constraints. + +## Appendix D. Validation and checking gate catalog + +Gate validation starts with `pnpm run check:v30-gate1`. +Later gates must add focused scripts before claiming implementation closure. +Promotion validation must run all V30 gate scripts, source scans, package tests, UAPI tests, demonstration proof checks, generated report checks, and diff hygiene. + +## Appendix E. Current canonical source map + +Source map: + +- `BITCODE_SPEC.txt`: active canon pointer, still `V29` during V30 drafting. +- `BITCODE_SPEC_V30.md`, `_DELTA`, `_NOTES`, `_PARITY_MATRIX`: draft target family. +- `protocol-demonstration/src/canon-posture.js`: active/draft runtime posture carrier. +- `packages/pipelines/asset-pack`: Reading pipeline and AssetPack synthesis source. +- `packages/pipeline-hosts`: sandbox/harness execution source. +- `packages/btd`: BTD, BTC, rights, journal, and reconciliation primitives. +- `uapi/app/terminal`: Terminal operator surface. +- `.github/workflows`: gate and promotion automation. + +## Appendix F. Subsystem totality and derivability matrix + +V30 must cover repo supply and depositing; reading and measured demand; prompt/inference/evaluator ownership; deposit-to-read fit; recall and ranking; verification decisions; selection and materialization; branch artifacts and assetPackEvidence; identity, authority, signing, and policy; sensitive data and confidentiality flows; projection, disclosure, and redaction; proof families, members, theorems, witnesses, and replay; settlement, source-to-shares, journals, and exact accounting; telemetry, persistence, state, and failure semantics; host/runtime capability truth; operator experience and pedagogy; validation and test stack; generated artifacts and canonical promotion. + +The subsystem sections in the canonical subsystem surfaces chapter are the active derivability matrix rows for V30. + +## Appendix G. Canonical file-family and promotion contract catalog + +V30 file family: + +- `BITCODE_SPEC_V30.md` +- `BITCODE_SPEC_V30_DELTA.md` +- `BITCODE_SPEC_V30_NOTES.md` +- `BITCODE_SPEC_V30_PARITY_MATRIX.md` +- future `BITCODE_SPEC_V30_PROVEN.md` +- `.bitcode/v30-spec-family-report.json` +- `.bitcode/v30-canonical-input-report.json` +- future `.bitcode/v30-canon-posture-drift-report.json` + +## Appendix H. Operator surface and quality contract catalog + +Terminal quality must include: + +- URL-addressable transaction state; +- guided low-detail default path; +- expandable complete detail; +- readable live stream rows for pipeline, agent, tool, prompt, ledger, and delivery activity; +- keyboard and screen-reader usable controls; +- responsive layout; +- explicit empty, loading, blocked, failed, repaired, paid, and delivered states. + +## Appendix I. Scenario, workflow, and cross-product contract catalog + +V30 cross-product scenarios include auth-issuer-rollback, privacy-boundary-proof-export, polyglot-gateway-benchmark-remediation, auth-many-asset-normalization, Targeted deposit, Normalization deposit, patch, context, public, buyer, reviewer, internal, Openly writable, Measurably readable, Provable, and Valuable. + +These names are scenario/workflow coverage labels, not new product brands. + +## Appendix J. Fail-closed contract and error posture matrix + +Fail-closed states: + +- invalid deposit blocks Finding Fits; +- prompt contract incompleteness blocks inference; +- parsed-envelope inadmissibility blocks typed pipeline output; +- no-survivor asset pack blocks preview and settlement; +- authorization denial blocks protected action; +- public projection overexposure blocks display; +- settlement conservation drift blocks unlock and delivery; +- stale promoted status truth blocks promotion. + +Every fail-closed state must carry a readable Terminal blocker and a repair or retry posture when repair is allowed. + +## Appendix K. Source-bearing AssetPack and artifact contract catalog + +Source-bearing AssetPack artifacts include: + +- `.bitcode/asset-pack.lock.json` +- `.bitcode/selected-source-material.json` +- `.bitcode/verification-report.json` +- `.bitcode/source-to-shares.json` +- `.bitcode/projection-policy.json` +- `.bitcode/system-proof-bundle.json` +- `BITCODE_SPEC_V30_PROVEN.md` + +Before settlement, the Reader may see only source-safe preview metadata. +After settlement, the Reader may receive the full AssetPack source according to the paid read-license/right transfer and delivery policy. + +## V30 accepted boundaries and reopen conditions + +Accepted boundaries: + +- V30 remains Protocol/BTD-hardening, not Exchange depth. +- V30 may deepen MCP/ChatGPT only where Terminal transaction authority requires shared permission truth. +- V30 may harden demonstration-origin commercial internals but must keep the demonstration standalone. +- V30 may use staging-testnet and local live validation; value-bearing mainnet remains separately approved. +- V30 promotion automation may be implemented across gates, but it must be complete before promotion. + +Reopen conditions: + +- V29 promoted law is found inconsistent with source behavior. +- Terminal exposes protected source before settlement. +- ledger/database projection contradicts settlement truth. +- organization permission decisions cannot be derived from registry/access policy state. +- gate workflow cannot fail closed for stale active/draft posture. + +## V30 completion condition + +V30 is complete only when: + +- all gates in the V30 parity matrix are closed; +- the Terminal supports the deep transaction workflows specified here; +- live or bounded-real validation proves the claimed Reading/settlement/delivery paths; +- promotion workflows can promote only `version/v30`; +- generated V30 proof artifacts and `BITCODE_SPEC_V30_PROVEN.md` are produced; +- `BITCODE_SPEC.txt` changes from `V29` to `V30` only in the formal promotion commit. diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md new file mode 100644 index 000000000..65dbc3eb8 --- /dev/null +++ b/BITCODE_SPEC_V30_DELTA.md @@ -0,0 +1,178 @@ +# Bitcode Spec V30 Delta + +## Status + +- Version: `V30` +- V30 state: draft target delta opened for Protocol/BTD hardening +- Current canonical/latest target: `V29` +- Prior canonical anchor: `BITCODE_SPEC_V29.md` +- Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` +- Generated structured artifact inventory: none for V30 yet; draft gates must create V30 reports and generated proof only as acceptance evidence +- Source parity state: V30 source parity is draft-opened for Protocol/BTD package APIs, Bitcoin/Taproot/PSBT rigor, BTD receipts, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness boundaries, telemetry hooks, and promotion automation +- State: draft target delta opened +- Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` +- Scope: V30 draft delta for Protocol/BTD hardening over promoted V29 +- Spec companion: `BITCODE_SPEC_V30.md` +- Notes companion: `BITCODE_SPEC_V30_NOTES.md` +- Parity companion: `BITCODE_SPEC_V30_PARITY_MATRIX.md` +- Generated proof appendix: none until V30 promotion + +## Why V30 exists + +V29 canonically promoted Terminal transaction depth over the commercial Reading system. +It made the operator cockpit more navigable, recoverable, source-safe, repairable, and promotion-proven. + +V30 exists because the protocol rails beneath that cockpit now need commercial hardening before Bitcode can responsibly expand into Auxillaries depth, proof depth, interface depth, deployment depth, documentation depth, Exchange, and Conversations. +The focus is not a new product surface. +The focus is making Protocol/BTD packages, Bitcoin/Taproot/PSBT flow, BTD receipts, ledger/database/object-storage projections, source-to-shares proofs, and bridge-readiness boundaries stable enough for enterprise shippability. + +## Accepted V30 decisions + +- V29 remains active canon during V30 drafting. +- V30 gate branches are opened from `version/v30` and merged back only when their gate acceptance criteria are closed. +- V30 owns Protocol/BTD hardening, not another Terminal redesign. +- V30 preserves the V29 Reading journey: request Read, review synthesized Need, request Finding Fits, review source-safe AssetPack preview, buy/settle, and receive paid delivery. +- V30 narrows shared package APIs before they become Exchange, Auxillaries, interface, deployment, or documentation dependencies. +- V30 makes Bitcoin fee, Taproot, PSBT, signer, broadcast, replacement, reorg, blocked-readiness, and finality semantics typed and testable. +- V30 binds BTD-AssetPack mint/read/right-transfer receipts to source-safe preview, paid unlock, delivery, and reconciliation. +- V30 cleans source-to-shares contribution accounting, settlement conservation, zero-cell/refit tail posture, and no-overpayment/no-underpayment proof surfaces. +- V30 records bridge-readiness research without treating any bridge as current `$BTD` chain-of-record truth. +- V30 workflows and scripts must validate V29 active / V30 draft posture. + +## Explicitly deferred + +- V31 Auxillaries depth remains V31. +- V32 proof-family/provation expansion remains V32. +- V33 interface/MCP/ChatGPT/API depth remains V33 except for Protocol/BTD hooks needed by V30. +- V34 deployment/runtime/storage depth remains V34 except for host-capability facts needed by V30. +- V35 telemetry/documentation depth remains V35 except for Protocol/BTD telemetry hooks needed by V30. +- Exchange product/market depth remains beyond V35. +- Website Conversations product depth remains beyond V35. +- New `$BTD` supply law remains out of scope. +- Value-bearing mainnet launch remains separately approval-gated. +- Bridge integrations remain research posture, not chain-of-record implementation. + +## Pre-Implementation Sequence + +1. Open `version/v30` from promoted `main`. +2. Open `v30/gate-1-roadmap-and-gating` from `version/v30`. +3. Create the V30 SPEC, DELTA, NOTES, and PARITY family while preserving `BITCODE_SPEC.txt -> V29`. +4. Refresh `SPECIFICATIONS_ROADMAP.md` so V29 is active canon, V30 is draft target, and V31-V37 scopes remain coherent after recent V28/V29 work. +5. Retarget gate-quality and canon-quality workflow posture checks to V29 active / V30 draft. +6. Add `check:v30-gate1` and a V30 Gate 1 checker. +7. Define V30 gates, acceptance criteria, carryforward parity rows, and post-V30 roadmap responsibilities. +8. Validate spec family, canonical inputs, canon posture, workflows, roadmap truth, README/docs, and diff hygiene. +9. Push the gate branch and open a pull request to `version/v30`. + +## Commit-Body Direction + +V30 gate commit bodies should describe the closed gate, specification changes, implementation surfaces, tests, proof commands, and accepted boundaries. +The eventual V30 promotion commit body must name all closed V30 gates, generated proof artifacts, Protocol/BTD hardening surfaces, and the `BITCODE_SPEC.txt` pointer change from `V29` to `V30`. +It must explicitly defer V31+ scopes, Exchange, Conversations, bridge chain-of-record implementation, and value-bearing mainnet launch. + +## Gate Delta + +### Gate 1: V30 Roadmap And Gating + +Gate 1 opens V30 correctly: + +- V30 SPEC, DELTA, NOTES, and PARITY files exist. +- `BITCODE_SPEC.txt` remains `V29`. +- README, roadmap, PR template, and workflows describe V29 active / V30 draft posture. +- `check:v30-gate1` validates branch naming, spec family, notes, parity, roadmap truth, workflow posture, and promotion boundaries. +- The V30 gate list is explicit before product implementation begins. + +### Gate 2: Protocol Package API Boundaries + +Gate 2 narrows the commercial Protocol/BTD package API surface. + +Closure acceptance: + +- shared Protocol/BTD objects used by multiple interfaces have package-owned builders, parsers, validators, tests, and JSON-safe serialization; +- route code delegates policy and receipt derivation to packages rather than duplicating it; +- no commercial runtime code imports `protocol-demonstration/src/*`; +- package READMEs name ownership boundaries and accepted imports. + +### Gate 3: Bitcoin Taproot PSBT Fee Rigor + +Gate 3 hardens Bitcoin fee and signer semantics. + +Closure acceptance: + +- BTC fee quote, signer recovery, PSBT handoff, Taproot/script posture, broadcast, replacement, reorg, and finality states are typed; +- server-custody rejection remains explicit; +- testnet/mainnet distinction is policy-enforced and proof-rooted; +- focused BTD/API tests prove fee lifecycle and blocked-readiness behavior. + +### Gate 4: BTD AssetPack Mint And Read Receipts + +Gate 4 creates typed BTD receipt boundaries. + +Closure acceptance: + +- `BtdAssetPackMintReceipt`, `BtdReadReceipt`, and `BtdRightsTransferReceipt` are package-owned; +- receipts bind AssetPack ids, BTD ranges, Reader/Depositor identities, source-safe preview roots, paid unlock, delivery admission, and ledger projection roots; +- protected source remains hidden before settlement; +- receipts are stored, streamed, and rendered through existing execution and Terminal surfaces. + +### Gate 5: Testnet Ledger Projection Hardening + +Gate 5 hardens ledger/database/object-storage projection and repair. + +Closure acceptance: + +- ledger-observed facts, database projections, object-storage artifacts, and private metaphysical facts remain distinct; +- projection repair classes and proof roots are deterministic; +- Supabase staging-testnet readback can prove synchronized or blocked state without secrets in tracked files; +- reconciliation tests cover drift, quarantine, retry, and unlock blocking. + +### Gate 6: Source-To-Shares Proof Cleanup + +Gate 6 cleans contribution measurement and settlement conservation. + +Closure acceptance: + +- source-to-shares proof surfaces bind measurements, fit deposits, range slices, fee quote, contribution weights, settlement conservation, zero-cell/refit tail posture, and ancestry evidence where available; +- no-overpayment and no-underpayment invariants are testable; +- later Exchange work can reuse the proof without reinterpreting V30 accounting. + +### Gate 7: Bridge Readiness Research Boundaries + +Gate 7 records bridge-readiness without false chain-of-record claims. + +Closure acceptance: + +- Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future distribution paths have research posture records; +- each record names feasibility, risks, current non-admission, rereview triggers, and required proof before admission; +- no bridge path is treated as current `$BTD` chain-of-record truth. + +### Gate 8: Protocol Telemetry And Proof Hooks + +Gate 8 adds Protocol/BTD telemetry and proof hooks. + +Closure acceptance: + +- BTD receipts, BTC fee states, ledger projection, source-to-shares proofs, and bridge-readiness posture emit typed telemetry; +- telemetry avoids protected source and secrets; +- proof hooks are compatible with V32 provation and V35 documentation/observability work. + +### Gate 9: Interface Integration And Regression Proof + +Gate 9 proves existing interfaces can consume the hardened Protocol/BTD rails. + +Closure acceptance: + +- Terminal, API, MCP, ChatGPT App, and future Auxillaries/Exchange hooks consume package-owned objects without route-local reinvention; +- low-detail source-safe UX remains intact; +- focused regression tests prove no V29 transaction cockpit behavior regresses. + +### Gate 10: V30 Promotion Readiness + +Gate 10 owns final local/staging proof, generated artifacts, and V30 promotion workflow support. + +Closure acceptance: + +- `check:v30-gate10` validates promoted-readiness posture; +- V30 promotion workflow validates source branch, local proof commands, staging-testnet readback evidence, generated `.bitcode/v30-*` reports, and `BITCODE_SPEC_V30_PROVEN.md`; +- promotion scripts support V30 and rewrite post-promotion active V30 / draft V31 posture; +- `version/v30` can be requested into `main` only after all V30 gates close. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index b4137a678..e6c9ebb5b 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -3,7 +3,7 @@ ## Status - Version: `V30` -- V30 state: notes-only draft opening +- V30 state: draft target opened; Gate 1 converts this file from planning memory into the V30 notes companion - Current canonical/latest target: `V29` - Current active draft target: `V30` - Canonical pointer: `BITCODE_SPEC.txt` -> `V29` @@ -12,23 +12,34 @@ - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` - Generated structured artifact inventory: none for V30 yet -- Source parity state: notes-only draft opening; V30 source parity begins only after V30 first-gate work +- Source parity state: V30 source parity begins with Gate 1 roadmap/gating and then closes through Protocol/BTD package API, Bitcoin/PSBT, BTD receipt, ledger projection, source-to-shares, bridge-readiness, telemetry/proof, interface-regression, and promotion-readiness gates - Scope: future notes for Protocol/BTD hardening after V28 commercial Protocol/Terminal MVP and V29 deeper Terminal work. Exchange is deferred beyond V35. -This NOTES file does not promote V30 and does not open V30 implementation. -It preserves roadmap intent so V30 first-gate work can open from promoted V29 without rediscovering deferred Protocol/BTD hardening pressure. +This NOTES file does not promote V30. +Gate 1 opens V30 implementation discipline from promoted V29 without rediscovering deferred Protocol/BTD hardening pressure. -## Notes-only draft rule +## Notes companion rule -This file is planning memory only and is not first-gate implementation. -Requirements become binding only when V30 is explicitly opened as a full draft-target SPEC family. +This file is a required companion to `BITCODE_SPEC_V30.md`. +It may carry planning detail, QA observations, and simplified reading, but it must not override the main V30 SPEC. +Binding V30 requirements must be reflected in SPEC, DELTA, and PARITY before a gate closes. ## Concise current-system reading V29 is active canon. -V30 is expected to harden Protocol/BTD surfaces after V28/V29 reveal implementation pressure. +V30 hardens Protocol/BTD surfaces after V28/V29 revealed implementation pressure. Exchange is not V30 work. +## Simplified-spec reading rule + +For a simplified reading of V30: + +1. V29 is the current law. +2. V30 does not change `$BTD` supply, BTC fee asset, source-safe paid unlock, or the five-step Reading journey. +3. V30 makes the underlying Protocol/BTD rails more precise: packages, Bitcoin fee flow, receipts, ledger projection, source-to-shares accounting, bridge boundaries, telemetry, and proof hooks. +4. If a Protocol/BTD fact matters for money, source visibility, rights, proof, delivery, or repair, it must be typed, stored, testable, and source-safe. +5. `BITCODE_SPEC.txt` remains `V29` until V30 promotion automation advances canon. + ## Deferred from V29 V29 canonically closes deeper Terminal transaction depth, local/staging promotion readiness, and promotion automation. @@ -46,6 +57,46 @@ V30 owns Protocol/BTD hardening: - source-to-shares proof cleanup revealed by V28/V29; - Protocol/BTD-specific tests, proofs, and telemetry hooks needed before Exchange returns beyond V35. +## V30 gate plan + +1. **Gate 1: V30 Roadmap And Gating** + - Open the V30 spec family. + - Refresh `SPECIFICATIONS_ROADMAP.md` to current V29 active / V30 draft truth and V31-V37 progressive scopes. + - Wire V30 Gate 1 checks, README posture, PR title guidance, gate-quality, and canon-quality posture. + +2. **Gate 2: Protocol Package API Boundaries** + - Narrow package APIs for shared Protocol/BTD objects used by API, Terminal, MCP, ChatGPT App, and future Auxillaries/Exchange work. + - Require package-owned builders, validators, parsers, tests, and JSON-safe serialization before cross-interface use. + +3. **Gate 3: Bitcoin Taproot PSBT Fee Rigor** + - Harden BTC fee quote, signer recovery, PSBT, Taproot/script posture, broadcast, replacement, reorg, finality, and testnet/mainnet boundaries. + +4. **Gate 4: BTD AssetPack Mint And Read Receipts** + - Make BTD mint, read, and rights-transfer receipts typed, proof-rooted, stored, streamed, and source-safe. + +5. **Gate 5: Testnet Ledger Projection Hardening** + - Harden ledger/database/object-storage projection, repair, proof roots, and staging-testnet readback. + +6. **Gate 6: Source-To-Shares Proof Cleanup** + - Clean contribution measurements, settlement conservation, zero-cell/refit tail, ancestry, and no-overpayment/no-underpayment proof surfaces. + +7. **Gate 7: Bridge Readiness Research Boundaries** + - Document Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future bridge postures without admitting any as current chain-of-record truth. + +8. **Gate 8: Protocol Telemetry And Proof Hooks** + - Add typed Protocol/BTD telemetry and proof hooks needed by V32 provation, V34 deployment, and V35 documentation/observability. + +9. **Gate 9: Interface Integration And Regression Proof** + - Prove existing interfaces consume package-owned Protocol/BTD objects without regressing V29 Terminal transaction behavior. + +10. **Gate 10: V30 Promotion Readiness** + - Close local/staging proof, generated artifacts, V30 promotion workflow, and post-promotion V30 active / V31 draft posture. + +## Gate 1 working notes + +Gate 1 is complete only when the V30 family exists, validates in draft mode over active V29, and makes the roadmap truthful enough to drive V31 through V37 without stale V27/V28/V29 posture. +Gate 1 does not implement Protocol/BTD product hardening; it creates the exact gate map, checks, and documentation needed to do that hardening safely. + ## Non-goals during V30 opening V30 must not redefine `$BTD` supply, BTC fee separation, AssetPack range identity, owner-read/licensed-read law, measureminting, or ancestry. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md new file mode 100644 index 000000000..40a471e51 --- /dev/null +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -0,0 +1,102 @@ +# Bitcode Spec V30 Parity Matrix + +## Status + +- Version: `V30` +- V30 state: draft target parity matrix opened for Protocol/BTD hardening +- Current canonical/latest target: `V29` +- Prior canonical anchor: `BITCODE_SPEC_V29.md` +- Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` +- Generated structured artifact inventory: none for V30 yet; V30 gates must create and validate generated artifacts before promotion +- Source parity state: V30 parity begins with roadmap/gating, then hardens package APIs, Bitcoin/PSBT, BTD receipts, ledger projection, source-to-shares proof, bridge-readiness boundaries, telemetry/proof hooks, interface regression, and promotion readiness +- State: draft target parity matrix opened +- Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` +- Scope: V30 parity ledger for Protocol/BTD hardening over promoted V29 +- Spec companion: `BITCODE_SPEC_V30.md` +- Notes companion: `BITCODE_SPEC_V30_NOTES.md` +- Delta companion: `BITCODE_SPEC_V30_DELTA.md` +- Generated proof appendix: none until V30 promotion +- Last fully realized canonical target preserved in source: `V29` + +## Purpose + +The V30 parity matrix prevents Protocol/BTD hardening from becoming vague infrastructure work. +Each gate must name package boundaries, implementation surfaces, tests, generated/proof artifacts, documentation, accepted non-goals, and promotion evidence before it closes. + +## Audit basis + +Gate 1 audit basis: + +- `BITCODE_SPEC.txt` +- `BITCODE_SPEC_V29.md` +- `BITCODE_SPEC_V29_DELTA.md` +- `BITCODE_SPEC_V29_NOTES.md` +- `BITCODE_SPEC_V29_PARITY_MATRIX.md` +- `BITCODE_SPEC_V29_PROVEN.md` +- `BITCODE_SPEC_V30.md` +- `BITCODE_SPEC_V30_DELTA.md` +- `BITCODE_SPEC_V30_NOTES.md` +- `BITCODE_SPEC_V30_PARITY_MATRIX.md` +- `SPECIFICATIONS_ROADMAP.md` +- `README.md` +- `AGENTS.md` +- `.github/pull_request_template.md` +- `.github/workflows/bitcode-gate-quality.yml` +- `.github/workflows/bitcode-canon-quality.yml` +- `package.json` +- `packages/protocol/src/canon-posture.js` +- `protocol-demonstration/src/canon-posture.js` + +No `_legacy/` source is active source truth. + +## V30 implementation matrix + +| Area | Gate | Source evidence | Judgment | Closure requirement | +| --- | --- | --- | --- | --- | +| Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V30.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v30/gate-1-roadmap-and-gating` | drafted | V30 family validates in draft mode over active V29 and `check:v30-gate1` passes. | +| Roadmap truth | Gate 1 | `SPECIFICATIONS_ROADMAP.md`, README, PR template, workflow posture | drafted | Roadmap states V29 active, V30 draft, and coherent V31-V37 responsibilities. | +| Protocol package API boundaries | Gate 2 | `packages/protocol`, `packages/btd`, `packages/api`, package READMEs/tests | pending | Shared Protocol/BTD objects have package-owned builders, parsers, validators, JSON-safe serializers, and tests. | +| Bitcoin Taproot PSBT fee rigor | Gate 3 | BTD fee/signer/PSBT primitives, API route adapters, tests | pending | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, and proof-rooted. | +| BTD AssetPack mint/read receipts | Gate 4 | BTD receipt primitives, asset-pack postprocess, harness evidence, Terminal/API readback | pending | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | +| Testnet ledger projection hardening | Gate 5 | BTD reconciliation, Supabase readback, object-storage evidence, repair tests | pending | Ledger/database/object-storage projections are synchronized or blocked with deterministic repair posture. | +| Source-to-shares proof cleanup | Gate 6 | BTD/source-to-shares proof primitives, settlement conservation tests | pending | Measurement contribution, fee allocation, zero-cell/refit tail, and conservation invariants are testable. | +| Bridge-readiness research boundaries | Gate 7 | Protocol/BTD research notes, policy posture tests, docs | pending | Bridge paths are documented as research until admitted by explicit future proof and policy. | +| Protocol telemetry/proof hooks | Gate 8 | telemetry schema, proof hooks, generated-artifact inventory, tests | pending | Receipts, fee states, projections, and source-to-shares facts emit source-safe telemetry and proof hooks. | +| Interface integration regression | Gate 9 | Terminal/API/MCP/ChatGPT App adapters and tests | pending | Existing interfaces consume package-owned objects without regressing V29 behavior. | +| Promotion readiness | Gate 10 | V30 promotion workflow, generated `.bitcode/v30-*`, `BITCODE_SPEC_V30_PROVEN.md` | pending | `version/v30` can promote to `main` only after all V30 checks pass and promotion automation can commit generated canon. | + +## V30 implementation checklist + +| Area | Required V30 result | Judgment | +| --- | --- | --- | +| Active canon pointer | `BITCODE_SPEC.txt` remains `V29` during V30 gate work | drafted | +| Gate branch pattern | V30 work happens on `version/v30` or `v30/gate-N-*` branches | drafted | +| Spec-family shape | V30 SPEC, DELTA, NOTES, and PARITY satisfy the full spec-family checker | drafted | +| Gate 1 script | `pnpm run check:v30-gate1` fails closed on stale posture, missing roadmap truth, or missing gates | drafted | +| Gate-quality workflow | Gate workflow validates V29 active / V30 draft posture and V30 Gate 1 | drafted | +| Canon-quality workflow | Canon workflow validates V29 active / V30 draft posture and V30 draft family | drafted | + +## Gate 1 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| Active canon remains V29 during V30 draft opening | `BITCODE_SPEC.txt` contains `V29` | drafted | +| Runtime draft target is V30 | `packages/protocol/src/canon-posture.js` and `protocol-demonstration/src/canon-posture.js` declare V29 active and V30 draft | drafted | +| V30 SPEC family exists as draft | `BITCODE_SPEC_V30.md`, DELTA, NOTES, and PARITY | drafted | +| Roadmap is current | `SPECIFICATIONS_ROADMAP.md` states V29 active canon, V30 active draft target, and V31-V37 scopes | drafted | +| Gate-quality workflow is V30-aware | `.github/workflows/bitcode-gate-quality.yml` | drafted | +| Canon-quality workflow is V30-aware | `.github/workflows/bitcode-canon-quality.yml` | drafted | +| README reflects V29/V30 posture | `README.md` | drafted | +| V30 Gate 1 checker exists | `scripts/check-v30-gate1-roadmap-and-gating.mjs` and package script | drafted | + +## accepted boundaries + +- Gate 1 does not implement Protocol/BTD package hardening. +- Gate 1 does not create `BITCODE_SPEC_V30_PROVEN.md`. +- Gate 1 does not promote `BITCODE_SPEC.txt` to V30. +- Gate 1 may retarget workflows to active V29 / draft V30 so later gates are greenable. +- Gate 1 may update roadmap scope for V31-V37 to align with V28/V29 promotion learning without opening those versions. + +## completion condition + +Gate 1 is complete when the V30 draft family validates, `check:v30-gate1` passes, workflow posture is V30-aware, README and roadmap reflect V30 initiation, V31-V37 scopes are current enough to guide future gates, diff hygiene passes, and the gate branch is committed and pushed for review into `version/v30`. diff --git a/README.md b/README.md index 51346f18b..3c6022a0e 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ # Bitcode Repository `BITCODE_SPEC.txt` is the canonical pointer for active-system work. It currently -resolves to `V28`; V29 is the active draft target for deeper Terminal -transaction workflows and operator recovery. +resolves to `V29`; V30 is the active draft target for Protocol/BTD hardening +after the promoted Terminal transaction-depth canon. ## Current Product Posture @@ -13,9 +13,10 @@ The primary operator routes are: - `/auxillaries` for Wallet, Externals, Profile, and Interfaces support surfaces. Exchange and website Conversations remain in source as deferred commercial work. -V29 closure focuses on Terminal transaction depth over the promoted V28 Reading, -Finding Fits, AssetPack preview, BTC settlement, rights transfer, and delivery -canon. +V30 closure focuses on Protocol/BTD hardening over promoted V29: package API +boundaries, Bitcoin/Taproot/PSBT rigor, BTD receipts, testnet ledger projection, +source-to-shares proof cleanup, bridge-readiness boundaries, telemetry/proof +hooks, interface regression, and promotion readiness. The protocol demonstration remains the minimal deterministic reference for the same protocol. Commercial code may mount or compare against demonstration @@ -40,10 +41,10 @@ verified signatures. Use a version branch and gate-numbered branches: -1. Create one base branch per draft target, such as `version/v29`. +1. Create one base branch per draft target, such as `version/v30`. 2. Create scoped gate branches from the version branch. Prefix every gate branch - with the gate number, for example `v29/gate-1-objectives-and-gating` or - `v29/gate-6-settlement-reconciliation-repair`. + with the gate number, for example `v30/gate-1-roadmap-and-gating` or + `v30/gate-6-source-to-shares-proof-cleanup`. 3. Group related work into clear commits with quality commit messages whose titles and bodies describe the proof, implementation, or documentation change. @@ -52,7 +53,7 @@ Use a version branch and gate-numbered branches: closure review. 5. Open pull requests from gate branches into the version branch as gates close. Title gate PRs with the uppercase version and gate prefix plus a topical - title, for example `V29 Gate 5: AssetPack Disclosure Rights And Preview Depth`. + title, for example `V30 Gate 5: Testnet Ledger Projection Hardening`. 6. Open the version branch back into `main` only after all gates close and the version is formally promoted as canon. @@ -62,13 +63,15 @@ Jest suites, protocol-demonstration QA, and diff hygiene. The repository-wide canon quality workflow stays green during draft work by checking active/draft posture and promoted-spec proof posture, while full promoted-suite closure is reserved for the version promotion workflow. Version pull requests into `main` -run the version promotion workflow. For V29, promotion work must validate the -Terminal-depth proof posture, generate `BITCODE_SPEC_V29_PROVEN.md`, and commit -promotion artifacts plus the `BITCODE_SPEC.txt` pointer change from `V28` to -`V29` on the version branch. -Gate 10 is the local/staging promotion-readiness gate; run -`pnpm run check:v29-gate10` before opening the final gate PR. The V29 promotion -workflow is [v29-canon-promotion.yml](.github/workflows/v29-canon-promotion.yml). +run the version promotion workflow. For V30, promotion work must validate the +Protocol/BTD hardening proof posture, generate `BITCODE_SPEC_V30_PROVEN.md`, +and commit promotion artifacts plus the `BITCODE_SPEC.txt` pointer change from +`V29` to `V30` on the version branch. +Gate 10 is the local/staging promotion-readiness gate; run the V30 Gate 10 +checker before opening the final gate PR. V30 Gate 1 wires the first checker as +`pnpm run check:v30-gate1`. +The promoted V29 closure remains reproducible through `pnpm run check:v29-gate10` +and [v29-canon-promotion.yml](.github/workflows/v29-canon-promotion.yml). The application CI workflow uses the root pnpm workspace install, runs uapi lint/typecheck/build plus mocked Jest coverage, and keeps heavier legacy scans explicitly opt-in until their catalogs are refurbished: set @@ -79,9 +82,9 @@ or promotion validation. ## Key Surfaces - [BITCODE_SPEC.txt](BITCODE_SPEC.txt) is the canonical version pointer. -- [BITCODE_SPEC_V28.md](BITCODE_SPEC_V28.md) is the active promoted spec family. -- [BITCODE_SPEC_V29.md](BITCODE_SPEC_V29.md) is the active draft target. -- [BITCODE_SPEC_V29_PARITY_MATRIX.md](BITCODE_SPEC_V29_PARITY_MATRIX.md) tracks V29 gate parity. +- [BITCODE_SPEC_V29.md](BITCODE_SPEC_V29.md) is the active promoted spec family. +- [BITCODE_SPEC_V30.md](BITCODE_SPEC_V30.md) is the active draft target. +- [BITCODE_SPEC_V30_PARITY_MATRIX.md](BITCODE_SPEC_V30_PARITY_MATRIX.md) tracks V30 gate parity. - [uapi/README.md](uapi/README.md) documents the commercial website/API surface. - [uapi/app/terminal/README.md](uapi/app/terminal/README.md) documents Terminal. - [uapi/app/exchange/README.md](uapi/app/exchange/README.md) documents Exchange. diff --git a/SPECIFICATIONS_ROADMAP.md b/SPECIFICATIONS_ROADMAP.md index 85d3c1950..0444ffb8f 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -2,9 +2,9 @@ ## Status -- Current active canonical pointer: `BITCODE_SPEC.txt` -> `V27` -- Current active canon: `BITCODE_SPEC_V27.md` -- Current draft target: `BITCODE_SPEC_V28.md` +- Current active canonical pointer: `BITCODE_SPEC.txt` -> `V29` +- Current active canon: `BITCODE_SPEC_V29.md` +- Current draft target: `BITCODE_SPEC_V30.md` - Purpose: concise running index of Bitcode/ENGI specification history, current work, and planned work. This roadmap is not an active system specification. @@ -16,8 +16,9 @@ They are referenced here for specification history only; active implementation w ## Source Families - Legacy ENGI specifications: `_legacy/ENGI_SPEC_V1.md` through `_legacy/ENGI_SPEC_V25.md`, with companion `NOTES`, `DELTA`, `PARITY_MATRIX`, `SYSTEM_PARITY_MATRIX`, `PROVEN`, and audit files where present. -- Active Bitcode specifications: `BITCODE_SPEC_V26.md`, `BITCODE_SPEC_V27.md`, their companion `DELTA`, `NOTES`, `PARITY_MATRIX`, and `PROVEN` files. -- Draft and future Bitcode specifications: `BITCODE_SPEC_V28.md`, `BITCODE_SPEC_V28_DELTA.md`, `BITCODE_SPEC_V28_NOTES.md`, `BITCODE_SPEC_V28_PARITY_MATRIX.md`, and `BITCODE_SPEC_V29_NOTES.md` through `BITCODE_SPEC_V37_NOTES.md`. +- Active Bitcode specifications: `BITCODE_SPEC_V29.md`, with companion `DELTA`, `NOTES`, `PARITY_MATRIX`, and `PROVEN` files. +- Promoted Bitcode history: `BITCODE_SPEC_V26.md` through `BITCODE_SPEC_V28.md`, with companion `DELTA`, `NOTES`, `PARITY_MATRIX`, and `PROVEN` files. +- Draft and future Bitcode specifications: `BITCODE_SPEC_V30.md`, `BITCODE_SPEC_V30_DELTA.md`, `BITCODE_SPEC_V30_NOTES.md`, `BITCODE_SPEC_V30_PARITY_MATRIX.md`, and `BITCODE_SPEC_V31_NOTES.md` through `BITCODE_SPEC_V37_NOTES.md`. - Specification discipline references: `BITCODE_SPECIFYING.md` and `BITCODE_SPEC_TEMPLATEGUIDE.md`. ## Roadmap @@ -50,13 +51,13 @@ They are referenced here for specification history only; active implementation w | V24 | `_legacy/ENGI_SPEC_V24.md` | historical | External realization: moves modeled Bitcoin, sidechain, compute, storage, and GitHub interfaces toward real typed execution receipts, exhaustive telemetry, live adapter contracts, and full-canon conformance repair. | | V25 | `_legacy/ENGI_SPEC_V25.md` | historical | Rename canon: full project rename from ENGI to Bitcode and NGI to BTD while preserving V24 behavior, proof obligations, settlement, disclosure, fail-closed posture, generated evidence, and runtime/API/site alignment. | | V26 | `BITCODE_SPEC_V26.md` | promoted historical Bitcode canon | First commercial Bitcode promotion: productionizing hardening, demonstration-to-application integration, app-native UI replacement, package-first refurbishment, retained-system purification, Exchange/Terminal minimum functionality, MVP elevation, commercial testnet readiness, and whole-repository provation. | -| V27 | `BITCODE_SPEC_V27.md` | active canon | `$BTD` tokenomics and practical cryptotechnological commercialization: 21,000,000 non-fungible source-share cells, AssetPack ranges, Read-Fit-Prove-Settle mint admission, measureminting decay, zero-cell/refit tail receipts, BTC fee separation, wallet/PSBT paths, ledgerized anchors, minimal AssetPack Exchange, Terminal journals, reconciliation, telemetry, upgrades, access rights, revenue, and optional evidence-based ancestry. | -| V28 | `BITCODE_SPEC_V28.md` | active draft target | Commercial Protocol implementation and Terminal MVP over V27: Terminal readiness over wallet/BTC/Read-Fit-measuremint primitives, realistic testnet BTD-AssetPack minting, synthetic measurements journaled and ledgerized, BTD range disclosure, read-right state, journal/reconciliation readability, MCP API and ChatGPT App MVP, Auxillaries contained readiness cleanup, removal of commercial runtime dependencies on `protocol-demonstration/`, and unversioned route discipline. Exchange and website Conversations are deferred beyond V35. | -| V29 | `BITCODE_SPEC_V29_NOTES.md` | future notes | Deeper Terminal: full Read/Fit/proof/dedupe/measuremint/settlement workflows, wallet recovery, BTC fee lifecycle depth, AssetPack range/read-right reviews, journal diffing, reconciliation repair, organization permissions, and Terminal-specific UI/test coverage. | -| V30 | `BITCODE_SPEC_V30_NOTES.md` | future notes | Protocol/BTD hardening after V28/V29: follow-up package extraction, Bitcoin/Taproot/PSBT rigor, BTD-AssetPack mint/read receipts, testnet ledger/projection hardening, bridge-readiness research notes, and source-to-shares proof cleanup. Exchange is not V30. | -| V31 | `BITCODE_SPEC_V31_NOTES.md` | future notes | Deeper Auxillaries: profile, connects, interfaces, BTD panes, provider readiness, account state, team/org/wallet/multi-sig/role/policy controls, readiness diagnostics, recovery flows, responsive/accessibility QA, and Auxillaries-specific tests/proofs. | -| V32 | `BITCODE_SPEC_V32_NOTES.md` | future notes | Deeper provation and testing: broader proof-family replay across Terminal, Exchange, Auxillaries, BTD registry, and protocol-demonstration; E2E/failure-state breadth, regression suites, promotion-proof generation hardening, scenario expansion, visual/accessibility/responsive tests, and testnet/mainnet-readiness rehearsal. | -| V33 | `BITCODE_SPEC_V33_NOTES.md` | future notes | Deeper Interfaces beyond V28 MVP: mature MCP API, ChatGPT App, API packaging, schemas, examples, contract tests, interface auth, policy checks, fail-closed read/license behavior, and commercial non-Auxillaries non-website application interfaces. | +| V27 | `BITCODE_SPEC_V27.md` | promoted historical Bitcode canon | `$BTD` tokenomics and practical cryptotechnological commercialization: 21,000,000 non-fungible source-share cells, AssetPack ranges, Read-Fit-Prove-Settle mint admission, measureminting decay, zero-cell/refit tail receipts, BTC fee separation, wallet/PSBT paths, ledgerized anchors, Terminal journals, reconciliation, telemetry, upgrades, access rights, revenue, and optional evidence-based ancestry. | +| V28 | `BITCODE_SPEC_V28.md` | promoted historical Bitcode canon | Commercial Protocol implementation and Terminal MVP: Depositing, Read Request, Read-Need Comprehension, Finding Fits, source-safe AssetPack preview, settlement posture, BTD range/read-right state, PR delivery, streaming pipeline telemetry, staging-testnet harnesses, MCP/ChatGPT App MVP, demonstration boundary cleanup, and unversioned route discipline. | +| V29 | `BITCODE_SPEC_V29.md` | active canon | Deeper Terminal transaction cockpit: route-owned transaction state, Wallet/BTC operation depth, Reading pipeline observability, AssetPack disclosure rights, settlement reconciliation/repair, organization permission authority, browser-proven Terminal UX, local/staging promotion readiness, and V29 canonical promotion. | +| V30 | `BITCODE_SPEC_V30.md` | active draft target | Protocol/BTD hardening after V28/V29: package API boundaries, Bitcoin/Taproot/PSBT rigor, BTD-AssetPack mint/read/right-transfer receipts, testnet ledger/database/object-storage projection hardening, source-to-shares proof cleanup, bridge-readiness research boundaries, Protocol/BTD telemetry/proof hooks, interface regression proof, and V30 promotion readiness. Exchange is not V30. | +| V31 | `BITCODE_SPEC_V31_NOTES.md` | future notes | Deeper Auxillaries after Protocol/BTD rails stabilize: profile, connects, interfaces, BTD panes, provider readiness, account state, team/org/wallet/multi-sig/role/policy controls, readiness diagnostics, recovery flows, responsive/accessibility QA, and Auxillaries-specific tests/proofs. | +| V32 | `BITCODE_SPEC_V32_NOTES.md` | future notes | Deeper provation and testing over stable Terminal and Protocol/BTD rails: proof-family replay across Terminal, Exchange placeholders, Auxillaries, BTD registry, and protocol-demonstration; E2E/failure-state breadth, regression suites, promotion-proof generation hardening, scenario expansion, visual/accessibility/responsive tests, and testnet/mainnet-readiness rehearsal. | +| V33 | `BITCODE_SPEC_V33_NOTES.md` | future notes | Deeper Interfaces beyond the V28 MVP: mature MCP API, ChatGPT App, API packaging, schemas, examples, contract tests, interface auth, policy checks, fail-closed read/license behavior, and commercial non-Auxillaries non-website application interfaces using package-owned Protocol/BTD objects. | | V34 | `BITCODE_SPEC_V34_NOTES.md` | future notes | Deeper Deployment: host capabilities, real executions, distributed compute aligned with provations, runtime/storage expectations, ledger/database/object-storage/proof-artifact posture, CI/CD for canonical promotions, environment lanes, deployment approvals, rollback, upgrades, secret rotation, and repair playbooks. | | V35 | `BITCODE_SPEC_V35_NOTES.md` | future notes | Deeper telemetry and documenting: internal codebase docs, public `/docs`, telemetry taxonomy, dashboards, alert runbooks, incident response, operator escalation, documentation QA across code/spec/proofs/deployments, developer onboarding, operator guides, and testnet-rollout readiness material. | | V36 | `BITCODE_SPEC_V36_NOTES.md` | future notes | Deeper Exchange after V35: Exchange MVP/deepening, market-wide activity master-detail, buy/sell/bid/ask/cancel/accept/settle/history flows, AssetPack range trading, rights-transfer review, liquidity/wrapper analysis, dispute/repair/revenue-route operations, and Exchange-specific tests/proofs. | @@ -64,20 +65,22 @@ They are referenced here for specification history only; active implementation w ## Current Planning Spine -1. V26 converted the renamed repository into commercial Bitcode: package-owned, app-owned, proof-bearing, MVP-ready enough for V27 tokenomics. +1. V26 converted the renamed repository into commercial Bitcode: package-owned, app-owned, proof-bearing, and MVP-ready enough for V27 tokenomics. 2. V27 made `$BTD` and practical crypto rails exact enough to serve as active law. -3. V28 must harden the commercial Protocol implementation and Terminal MVP so V27 law is usable by operators without fighting visual, route, readiness, wallet/BTC/testnet, MCP, ChatGPT App, or demonstration-boundary defects. -4. V29 through V31 deepen Terminal, Protocol/BTD hardening, and Auxillaries in order. -5. V32 deepens provation and testing after those surfaces are stable enough to prove. -6. V33 deepens commercial interfaces outside the website/Auxillaries frame beyond the V28 MCP API and ChatGPT App MVP. -7. V34 makes deployment, host capability, distributed execution, storage, CI/CD, and promotion operations robust enough for testnet-facing reality. -8. V35 deepens telemetry and documentation as the prelude to full commercial application testnet rollout. -9. V36+ returns to deferred Exchange and website Conversations after the Protocol/Terminal/interface/deployment/documentation spine is mature. +3. V28 promoted the first commercial Reading implementation and Terminal MVP: Depositing, Read-Need Comprehension, Finding Fits, AssetPack preview, settlement posture, delivery, staging-testnet harnessing, and demonstration-boundary discipline. +4. V29 promoted the deeper Terminal transaction cockpit: recoverable transaction routes, Wallet/BTC operation detail, Reading observability, disclosure rights, reconciliation repair, organization authority, browser-proof UX, and promotion readiness. +5. V30 is the current draft target and hardens Protocol/BTD rails beneath V28/V29: packages, Bitcoin/PSBT, receipts, ledger projection, source-to-shares, bridge-readiness boundaries, telemetry/proof hooks, interface regression, and promotion readiness. +6. V31 deepens Auxillaries after Protocol/BTD objects are stable enough for account, wallet, provider, team, role, and policy support surfaces. +7. V32 deepens provation and testing after Terminal, Protocol/BTD, and Auxillaries are stable enough to prove broadly. +8. V33 deepens commercial interfaces outside the website/Auxillaries frame beyond the V28 MCP API and ChatGPT App MVP. +9. V34 makes deployment, host capability, distributed execution, storage, CI/CD, and promotion operations robust enough for testnet-facing reality. +10. V35 deepens telemetry and documentation as the prelude to full commercial application testnet rollout. +11. V36+ returns to deferred Exchange and website Conversations after the Protocol/Terminal/Auxillaries/interface/deployment/documentation spine is mature. ## Boundary Rules - Do not treat `_legacy/` ENGI specifications as active implementation authority. - Do use `_legacy/` specifications to understand why current Bitcode concepts exist and what must not regress. -- V28+ work must build on V27 `$BTD` law unless a future promoted spec explicitly supersedes it. +- V30+ work must build on V29 active canon and V27 `$BTD` law unless a future promoted spec explicitly supersedes it. - No implementation route should be versioned by spec number; source should move in place with the active canon. - Future notes files are planning memory only until their version is explicitly opened as the draft-target SPEC family. diff --git a/package.json b/package.json index 55a10fdca..8aa289117 100644 --- a/package.json +++ b/package.json @@ -54,6 +54,7 @@ "check:v29-gate8": "node scripts/check-v29-gate8-demonstration-origin-formalization.mjs", "check:v29-gate9": "node scripts/check-v29-gate9-terminal-ux-browser-proof.mjs", "check:v29-gate10": "node scripts/check-v29-gate10-local-staging-promotion-readiness.mjs", + "check:v30-gate1": "node scripts/check-v30-gate1-roadmap-and-gating.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/protocol/README.md b/packages/protocol/README.md index e657fbe70..40d84ff19 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -2,7 +2,7 @@ Formal Bitcode protocol package for commercial source. -V29 Gate 8 makes this package the package-native boundary for canonical helpers +V29 Gate 8 made this package the package-native boundary for canonical helpers that were originally ported from the standalone `protocol-demonstration` witness. Commercial scripts, API/runtime code, and workflow checks must import canon posture, spec-family checks, canonical-input checks, canon-drift checks, @@ -15,15 +15,17 @@ inventories, but it is not a commercial runtime implementation dependency. Current exported commercial helpers include: -- active/draft canon posture (`V29` active, `V30` draft after V29 promotion); +- active/draft canon posture (`V29` active, `V30` draft); - spec-family and canonical-input validation helpers; - canon-posture drift reporting; - canonical proven-generation helpers; - the package app/server context used by commercial interfaces. -V29 Gate 10 treats this package as promotion-critical runtime posture. +This is the `V29` active, `V30` draft after V29 promotion posture accepted by +V29 Gate 10. +V30 Gate 1 treats this package as promotion-critical runtime posture. `packages/protocol/src/canon-posture.js` and `packages/protocol/data/state.json` -must remain aligned to `V29` active, `V30` draft after promotion. +must remain aligned to `V29` active, `V30` draft until V30 promotion. The package boundary is enforced by `packages/protocol` tests, the UAPI -commercial protocol boundary test, and `check:v29-gate8`. +commercial protocol boundary test, and V30 gate checks. diff --git a/protocol-demonstration/README.md b/protocol-demonstration/README.md index 58093ac4b..71abc228f 100644 --- a/protocol-demonstration/README.md +++ b/protocol-demonstration/README.md @@ -4,9 +4,11 @@ This package is the deterministic demonstration of Bitcode. Within this package the correct name is demonstration. `BITCODE_SPEC.txt` is the canonical pointer for active-system work. It currently -resolves to `V28`; V29 is the next draft target after this promotion. -`BITCODE_SPEC.txt -> V29`. This demo is governed by the active V29 canonical -spec and `BITCODE_SPEC_V29_PROVEN.md` as the current generated appendix. +resolves to `V29`; V30 is the active draft target for Protocol/BTD hardening. +`BITCODE_SPEC.txt -> V29`. +This demo is governed by the active V29 canonical spec and +`BITCODE_SPEC_V29_PROVEN.md` as the current generated appendix while V30 draft +work proceeds outside the demonstration runtime boundary. ## What This Demonstration Carries diff --git a/scripts/check-v30-gate1-roadmap-and-gating.mjs b/scripts/check-v30-gate1-roadmap-and-gating.mjs new file mode 100644 index 000000000..b9112532e --- /dev/null +++ b/scripts/check-v30-gate1-roadmap-and-gating.mjs @@ -0,0 +1,216 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function hasSection(content, sectionHeading) { + const escaped = sectionHeading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + return new RegExp(`^#{2,6}\\s+${escaped}\\s*$`, 'm').test(content); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate1-roadmap-and-gating.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 1 roadmap, draft-family, branch, workflow, docs, and active/draft posture readiness.' + ].join('\n') + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.` + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-\d+-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 work must occur on version/v30 or v30/gate-N-* branches. Observed ${branch || 'detached HEAD'}.` + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + 'BITCODE_SPECIFYING.md', + 'BITCODE_SPEC_TEMPLATEGUIDE.md', + 'SPECIFICATIONS_ROADMAP.md', + '.github/workflows/bitcode-gate-quality.yml', + '.github/workflows/bitcode-canon-quality.yml', + '.github/pull_request_template.md', + 'README.md', + 'AGENTS.md', + 'packages/protocol/src/canon-posture.js', + 'protocol-demonstration/src/canon-posture.js' + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing required V30 Gate 1 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const roadmap = read(root, 'SPECIFICATIONS_ROADMAP.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + const canonWorkflow = read(root, '.github/workflows/bitcode-canon-quality.yml'); + const prTemplate = read(root, '.github/pull_request_template.md'); + const readme = read(root, 'README.md'); + const protocolReadme = read(root, 'packages/protocol/README.md'); + const demoReadme = read(root, 'protocol-demonstration/README.md'); + const packagePosture = read(root, 'packages/protocol/src/canon-posture.js'); + const demoPosture = read(root, 'protocol-demonstration/src/canon-posture.js'); + + for (const [label, content] of [ + ['V30 SPEC', spec], + ['V30 DELTA', delta], + ['V30 NOTES', notes], + ['V30 PARITY', parity] + ]) { + assertCheck( + failures, + content.includes('Current canonical/latest target: `V29`'), + `${label} must declare V29 as current canonical/latest target.` + ); + } + + assertCheck(failures, spec.includes('Protocol/BTD hardening'), 'V30 SPEC must define Protocol/BTD hardening scope.'); + assertCheck(failures, spec.includes('BtdAssetPackMintReceipt'), 'V30 SPEC must name BTD AssetPack mint receipts.'); + assertCheck(failures, spec.includes('SourceToSharesProof'), 'V30 SPEC must name source-to-shares proof cleanup.'); + assertCheck(failures, spec.includes('BridgeReadinessResearchPosture'), 'V30 SPEC must name bridge-readiness research posture.'); + assertCheck(failures, delta.includes('Gate 1: V30 Roadmap And Gating'), 'V30 DELTA must define Gate 1.'); + assertCheck(failures, notes.includes('V30 gate plan'), 'V30 NOTES must carry the V30 gate plan.'); + assertCheck(failures, parity.includes('## Gate 1 Parity'), 'V30 PARITY must include Gate 1 parity.'); + assertCheck(failures, parity.includes('V30 implementation matrix'), 'V30 PARITY must include the implementation matrix.'); + assertCheck(failures, parity.includes('completion condition'), 'V30 PARITY must include a completion condition.'); + + for (const gate of [ + 'Gate 1: V30 Roadmap And Gating', + 'Gate 2: Protocol Package API Boundaries', + 'Gate 3: Bitcoin Taproot PSBT Fee Rigor', + 'Gate 4: BTD AssetPack Mint And Read Receipts', + 'Gate 5: Testnet Ledger Projection Hardening', + 'Gate 6: Source-To-Shares Proof Cleanup', + 'Gate 7: Bridge Readiness Research Boundaries', + 'Gate 8: Protocol Telemetry And Proof Hooks', + 'Gate 9: Interface Integration And Regression Proof', + 'Gate 10: V30 Promotion Readiness' + ]) { + assertCheck(failures, delta.includes(gate) || notes.includes(gate), `V30 gate plan is missing ${gate}.`); + } + + assertCheck(failures, hasSection(notes, 'Notes companion rule'), 'V30 NOTES must be a notes companion, not notes-only planning memory.'); + assertCheck(failures, hasSection(notes, 'Simplified-spec reading rule'), 'V30 NOTES must carry the simplified-spec reading rule.'); + + assertCheck(failures, roadmap.includes('Current active canonical pointer: `BITCODE_SPEC.txt` -> `V29`'), 'Roadmap must state V29 as active pointer.'); + assertCheck(failures, roadmap.includes('Current draft target: `BITCODE_SPEC_V30.md`'), 'Roadmap must state V30 as active draft target.'); + assertCheck(failures, roadmap.includes('| V29 | `BITCODE_SPEC_V29.md` | active canon |'), 'Roadmap must mark V29 active canon.'); + assertCheck(failures, roadmap.includes('| V30 | `BITCODE_SPEC_V30.md` | active draft target |'), 'Roadmap must mark V30 active draft target.'); + for (const version of ['V31', 'V32', 'V33', 'V34', 'V35', 'V36', 'V37']) { + assertCheck(failures, roadmap.includes(`| ${version} |`), `Roadmap must preserve ${version} scope.`); + } + + assertCheck(failures, packageJson.includes('"check:v30-gate1"'), 'package.json must expose check:v30-gate1.'); + assertCheck(failures, gateWorkflow.includes('check-v30-gate1-roadmap-and-gating.mjs'), 'Gate workflow must run the V30 Gate 1 checker.'); + assertCheck(failures, gateWorkflow.includes('--version V30 --mode draft --current-target V29'), 'Gate workflow must validate V30 draft spec over V29.'); + assertCheck(failures, gateWorkflow.includes('--active-canon V29 --draft-target V30'), 'Gate workflow must validate V29/V30 canon posture.'); + assertCheck(failures, canonWorkflow.includes('--version V30 --mode draft --current-target V29'), 'Canon workflow must validate V30 draft family.'); + assertCheck(failures, canonWorkflow.includes('--active-canon V29 --draft-target V30'), 'Canon workflow must validate V29/V30 canon posture.'); + + assertCheck(failures, readme.includes('resolves to `V29`; V30 is the active draft target'), 'README must state V29 active / V30 draft posture.'); + assertCheck(failures, readme.includes('version/v30'), 'README must document the version/v30 branch workflow.'); + assertCheck(failures, readme.includes('v30/gate-1-roadmap-and-gating'), 'README must document a V30 gate branch example.'); + assertCheck(failures, prTemplate.includes('V30 Gate N:'), 'PR template must show V30 gate title format.'); + assertCheck(failures, protocolReadme.includes('V29` active, `V30` draft'), 'Protocol README must state V29/V30 posture.'); + assertCheck(failures, demoReadme.includes('resolves to `V29`; V30 is the active draft target'), 'Demonstration README must state V29/V30 posture.'); + + for (const [label, content] of [ + ['commercial protocol package', packagePosture], + ['standalone demonstration', demoPosture] + ]) { + assertCheck(failures, content.includes("ACTIVE_CANON_VERSION = 'V29'"), `${label} must keep V29 active.`); + assertCheck(failures, content.includes("DRAFT_TARGET_VERSION = 'V30'"), `${label} must declare V30 draft target.`); + } + + const routeScan = execFileSync('find', ['uapi/app/api', '-path', '*v[0-9]*', '-print'], { + cwd: root, + encoding: 'utf8' + }).trim(); + assertCheck(failures, routeScan.length === 0, `UAPI API routes must remain unversioned. Found:\n${routeScan}`); + + if (failures.length > 0) { + process.stderr.write('V30 Gate 1 roadmap and gating check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write(`V30 Gate 1 roadmap and gating ok pointer=${pointer}\n`); +} + +try { + main(); +} catch (error) { + const detail = error instanceof Error ? error.message : String(error); + process.stderr.write(`${detail}\n`); + process.exitCode = 1; +} From b452e2aca97c3f5ae6a13688038323665f9f03b3 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 17:10:55 -0300 Subject: [PATCH 02/15] V30 Gate 2: Package BTD API boundaries Move shared BTD route-facing builders, parsers, settlement constructors, registry snapshots, and JSON-safe serialization into @bitcode/btd so API routes delegate protocol policy instead of owning it. Add package boundary tests, update route tests to import package builders directly, document accepted import direction, and wire the V30 Gate 2 checker into gate-quality. --- .github/workflows/bitcode-gate-quality.yml | 1 + BITCODE_SPEC_V30_DELTA.md | 12 + BITCODE_SPEC_V30_NOTES.md | 19 + BITCODE_SPEC_V30_PARITY_MATRIX.md | 21 +- README.md | 6 +- package.json | 1 + packages/api/README.md | 8 + .../src/routes/__tests__/btd-crypto.test.ts | 16 +- packages/api/src/routes/btd-crypto.ts | 1573 +--------------- packages/btd/README.md | 12 + packages/btd/__tests__/api-boundaries.test.ts | 122 ++ packages/btd/src/api-boundaries.ts | 1575 +++++++++++++++++ packages/btd/src/index.ts | 1 + ...-gate2-protocol-package-api-boundaries.mjs | 236 +++ 14 files changed, 2088 insertions(+), 1515 deletions(-) create mode 100644 packages/btd/__tests__/api-boundaries.test.ts create mode 100644 packages/btd/src/api-boundaries.ts create mode 100644 scripts/check-v30-gate2-protocol-package-api-boundaries.mjs diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index a2735fe28..86736a6d7 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -80,6 +80,7 @@ jobs: node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V29 --draft-target V30 node scripts/check-v29-gate10-local-staging-promotion-readiness.mjs --promotion-mode --skip-branch-check node scripts/check-v30-gate1-roadmap-and-gating.mjs --skip-branch-check + node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 65dbc3eb8..09f9a3010 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -93,6 +93,18 @@ Closure acceptance: - no commercial runtime code imports `protocol-demonstration/src/*`; - package READMEs name ownership boundaries and accepted imports. +Gate 2 implementation centers the currently shared BTD route objects in +`packages/btd/src/api-boundaries.ts`. API routes may authenticate, parse request +bodies, resolve registry projections, commit explicit persistence writes, and +serialize responses, but BTD mint drafts, registry snapshots, read-access +decisions, BTC-fee settlements, ledger anchors, Exchange settlements, Terminal +journal settlements, reconciliation settlements, deployment-readiness receipts, +BigInt parsing, and JSON-safe conversion are package-owned. + +The package boundary is proven by `packages/btd/__tests__/api-boundaries.test.ts`, +`packages/api/src/routes/__tests__/btd-crypto.test.ts`, and +`scripts/check-v30-gate2-protocol-package-api-boundaries.mjs`. + ### Gate 3: Bitcoin Taproot PSBT Fee Rigor Gate 3 hardens Bitcoin fee and signer semantics. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index e6c9ebb5b..994b27279 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -68,6 +68,25 @@ V30 owns Protocol/BTD hardening: - Narrow package APIs for shared Protocol/BTD objects used by API, Terminal, MCP, ChatGPT App, and future Auxillaries/Exchange work. - Require package-owned builders, validators, parsers, tests, and JSON-safe serialization before cross-interface use. +## Gate 2 protocol package API boundary notes + +Gate 2 moves reusable BTD route-facing construction into +`packages/btd/src/api-boundaries.ts`. `packages/api/src/routes/btd-crypto.ts` +remains the route owner: it authenticates requests, parses request bodies, +resolves registry projections, commits explicit persistence writes, and returns +JSON responses. It no longer owns BTD mint draft admission, registry snapshot +construction, read-access policy derivation, BTC-fee settlement receipts, +AssetPack ledger anchors, Exchange settlement receipts, Terminal journal +settlements, reconciliation reports, deployment-readiness receipts, BigInt +parsing, or JSON-safe conversion. + +The package test `packages/btd/__tests__/api-boundaries.test.ts` is the local +contract for package-owned builders/parsers/serialization. The API route test +imports those builders from `@bitcode/btd` and keeps route-handler coverage in +the API package. `pnpm run check:v30-gate2` closes the gate by checking this +seam, package README ownership language, and commercial runtime avoidance of +standalone demonstration imports. + 3. **Gate 3: Bitcoin Taproot PSBT Fee Rigor** - Harden BTC fee quote, signer recovery, PSBT, Taproot/script posture, broadcast, replacement, reorg, finality, and testnet/mainnet boundaries. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index 40a471e51..091db6b1f 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -55,7 +55,7 @@ No `_legacy/` source is active source truth. | --- | --- | --- | --- | --- | | Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V30.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v30/gate-1-roadmap-and-gating` | drafted | V30 family validates in draft mode over active V29 and `check:v30-gate1` passes. | | Roadmap truth | Gate 1 | `SPECIFICATIONS_ROADMAP.md`, README, PR template, workflow posture | drafted | Roadmap states V29 active, V30 draft, and coherent V31-V37 responsibilities. | -| Protocol package API boundaries | Gate 2 | `packages/protocol`, `packages/btd`, `packages/api`, package READMEs/tests | pending | Shared Protocol/BTD objects have package-owned builders, parsers, validators, JSON-safe serializers, and tests. | +| Protocol package API boundaries | Gate 2 | `packages/btd/src/api-boundaries.ts`, `packages/api/src/routes/btd-crypto.ts`, package READMEs/tests | drafted | Shared Protocol/BTD objects have package-owned builders, parsers, validators, JSON-safe serializers, and tests. | | Bitcoin Taproot PSBT fee rigor | Gate 3 | BTD fee/signer/PSBT primitives, API route adapters, tests | pending | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, and proof-rooted. | | BTD AssetPack mint/read receipts | Gate 4 | BTD receipt primitives, asset-pack postprocess, harness evidence, Terminal/API readback | pending | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | | Testnet ledger projection hardening | Gate 5 | BTD reconciliation, Supabase readback, object-storage evidence, repair tests | pending | Ledger/database/object-storage projections are synchronized or blocked with deterministic repair posture. | @@ -93,6 +93,25 @@ No `_legacy/` source is active source truth. - Gate 1 does not implement Protocol/BTD package hardening. - Gate 1 does not create `BITCODE_SPEC_V30_PROVEN.md`. + +## Gate 2 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| Package-owned BTD builders and parsers exist | `packages/btd/src/api-boundaries.ts` exports mint, registry, read-access, fee, ledger-anchor, Exchange, journal, reconciliation, deployment-readiness builders plus `parseBtdRequiredBigInt`, `parseBtdOptionalBigInt`, and `toBtdJsonSafe` | drafted | +| API route delegates BTD policy and receipt derivation | `packages/api/src/routes/btd-crypto.ts` imports package builders from `@bitcode/btd` and keeps route code scoped to auth, request parsing, registry projection reads/writes, and responses | drafted | +| Package tests cover the boundary | `packages/btd/__tests__/api-boundaries.test.ts` proves mint drafts, registry snapshots, read-access decisions, parsers, and JSON-safe serialization | drafted | +| Route tests consume package-owned builders | `packages/api/src/routes/__tests__/btd-crypto.test.ts` imports BTD builders from `@bitcode/btd` and route handlers from the API route module | drafted | +| Commercial runtime avoids standalone demonstration imports | `scripts/check-v30-gate2-protocol-package-api-boundaries.mjs` scans runtime source import statements for `protocol-demonstration/src` and `@bitcode/protocol-demonstration` | drafted | +| Package READMEs state accepted imports | `packages/btd/README.md`, `packages/api/README.md`, and `packages/protocol/README.md` name package ownership and accepted import direction | drafted | +| Gate checker protects the seam | `pnpm run check:v30-gate2` and gate-quality workflow call `scripts/check-v30-gate2-protocol-package-api-boundaries.mjs` | drafted | + +## Gate 2 accepted boundaries + +- Gate 2 does not change the active canon pointer. +- Gate 2 does not introduce bridge chain-of-record behavior. +- Gate 2 does not admit value-bearing mainnet settlement. +- Gate 2 does not remove existing API route persistence adapters; it narrows their policy and receipt derivation responsibilities to package calls. - Gate 1 does not promote `BITCODE_SPEC.txt` to V30. - Gate 1 may retarget workflows to active V29 / draft V30 so later gates are greenable. - Gate 1 may update roadmap scope for V31-V37 to align with V28/V29 promotion learning without opening those versions. diff --git a/README.md b/README.md index 3c6022a0e..235a12f5e 100644 --- a/README.md +++ b/README.md @@ -69,7 +69,11 @@ and commit promotion artifacts plus the `BITCODE_SPEC.txt` pointer change from `V29` to `V30` on the version branch. Gate 10 is the local/staging promotion-readiness gate; run the V30 Gate 10 checker before opening the final gate PR. V30 Gate 1 wires the first checker as -`pnpm run check:v30-gate1`. +`pnpm run check:v30-gate1`. V30 Gate 2 wires the Protocol/BTD package boundary +checker as `pnpm run check:v30-gate2`; shared BTD objects consumed by API, +Terminal, MCP, ChatGPT App, Auxillaries, or Exchange must be built, parsed, +validated, and JSON-serialized by package owners before route or interface code +uses them. The promoted V29 closure remains reproducible through `pnpm run check:v29-gate10` and [v29-canon-promotion.yml](.github/workflows/v29-canon-promotion.yml). The application CI workflow uses the root pnpm workspace install, runs uapi diff --git a/package.json b/package.json index 8aa289117..dfa971654 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "check:v29-gate9": "node scripts/check-v29-gate9-terminal-ux-browser-proof.mjs", "check:v29-gate10": "node scripts/check-v29-gate10-local-staging-promotion-readiness.mjs", "check:v30-gate1": "node scripts/check-v30-gate1-roadmap-and-gating.mjs", + "check:v30-gate2": "node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/api/README.md b/packages/api/README.md index 48c60d674..f06b3750d 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -6,6 +6,14 @@ Unified Bitcode API orchestration layer. This package owns route-level request l Interface-owned route bindings such as `uapi/app/api/*` should stay thin. They import formal route handlers from `packages/api` entry modules such as `@bitcode/api/src/routes/*`, while those handlers import narrower functionality from the appropriate subsystem packages. +For BTD routes, the accepted import direction is route code importing +package-owned builders, parsers, validators, and JSON serializers from +`@bitcode/btd`. The route-owned behavior is limited to authentication, request body +parsing, registry projection reads, explicit persistence commits, response +status decisions, and framework-compatible response serialization. Route code +must not duplicate BTD policy, mint admission, receipt derivation, settlement +state construction, or JSON-safe conversion already exported by `@bitcode/btd`. + In V26 fourth-gate this package is where merged-world Bitcode becomes concrete: - `/conversations` continuity - `/executions` compatibility and pipeline-run APIs diff --git a/packages/api/src/routes/__tests__/btd-crypto.test.ts b/packages/api/src/routes/__tests__/btd-crypto.test.ts index 8be25a2c5..ad928c2ec 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -14,6 +14,7 @@ jest.mock( ); import { + advanceBtcFeeQuote, buildBtdAncestryReviewSettlement, buildBtdAssetPackLedgerAnchorSettlement, buildBtdAssetPackExchangeSettlement, @@ -25,6 +26,10 @@ import { buildBtdOrganizationInterfaceAuthorityDecision, buildBtdReadAccessDecision, buildBtdTerminalJournalSettlement, + buildBtcFeeQuote, + createBtdMeasureMintState, +} from '@bitcode/btd'; +import { buildGetBtdRegistrySnapshotRoute, buildPostBtdAncestryReviewRoute, buildPostBtdAssetPackLedgerAnchorRoute, @@ -38,11 +43,6 @@ import { buildPostBtdReadAccessRoute, buildPostBtdTerminalJournalRoute, } from '../btd-crypto'; -import { - advanceBtcFeeQuote, - buildBtcFeeQuote, - createBtdMeasureMintState, -} from '@bitcode/btd'; const issuedAt = '2026-05-06T00:00:00.000Z'; @@ -215,7 +215,7 @@ describe('BTD crypto API builders', () => { const body = await response.json(); expect(response.status).toBe(400); - expect(body.error).toBe('V27 BTD mint draft requires accepted Read.'); + expect(body.error).toBe('BTD mint draft requires accepted Read.'); }); it('fails mint drafts closed when Fit admission is absent', async () => { @@ -231,7 +231,7 @@ describe('BTD crypto API builders', () => { const body = await response.json(); expect(response.status).toBe(400); - expect(body.error).toBe('V27 BTD mint draft requires accepted Fit.'); + expect(body.error).toBe('BTD mint draft requires accepted Finding Fits result.'); }); it('fails mint drafts closed when uncommitted proof inputs are missing', async () => { @@ -263,7 +263,7 @@ describe('BTD crypto API builders', () => { const body = await response.json(); expect(response.status).toBe(400); - expect(body.error).toBe('V27 BTD mint draft requires a positive Exchange sequence.'); + expect(body.error).toBe('BTD mint draft requires a positive Exchange sequence.'); }); it('builds read-access decisions without merging owner-read and licensed-read rights', () => { diff --git a/packages/api/src/routes/btd-crypto.ts b/packages/api/src/routes/btd-crypto.ts index 7a65ced3f..512f6ae99 100644 --- a/packages/api/src/routes/btd-crypto.ts +++ b/packages/api/src/routes/btd-crypto.ts @@ -1,89 +1,75 @@ -import { createHash } from 'crypto'; import { traceRoute } from '@bitcode/observability'; import { createAdminClient, type BtdRegistryModel } from '@bitcode/orm'; import { createClient } from '@bitcode/supabase/ssr/server'; import { createJsonResponse } from '@bitcode/responses'; import { - BTD_MAX_MINTABLE_SUPPLY, - type BitcoinNetwork, - type BtdAncestorEdgeInput, - type BtdAncestorGraphEdge, - type BtdAccessPolicy, - type BtdContributorMeasure, - type BtdMeasureMintState, - type BtdOwnershipClaim, - type BtdReadLicense, - type BtdInterfaceAuthoritySurface, - type BtdOrganizationPermissionAction, - type BtdOrganizationRole, - type BtdRepairApprovalState, - type BtdRevenueRecipientInput, - type BtdRevenueRouteException, - type BtdSettlementAuthorityState, - type BtdProtocolUpgradeReceipt, - type BtdProtocolUpgradeState, - type AssetPackLedgerAnchor, type AssetPackExchangeOrder, - type AssetPackExchangeOrderKind, + type AssetPackLedgerAnchor, type AssetPackRightsTransferReceipt, - type BtcFeeFinalityState, - type BtcFeeOperationPosture, - type DatabaseProjectedFact, - type BtcFeePurpose, - type BtcFeeQuote, + type BtdAccessPolicy, + type BtdAncestryReviewInput, + type BtdAncestryReviewSettlement, + type BtdAssetPackExchangeInput, + type BtdAssetPackExchangeSettlement, + type BtdAssetPackLedgerAnchorInput, + type BtdAssetPackLedgerAnchorSettlement, + type BtdBtcFeeTransactionInput, + type BtdBtcFeeTransactionSettlement, + type BtdDeploymentReadinessInput, + type BtdDeploymentReadinessSettlement, + type BtdLedgerDatabaseReconciliationInput, + type BtdLedgerDatabaseReconciliationSettlement, + type BtdLicensedReadRevenueInput, + type BtdLicensedReadRevenueSettlement, + type BtdMintDraft, + type BtdMintDraftInput, + type BtdOrganizationInterfaceAuthorityRouteInput, + type BtdReadAccessInput, + type BtdReadAccessDecision, + type BtdReadLicense, + type BtdOwnershipClaim, + type BtdTerminalJournalInput, + type BtdTerminalJournalSettlement, + type TerminalJournalEntry, type BtcFeeTransactionReceipt, - type LedgerObservedFact, - type LedgerFinalityState, - type LedgerNetwork, - type MetaphysicalCanonicalFact, type ProjectionRepairReceipt, - type SemanticVolumeUnitInput, - type TerminalJournalEntry, - type TerminalJournalProjection, - type TerminalTransactionKind, - type V27CryptoDeploymentLaneKind, - type V27CryptoTelemetryEvent, type V27CryptoTelemetryRecord, - type WalletSignerSession, - allocateAssetPackRange, - allocateBtdContributorCells, - advanceBtcFeeTransactionReceipt, - advanceAssetPackLedgerAnchor, - acceptAssetPackExchangeOrder, - assertAssetPackLedgerAnchor, - assertBtcFeeTransactionReceipt, - assertLicensedReadRevenueRouteConserved, - assertNonEmptyString, - applyBtdMeasureMint, - buildBtdMintReceipt, - buildAssetPackRightsTransferReceipt, - buildV27CryptoDeploymentLane, - buildV27CryptoDeploymentReadinessReceipt, - buildV27CryptoTelemetryRecord, - buildPreparedAssetPackLedgerAnchor, - buildPreparedBtcFeeTransactionReceipt, - buildBtcFeeOperationPosture, - assertBtcFeeQuote, - assertBtcFeeQuoteActive, + type BtdProtocolUpgradeReceipt, + buildBtdAncestryReviewSettlement, + buildBtdAssetPackExchangeSettlement, + buildBtdAssetPackLedgerAnchorSettlement, + buildBtdBtcFeeTransactionSettlement, + buildBtdDeploymentReadinessSettlement, + buildBtdLedgerDatabaseReconciliationSettlement, + buildBtdLicensedReadRevenueSettlement, + buildBtdMintDraft, + buildBtdOrganizationInterfaceAuthorityDecision, + buildBtdReadAccessDecision, + buildBtdRegistrySnapshot, + buildBtdStableId as stableId, + buildBtdTerminalJournalSettlement, buildLicensedReadRevenueRoute, - buildPlannedBtdProtocolUpgradeReceipt, - buildTerminalJournalEntry, - buildTerminalJournalCoverageReceipt, - createWalletSignerSession, - cancelAssetPackExchangeOrder, - createAssetPackExchangeOrder, - createBtdMeasureMintState, - createBtdSupplyState, - evaluateBtdOrganizationInterfaceAuthority, - evaluateBtdReadAccess, - measureProofAddressableSemanticVolume, + parseBtdOptionalBigInt, + parseBtdRequiredBigInt, reviewBtdAncestorEdges, - settleAssetPackExchangeOrder, - diffTerminalJournalProjection, - reconcileLedgerDatabaseProjection, - advanceBtdProtocolUpgradeReceipt, + toBtdJsonSafe as toJsonSafe, } from '@bitcode/btd'; +export { + buildBtdAncestryReviewSettlement, + buildBtdAssetPackExchangeSettlement, + buildBtdAssetPackLedgerAnchorSettlement, + buildBtdBtcFeeTransactionSettlement, + buildBtdDeploymentReadinessSettlement, + buildBtdLedgerDatabaseReconciliationSettlement, + buildBtdLicensedReadRevenueSettlement, + buildBtdMintDraft, + buildBtdOrganizationInterfaceAuthorityDecision, + buildBtdReadAccessDecision, + buildBtdRegistrySnapshot, + buildBtdTerminalJournalSettlement, +}; + type AuthenticatedUser = { userId: string; }; @@ -95,368 +81,10 @@ type BtdRouteOptions = { resolveAuthenticatedUser?: BtdRouteAuthResolver; }; -export interface BtdMintDraftInput { - assetPackId: string; - readId: string; - acceptedNeed: true; - acceptedFit: true; - sourceManifestRoot: string; - fitReceiptRoot: string; - proofRoot: string; - dedupeReceiptRoot: string; - settlementJournalRoot: string; - exchangeReceiptRoot: string; - accessPolicyId: string; - accessPolicyHash: string; - semanticUnits: SemanticVolumeUnitInput[]; - contributors?: BtdContributorMeasure[]; - measureMintState?: BtdMeasureMintState; - exchangeSequence: bigint; - actorId?: string; - issuedAt?: string; -} - -export interface BtdMintDraft { - kind: 'btd_mint_draft'; - assetPackId: string; - measurement: ReturnType; - measureMint: ReturnType['receipt']; - rangeAllocation?: ReturnType; - mintReceipt?: ReturnType; - contributorAllocation?: ReturnType; - terminalJournalEntry: ReturnType; - blocking: boolean; - zeroCell: boolean; -} - -export interface BtdReadAccessInput { - walletId: string; - assetPackId: string; - accessPolicy: BtdAccessPolicy; - ownershipClaims?: BtdOwnershipClaim[]; - licenses?: BtdReadLicense[]; - at?: string; -} - type BtdReadAccessRouteInput = Omit & { accessPolicy?: BtdAccessPolicy; }; -export interface BtdReadAccessDecision { - kind: 'btd_read_access_decision'; - actorId: string; - assetPackId: string; - decision: ReturnType; - policyDisclosure: { - accessPolicyId: string; - accessPolicyHash: string; - ownerRead: boolean; - licensedRead: boolean; - derivativeUse: boolean; - redistributionAllowed: boolean; - confidentiality: BtdAccessPolicy['confidentiality']; - }; -} - -export interface BtdOrganizationInterfaceAuthorityInput { - organizationId: string; - organizationRole?: BtdOrganizationRole | null; - organizationPermissionGrants?: string[]; - interfaceSurface: BtdInterfaceAuthoritySurface; - action: BtdOrganizationPermissionAction; - walletId?: string | null; - readAccessDecision?: ReturnType | null; - settlementState?: BtdSettlementAuthorityState; - confirmed?: boolean; - repairApprovalState?: BtdRepairApprovalState; - targetAnchor?: string | null; - at?: string; -} - -export type BtdOrganizationInterfaceAuthorityRouteDecision = ReturnType< - typeof evaluateBtdOrganizationInterfaceAuthority -> & { - routeKind: 'btd_organization_interface_authority_route_decision'; -}; - -export interface BtdLicensedReadRevenueInput { - paymentId: string; - assetPackId: string; - grossSats: bigint | number | string; - directRecipients: BtdRevenueRecipientInput[]; - ancestorRecipients?: BtdRevenueRecipientInput[]; - treasuryWalletId: string; - disputeHoldbackWalletId?: string; - exchangeSequence: bigint; - directSplitBps?: number; - ancestorSplitBps?: number; - treasurySplitBps?: number; - disputeHoldbackBps?: number; - pendingRoutes?: BtdRevenueRouteException[]; - failedRoutes?: BtdRevenueRouteException[]; - commitToRegistry?: boolean; - actorId?: string; - issuedAt?: string; -} - -export interface BtdAncestryReviewInput { - reviewId?: string; - childAssetPackId: string; - edges: BtdAncestorEdgeInput[]; - existingEdges?: BtdAncestorGraphEdge[]; - duplicateSourceRoots?: string[]; - minConfidenceBps?: number; - citationOnlyPayable?: boolean; - exchangeSequence: bigint; - commitToRegistry?: boolean; - actorId?: string; - issuedAt?: string; -} - -export type BtdBtcFeeTransactionAction = - | 'prepare' - | 'mark_signed' - | 'mark_broadcast' - | 'observe'; - -export type BtdWalletSignerSessionInput = Parameters[0]; - -export interface BtdBtcFeeTransactionInput { - action: BtdBtcFeeTransactionAction; - receiptId?: string; - feePurpose?: BtcFeePurpose; - payerSession?: WalletSignerSession | BtdWalletSignerSessionInput; - psbt?: string; - signedPsbt?: string; - satsPaid?: bigint | number | string; - satsPerVbyte?: number; - exchangeSequence?: bigint; - terminalJournalRoot?: string; - relatedAssetPackId?: string; - relatedOrderId?: string; - previousReceipt?: BtcFeeTransactionReceipt; - feeQuote?: BtcFeeQuote; - txid?: string; - vout?: number; - observedFinalityState?: Exclude; - confirmations?: number; - commitToRegistry?: boolean; - actorId?: string; - issuedAt?: string; -} - -export type BtdAssetPackLedgerAnchorAction = 'prepare' | 'mark_broadcast' | 'observe'; - -export interface BtdAssetPackLedgerAnchorInput { - action: BtdAssetPackLedgerAnchorAction; - anchorId?: string; - assetPackId?: string; - chain?: AssetPackLedgerAnchor['chain']; - network?: AssetPackLedgerAnchor['network']; - commitmentMethod?: AssetPackLedgerAnchor['commitmentMethod']; - commitmentRoot?: string; - sourceManifestRoot?: string; - proofRoot?: string; - accessPolicyHash?: string; - btdRangeStart?: number; - btdRangeEndExclusive?: number; - contractAddress?: string; - tokenId?: string; - previousAnchor?: AssetPackLedgerAnchor; - txidOrHash?: string; - outputIndex?: number; - observedFinalityState?: Exclude; - confirmations?: number; - exchangeSequence: bigint; - commitToRegistry?: boolean; - actorId?: string; - issuedAt?: string; -} - -export type BtdAssetPackExchangeAction = - | 'create_order' - | 'cancel_order' - | 'accept_order' - | 'settle_order' - | 'transfer_rights'; - -export type BtdTerminalJournalAction = 'commit_entry' | 'diff_projection' | 'coverage'; - -export interface BtdAssetPackExchangeInput { - action: BtdAssetPackExchangeAction; - orderId?: string; - orderKind?: AssetPackExchangeOrderKind; - assetPackId?: string; - rangeStart?: number; - rangeEndExclusive?: number; - makerWalletId?: string; - takerWalletId?: string; - priceSats?: bigint | number | string; - accessPolicyHash?: string; - createdAtExchangeSequence?: bigint; - previousOrder?: AssetPackExchangeOrder; - settledAtExchangeSequence?: bigint; - ledgerAnchorId?: string; - receiptId?: string; - fromWalletId?: string; - toWalletId?: string; - btcFeeReceiptId?: string; - commitToRegistry?: boolean; - actorId?: string; - issuedAt?: string; -} - -export interface BtdTerminalJournalInput { - action: BtdTerminalJournalAction; - journalEntryId?: string; - transactionKind?: TerminalTransactionKind; - preStateRoot?: string; - postStateRoot?: string; - receiptRoots?: string[]; - ledgerAnchorIds?: string[]; - exchangeSequence?: bigint; - entry?: TerminalJournalEntry; - projection?: TerminalJournalProjection; - coverageId?: string; - entries?: TerminalJournalEntry[]; - commitToRegistry?: boolean; - actorId?: string; - issuedAt?: string; -} - -export interface BtdLedgerDatabaseReconciliationInput { - reconciliationId: string; - ledgerFacts: LedgerObservedFact[]; - databaseFacts: DatabaseProjectedFact[]; - metaphysicalFacts?: MetaphysicalCanonicalFact[]; - settlementConservationChecks?: Parameters[0]['settlementConservationChecks']; - commitToRegistry?: boolean; - actorId?: string; - issuedAt?: string; -} - -export type BtdDeploymentReadinessAction = - | 'deployment_lane' - | 'telemetry_event' - | 'upgrade_plan' - | 'upgrade_transition'; - -export interface BtdDeploymentReadinessInput { - action: BtdDeploymentReadinessAction; - readinessId?: string; - lane?: V27CryptoDeploymentLaneKind; - bitcoinNetwork?: BitcoinNetwork; - ledgerNetwork?: LedgerNetwork; - rollbackPlanRoot?: string; - operationalApprovalRoot?: string; - presentEnvironmentKeys?: string[]; - telemetryEvent?: V27CryptoTelemetryEvent; - telemetrySubjectId?: string; - telemetryReceiptRoot?: string; - telemetryLedgerAnchorId?: string; - upgradeId?: string; - fromVersion?: string; - toVersion?: string; - migrationRoot?: string; - preStateRoot?: string; - postStateRoot?: string; - approvalReceiptRoot?: string; - previousUpgradeReceipt?: BtdProtocolUpgradeReceipt; - nextUpgradeState?: Exclude; - ledgerAnchorId?: string; - commitToRegistry?: boolean; - actorId?: string; - issuedAt?: string; -} - -export interface BtdLicensedReadRevenueSettlement { - kind: 'btd_licensed_read_revenue_settlement'; - actorId: string; - receipt: ReturnType; - terminalJournalEntry: ReturnType; - registryWrite?: Awaited>; - committed: boolean; -} - -export interface BtdAncestryReviewSettlement { - kind: 'btd_ancestry_review_settlement'; - actorId: string; - receipt: ReturnType; - terminalJournalEntry: ReturnType; - registryWrites?: Awaited>[]; - committed: boolean; -} - -export interface BtdBtcFeeTransactionSettlement { - kind: 'btd_btc_fee_transaction_settlement'; - actorId: string; - action: BtdBtcFeeTransactionAction; - receipt: BtcFeeTransactionReceipt; - operationPosture: BtcFeeOperationPosture; - terminalJournalEntry: ReturnType; - registryWrite?: Awaited>; - committed: boolean; -} - -export interface BtdAssetPackLedgerAnchorSettlement { - kind: 'btd_asset_pack_ledger_anchor_settlement'; - actorId: string; - action: BtdAssetPackLedgerAnchorAction; - anchor: AssetPackLedgerAnchor; - terminalJournalEntry: ReturnType; - registryWrite?: Awaited>; - committed: boolean; -} - -export interface BtdAssetPackExchangeSettlement { - kind: 'btd_asset_pack_exchange_settlement'; - actorId: string; - action: BtdAssetPackExchangeAction; - order?: AssetPackExchangeOrder; - rightsTransfer?: AssetPackRightsTransferReceipt; - terminalJournalEntry: ReturnType; - registryWrite?: Awaited< - | ReturnType - | ReturnType - | ReturnType - >; - committed: boolean; -} - -export interface BtdTerminalJournalSettlement { - kind: 'btd_terminal_journal_settlement'; - actorId: string; - action: BtdTerminalJournalAction; - entry?: TerminalJournalEntry; - diff?: ReturnType; - coverage?: ReturnType; - registryWrite?: Awaited>; - committed: boolean; -} - -export interface BtdLedgerDatabaseReconciliationSettlement { - kind: 'btd_ledger_database_reconciliation_settlement'; - actorId: string; - report: ReturnType; - terminalJournalEntry: ReturnType; - registryWrites?: Awaited>[]; - committed: boolean; -} - -export interface BtdDeploymentReadinessSettlement { - kind: 'btd_deployment_readiness_settlement'; - actorId: string; - action: BtdDeploymentReadinessAction; - readiness?: ReturnType; - telemetry?: V27CryptoTelemetryRecord; - upgradeReceipt?: BtdProtocolUpgradeReceipt; - registryWrite?: Awaited< - | ReturnType - | ReturnType - >; - committed: boolean; -} - let defaultRegistry: BtdRegistryModel | null = null; function getDefaultRegistry() { @@ -481,645 +109,6 @@ async function defaultResolveAuthenticatedUser(): Promise `${unit.unitId}:${unit.proofReceiptRoot}`).join('|'), - ]); - const measurement = measureProofAddressableSemanticVolume({ - measurementId, - assetPackId: input.assetPackId, - units: input.semanticUnits, - issuedAt, - }); - const measureMint = applyBtdMeasureMint({ - state: normalizeMeasureMintState(input.measureMintState), - assetPackId: input.assetPackId, - semanticVolume: measurement, - proofRoot: input.proofRoot, - settlementJournalRoot: input.settlementJournalRoot, - accessPolicyHash: input.accessPolicyHash, - exchangeSequence: input.exchangeSequence, - issuedAt, - }); - - const rangeAllocation = - measureMint.receipt.tokenCount > 0 - ? allocateAssetPackRange( - createBtdSupplyState({ - totalMinted: measureMint.receipt.totalMintedBefore, - nextTokenId: measureMint.receipt.totalMintedBefore, - cumulativeAdmittedMeasurement: measureMint.receipt.cumulativeMeasurementBefore, - residualMintCredit: measureMint.receipt.residualMintCreditBefore, - curveParameter: measureMint.previousState.curveParameter, - }), - { - assetPackId: input.assetPackId, - readId: input.readId, - acceptedNeed: input.acceptedNeed, - acceptedFit: input.acceptedFit, - sourceManifestRoot: input.sourceManifestRoot, - measurementReceiptRoot: measurement.measurementId, - fitReceiptRoot: input.fitReceiptRoot, - proofRoot: input.proofRoot, - dedupeReceiptRoot: input.dedupeReceiptRoot, - settlementJournalRoot: input.settlementJournalRoot, - exchangeReceiptRoot: input.exchangeReceiptRoot, - accessPolicyId: input.accessPolicyId, - accessPolicyHash: input.accessPolicyHash, - normalizedBitcodeVolume: measurement.normalizedBitcodeVolume, - tokenCount: measureMint.receipt.tokenCount, - mintedAtExchangeSequence: input.exchangeSequence, - }, - ) - : undefined; - const mintReceipt = rangeAllocation ? buildBtdMintReceipt(rangeAllocation, issuedAt) : undefined; - const contributorAllocation = - rangeAllocation && input.contributors?.length - ? allocateBtdContributorCells({ - assetPackId: input.assetPackId, - rangeStart: rangeAllocation.range.rangeStart, - rangeEndExclusive: rangeAllocation.range.rangeEndExclusive, - contributors: input.contributors, - issuedAt, - }) - : undefined; - const receiptRoots = [ - measurement.measurementId, - stableId('btd-measure-mint', [input.assetPackId, input.exchangeSequence.toString()]), - mintReceipt ? stableId('btd-asset-pack-mint', [input.assetPackId, mintReceipt.issuedAt]) : null, - contributorAllocation - ? stableId('btd-contributor-allocation', [input.assetPackId, contributorAllocation.issuedAt]) - : null, - ].filter((value): value is string => Boolean(value)); - const terminalJournalEntry = buildTerminalJournalEntry({ - journalEntryId: stableId('terminal-v27-btd-mint-draft', [ - input.assetPackId, - input.exchangeSequence.toString(), - ]), - transactionKind: measureMint.receipt.tokenCount > 0 ? 'asset_pack_mint' : 'measure_mint_tail', - actorId: input.actorId ?? 'system:v27-btd-mint-draft', - preStateRoot: stableId('btd-pre-state', [measureMint.receipt.totalMintedBefore.toString()]), - postStateRoot: stableId('btd-post-state', [ - measureMint.receipt.totalMintedAfter.toString(), - measureMint.receipt.cumulativeMeasurementAfter.toString(), - ]), - receiptRoots, - ledgerAnchorIds: [], - exchangeSequence: input.exchangeSequence, - issuedAt, - }); - - return { - kind: 'btd_mint_draft', - assetPackId: input.assetPackId, - measurement, - measureMint: measureMint.receipt, - rangeAllocation, - mintReceipt, - contributorAllocation, - terminalJournalEntry, - blocking: false, - zeroCell: measureMint.receipt.tokenCount === 0, - }; -} - -export function buildBtdReadAccessDecision( - input: BtdReadAccessInput & { actorId: string }, -): BtdReadAccessDecision { - assertNonEmptyString(input.actorId, 'actorId'); - assertNonEmptyString(input.walletId, 'walletId'); - assertNonEmptyString(input.assetPackId, 'assetPackId'); - const decision = evaluateBtdReadAccess(input); - - return { - kind: 'btd_read_access_decision', - actorId: input.actorId, - assetPackId: input.assetPackId, - decision, - policyDisclosure: { - accessPolicyId: input.accessPolicy.accessPolicyId, - accessPolicyHash: input.accessPolicy.accessPolicyHash, - ownerRead: input.accessPolicy.ownerRead, - licensedRead: input.accessPolicy.licensedRead, - derivativeUse: input.accessPolicy.derivativeUse, - redistributionAllowed: input.accessPolicy.redistributionAllowed, - confidentiality: input.accessPolicy.confidentiality, - }, - }; -} - -export function buildBtdOrganizationInterfaceAuthorityDecision( - input: BtdOrganizationInterfaceAuthorityInput & { actorId: string }, -): BtdOrganizationInterfaceAuthorityRouteDecision { - const decision = evaluateBtdOrganizationInterfaceAuthority({ - ...input, - actorId: assertNonEmptyString(input.actorId, 'actorId'), - }); - - return { - ...decision, - routeKind: 'btd_organization_interface_authority_route_decision', - }; -} - -export function buildBtdLicensedReadRevenueSettlement( - input: BtdLicensedReadRevenueInput & { actorId: string }, -): Omit { - const actorId = assertNonEmptyString(input.actorId, 'actorId'); - const receipt = assertLicensedReadRevenueRouteConserved( - buildLicensedReadRevenueRoute({ - paymentId: input.paymentId, - assetPackId: input.assetPackId, - grossSats: input.grossSats, - directRecipients: input.directRecipients, - ancestorRecipients: input.ancestorRecipients, - treasuryWalletId: input.treasuryWalletId, - disputeHoldbackWalletId: input.disputeHoldbackWalletId, - exchangeSequence: input.exchangeSequence, - directSplitBps: input.directSplitBps, - ancestorSplitBps: input.ancestorSplitBps, - treasurySplitBps: input.treasurySplitBps, - disputeHoldbackBps: input.disputeHoldbackBps, - pendingRoutes: input.pendingRoutes, - failedRoutes: input.failedRoutes, - issuedAt: input.issuedAt, - }), - ); - const terminalJournalEntry = buildTerminalJournalEntry({ - journalEntryId: stableId('terminal-v27-licensed-read-revenue', [ - receipt.assetPackId, - receipt.paymentId, - receipt.exchangeSequence.toString(), - ]), - transactionKind: 'settlement_finalization', - actorId, - preStateRoot: stableId('btd-revenue-pre-state', [receipt.paymentId]), - postStateRoot: stableId('btd-revenue-post-state', [ - receipt.paymentId, - receipt.grossSats.toString(), - receipt.routeState, - ]), - receiptRoots: [ - stableId('btd-licensed-read-revenue-route', [ - receipt.assetPackId, - receipt.paymentId, - receipt.issuedAt, - ]), - ], - ledgerAnchorIds: [], - exchangeSequence: receipt.exchangeSequence, - issuedAt: receipt.issuedAt, - }); - - return { - kind: 'btd_licensed_read_revenue_settlement', - actorId, - receipt, - terminalJournalEntry, - }; -} - -export function buildBtdAncestryReviewSettlement( - input: BtdAncestryReviewInput & { actorId: string }, -): Omit { - const actorId = assertNonEmptyString(input.actorId, 'actorId'); - assertNonEmptyString(input.childAssetPackId, 'childAssetPackId'); - if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { - throw new Error('BTD ancestry review requires a positive Exchange sequence.'); - } - - const issuedAt = input.issuedAt ?? new Date().toISOString(); - const reviewId = - input.reviewId ?? - stableId('btd-ancestry-review', [input.childAssetPackId, input.exchangeSequence.toString()]); - const receipt = reviewBtdAncestorEdges({ - reviewId, - childAssetPackId: input.childAssetPackId, - edges: input.edges, - existingEdges: input.existingEdges, - duplicateSourceRoots: input.duplicateSourceRoots, - minConfidenceBps: input.minConfidenceBps, - citationOnlyPayable: input.citationOnlyPayable, - issuedAt, - }); - const terminalJournalEntry = buildTerminalJournalEntry({ - journalEntryId: stableId('terminal-btd-ancestry-review', [ - receipt.childAssetPackId, - receipt.reviewId, - ]), - transactionKind: 'settlement_finalization', - actorId, - preStateRoot: stableId('btd-ancestry-pre-state', [receipt.childAssetPackId]), - postStateRoot: stableId('btd-ancestry-post-state', [ - receipt.childAssetPackId, - String(receipt.payableEdgeCount), - String(receipt.recordedUnpaidEdgeCount), - String(receipt.rejectedEdgeCount), - ]), - receiptRoots: [receipt.reviewId], - ledgerAnchorIds: [], - exchangeSequence: input.exchangeSequence, - issuedAt, - }); - - return { - kind: 'btd_ancestry_review_settlement', - actorId, - receipt, - terminalJournalEntry, - }; -} - -export function buildBtdBtcFeeTransactionSettlement( - input: BtdBtcFeeTransactionInput & { actorId: string }, -): Omit { - const actorId = assertNonEmptyString(input.actorId, 'actorId'); - const issuedAt = input.issuedAt ?? new Date().toISOString(); - const feeQuote = normalizeBtcFeeQuote(input.feeQuote); - const receipt = buildBtcFeeReceiptForAction({ ...input, feeQuote, issuedAt }); - const payerSession = input.payerSession ? normalizeWalletSignerSession(input.payerSession) : undefined; - const operationPosture = buildBtcFeeOperationPosture({ - quote: feeQuote, - receipt, - payerSession, - at: issuedAt, - }); - const terminalJournalEntry = buildTerminalJournalEntry({ - journalEntryId: stableId('terminal-btd-btc-fee', [ - receipt.receiptId, - receipt.finalityState, - receipt.exchangeSequence.toString(), - ]), - transactionKind: 'btc_fee_payment', - actorId, - preStateRoot: stableId('btc-fee-pre-state', [ - input.previousReceipt?.receiptId ?? receipt.receiptId, - input.previousReceipt?.finalityState ?? 'none', - ]), - postStateRoot: stableId('btc-fee-post-state', [ - receipt.receiptId, - receipt.finalityState, - receipt.txid ?? 'no-txid', - String(receipt.confirmations), - ]), - receiptRoots: [receipt.receiptId], - ledgerAnchorIds: receipt.txid ? [receipt.txid] : [], - exchangeSequence: receipt.exchangeSequence, - issuedAt, - }); - - return { - kind: 'btd_btc_fee_transaction_settlement', - actorId, - action: input.action, - receipt, - operationPosture, - terminalJournalEntry, - }; -} - -export function buildBtdAssetPackLedgerAnchorSettlement( - input: BtdAssetPackLedgerAnchorInput & { actorId: string }, -): Omit { - const actorId = assertNonEmptyString(input.actorId, 'actorId'); - if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { - throw new Error('AssetPack ledger anchor settlement requires a positive Exchange sequence.'); - } - const issuedAt = input.issuedAt ?? new Date().toISOString(); - const anchor = buildAssetPackLedgerAnchorForAction(input); - const terminalJournalEntry = buildTerminalJournalEntry({ - journalEntryId: stableId('terminal-btd-asset-pack-anchor', [ - anchor.anchorId, - anchor.finalityState, - input.exchangeSequence.toString(), - ]), - transactionKind: 'asset_pack_anchor', - actorId, - preStateRoot: stableId('asset-pack-anchor-pre-state', [ - input.previousAnchor?.anchorId ?? anchor.anchorId, - input.previousAnchor?.finalityState ?? 'none', - ]), - postStateRoot: stableId('asset-pack-anchor-post-state', [ - anchor.anchorId, - anchor.finalityState, - anchor.txidOrHash ?? 'no-ledger-id', - String(anchor.confirmations), - ]), - receiptRoots: [anchor.anchorId], - ledgerAnchorIds: anchor.txidOrHash ? [anchor.txidOrHash] : [], - exchangeSequence: input.exchangeSequence, - issuedAt, - }); - - return { - kind: 'btd_asset_pack_ledger_anchor_settlement', - actorId, - action: input.action, - anchor, - terminalJournalEntry, - }; -} - -export function buildBtdAssetPackExchangeSettlement( - input: BtdAssetPackExchangeInput & { actorId: string }, -): Omit { - const actorId = assertNonEmptyString(input.actorId, 'actorId'); - const { order, rightsTransfer, exchangeSequence } = buildAssetPackExchangeForAction(input); - const receiptRoot = rightsTransfer?.receiptId ?? order?.orderId; - if (!receiptRoot) { - throw new Error('AssetPack Exchange settlement requires an order or rights-transfer receipt.'); - } - const terminalJournalEntry = buildTerminalJournalEntry({ - journalEntryId: stableId('terminal-btd-asset-pack-exchange', [ - input.action, - receiptRoot, - exchangeSequence.toString(), - ]), - transactionKind: rightsTransfer ? 'rights_transfer' : 'exchange_order', - actorId, - preStateRoot: stableId('asset-pack-exchange-pre-state', [ - input.previousOrder?.orderId ?? input.orderId ?? receiptRoot, - input.previousOrder?.orderState ?? 'none', - ]), - postStateRoot: stableId('asset-pack-exchange-post-state', [ - order?.orderId ?? rightsTransfer?.orderId ?? receiptRoot, - order?.orderState ?? 'rights_transfer', - rightsTransfer?.btcFeeReceiptId ?? 'no-fee', - ]), - receiptRoots: [receiptRoot], - ledgerAnchorIds: [order?.ledgerAnchorId, rightsTransfer?.ledgerAnchorId].filter( - (value): value is string => Boolean(value), - ), - exchangeSequence, - issuedAt: input.issuedAt, - }); - - return { - kind: 'btd_asset_pack_exchange_settlement', - actorId, - action: input.action, - order, - rightsTransfer, - terminalJournalEntry, - }; -} - -export function buildBtdTerminalJournalSettlement( - input: BtdTerminalJournalInput & { actorId: string }, -): Omit { - const actorId = assertNonEmptyString(input.actorId, 'actorId'); - - switch (input.action) { - case 'commit_entry': { - const entry = - input.entry ?? - buildTerminalJournalEntry({ - journalEntryId: assertNonEmptyString(input.journalEntryId, 'journalEntryId'), - transactionKind: requireTerminalTransactionKind(input.transactionKind), - actorId, - preStateRoot: assertNonEmptyString(input.preStateRoot, 'preStateRoot'), - postStateRoot: assertNonEmptyString(input.postStateRoot, 'postStateRoot'), - receiptRoots: input.receiptRoots ?? [], - ledgerAnchorIds: input.ledgerAnchorIds, - exchangeSequence: requireBigInt(input.exchangeSequence, 'exchangeSequence'), - issuedAt: input.issuedAt, - }); - - return { - kind: 'btd_terminal_journal_settlement', - actorId, - action: input.action, - entry: normalizeTerminalJournalEntry(entry), - }; - } - case 'diff_projection': { - const entry = normalizeTerminalJournalEntry(input.entry); - if (!input.projection) { - throw new Error('Terminal journal diff requires projection.'); - } - - return { - kind: 'btd_terminal_journal_settlement', - actorId, - action: input.action, - entry, - diff: diffTerminalJournalProjection(entry, input.projection), - }; - } - case 'coverage': { - if (!input.coverageId) throw new Error('Terminal journal coverage requires coverageId.'); - if (!input.entries?.length) { - throw new Error('Terminal journal coverage requires entries.'); - } - - return { - kind: 'btd_terminal_journal_settlement', - actorId, - action: input.action, - coverage: buildTerminalJournalCoverageReceipt({ - coverageId: input.coverageId, - entries: input.entries.map((entry) => normalizeTerminalJournalEntry(entry)), - issuedAt: input.issuedAt, - }), - }; - } - default: - throw new Error( - `Unsupported Terminal journal action: ${(input as { action: string }).action}.`, - ); - } -} - -export function buildBtdLedgerDatabaseReconciliationSettlement( - input: BtdLedgerDatabaseReconciliationInput & { actorId: string }, -): Omit { - const actorId = assertNonEmptyString(input.actorId, 'actorId'); - const report = reconcileLedgerDatabaseProjection({ - reconciliationId: input.reconciliationId, - ledgerFacts: input.ledgerFacts, - databaseFacts: input.databaseFacts, - metaphysicalFacts: input.metaphysicalFacts, - settlementConservationChecks: input.settlementConservationChecks, - issuedAt: input.issuedAt, - }); - const terminalJournalEntry = buildTerminalJournalEntry({ - journalEntryId: stableId('terminal-btd-reconciliation', [ - report.reconciliationId, - String(report.repairs.length), - String(report.blocking), - ]), - transactionKind: 'ledger_database_reconciliation', - actorId, - preStateRoot: stableId('reconciliation-pre-state', [ - report.reconciliationId, - String(input.databaseFacts.length), - ]), - postStateRoot: stableId('reconciliation-post-state', [ - report.reconciliationId, - String(report.repairs.length), - String(report.blocking), - String(report.metaphysicalFacts.length), - ]), - receiptRoots: [ - report.reconciliationId, - ...report.repairs.map((repair) => repair.repairId), - ...report.metaphysicalFacts.map((fact) => fact.receiptRoot ?? fact.canonicalRoot), - report.proofRoots.ledgerObservedRoot, - report.proofRoots.databaseProjectionRoot, - report.proofRoots.repairPlanRoot, - report.proofRoots.settlementConservationRoot, - ], - ledgerAnchorIds: input.ledgerFacts.map((fact) => fact.factId), - exchangeSequence: BigInt(Math.max(1, input.ledgerFacts.length + input.databaseFacts.length)), - issuedAt: input.issuedAt, - }); - - return { - kind: 'btd_ledger_database_reconciliation_settlement', - actorId, - report, - terminalJournalEntry, - }; -} - -export function buildBtdDeploymentReadinessSettlement( - input: BtdDeploymentReadinessInput & { actorId: string }, -): Omit { - const actorId = assertNonEmptyString(input.actorId, 'actorId'); - - switch (input.action) { - case 'deployment_lane': { - if (!input.readinessId) throw new Error('Deployment readiness requires readinessId.'); - if (!input.lane) throw new Error('Deployment readiness requires lane.'); - if (!input.bitcoinNetwork) throw new Error('Deployment readiness requires bitcoinNetwork.'); - if (!input.ledgerNetwork) throw new Error('Deployment readiness requires ledgerNetwork.'); - if (!input.rollbackPlanRoot) { - throw new Error('Deployment readiness requires rollbackPlanRoot.'); - } - - const lane = buildV27CryptoDeploymentLane({ - lane: input.lane, - bitcoinNetwork: input.bitcoinNetwork, - ledgerNetwork: input.ledgerNetwork, - rollbackPlanRoot: input.rollbackPlanRoot, - operationalApprovalRoot: input.operationalApprovalRoot, - }); - - return { - kind: 'btd_deployment_readiness_settlement', - actorId, - action: input.action, - readiness: buildV27CryptoDeploymentReadinessReceipt({ - readinessId: input.readinessId, - lane, - presentEnvironmentKeys: input.presentEnvironmentKeys ?? [], - issuedAt: input.issuedAt, - }), - }; - } - case 'telemetry_event': { - if (!input.telemetryEvent) throw new Error('Telemetry settlement requires event.'); - if (!input.telemetrySubjectId) { - throw new Error('Telemetry settlement requires subjectId.'); - } - - return { - kind: 'btd_deployment_readiness_settlement', - actorId, - action: input.action, - telemetry: buildV27CryptoTelemetryRecord({ - event: input.telemetryEvent, - subjectId: input.telemetrySubjectId, - receiptRoot: input.telemetryReceiptRoot, - ledgerAnchorId: input.telemetryLedgerAnchorId, - issuedAt: input.issuedAt, - }), - }; - } - case 'upgrade_plan': { - if (!input.upgradeId) throw new Error('Upgrade plan requires upgradeId.'); - if (!input.fromVersion) throw new Error('Upgrade plan requires fromVersion.'); - if (!input.toVersion) throw new Error('Upgrade plan requires toVersion.'); - if (!input.ledgerNetwork) throw new Error('Upgrade plan requires ledgerNetwork.'); - if (!input.migrationRoot) throw new Error('Upgrade plan requires migrationRoot.'); - if (!input.preStateRoot) throw new Error('Upgrade plan requires preStateRoot.'); - if (!input.approvalReceiptRoot) { - throw new Error('Upgrade plan requires approvalReceiptRoot.'); - } - if (!input.rollbackPlanRoot) throw new Error('Upgrade plan requires rollbackPlanRoot.'); - - return { - kind: 'btd_deployment_readiness_settlement', - actorId, - action: input.action, - upgradeReceipt: buildPlannedBtdProtocolUpgradeReceipt({ - upgradeId: input.upgradeId, - fromVersion: input.fromVersion, - toVersion: input.toVersion, - network: input.ledgerNetwork, - migrationRoot: input.migrationRoot, - preStateRoot: input.preStateRoot, - approvalReceiptRoot: input.approvalReceiptRoot, - rollbackPlanRoot: input.rollbackPlanRoot, - issuedAt: input.issuedAt, - }), - }; - } - case 'upgrade_transition': { - if (!input.previousUpgradeReceipt) { - throw new Error('Upgrade transition requires previousUpgradeReceipt.'); - } - if (!input.nextUpgradeState) { - throw new Error('Upgrade transition requires nextUpgradeState.'); - } - - return { - kind: 'btd_deployment_readiness_settlement', - actorId, - action: input.action, - upgradeReceipt: advanceBtdProtocolUpgradeReceipt(input.previousUpgradeReceipt, { - upgradeState: input.nextUpgradeState, - postStateRoot: input.postStateRoot, - ledgerAnchorId: input.ledgerAnchorId, - }), - }; - } - default: - throw new Error( - `Unsupported deployment readiness action: ${(input as { action: string }).action}.`, - ); - } -} - export function buildGetBtdRegistrySnapshotRoute(options: BtdRouteOptions = {}) { return traceRoute('/btd/registry', async (request: Request) => { const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( @@ -1162,7 +151,7 @@ export function buildPostBtdMintDraftRoute(options: BtdRouteOptions = {}) { draft = buildBtdMintDraft({ ...body, actorId: user.userId, - exchangeSequence: BigInt(body.exchangeSequence), + exchangeSequence: parseBtdRequiredBigInt(body.exchangeSequence, 'exchangeSequence'), }); } catch (error) { return createJsonResponse({ error: toBadRequestMessage(error) }, 400); @@ -1240,7 +229,7 @@ export function buildPostBtdOrganizationInterfaceAuthorityRoute( return createJsonResponse({ error: 'Unauthorized' }, 401); } - let body: BtdOrganizationInterfaceAuthorityInput; + let body: BtdOrganizationInterfaceAuthorityRouteInput; try { body = await request.json(); } catch { @@ -1283,7 +272,7 @@ export function buildPostBtdLicensedReadRevenueRoute(options: BtdRouteOptions = const draft = buildBtdLicensedReadRevenueSettlement({ ...body, actorId: user.userId, - exchangeSequence: BigInt(body.exchangeSequence), + exchangeSequence: parseBtdRequiredBigInt(body.exchangeSequence, 'exchangeSequence'), }); const registry = body.commitToRegistry === true ? options.registry ?? getDefaultRegistry() : undefined; @@ -1327,7 +316,7 @@ export function buildPostBtdAncestryReviewRoute(options: BtdRouteOptions = {}) { const draft = buildBtdAncestryReviewSettlement({ ...body, actorId: user.userId, - exchangeSequence: BigInt(body.exchangeSequence), + exchangeSequence: parseBtdRequiredBigInt(body.exchangeSequence, 'exchangeSequence'), }); const registry = body.commitToRegistry === true ? options.registry ?? getDefaultRegistry() : undefined; @@ -1373,8 +362,7 @@ export function buildPostBtdBtcFeeTransactionRoute(options: BtdRouteOptions = {} const draft = buildBtdBtcFeeTransactionSettlement({ ...body, actorId: user.userId, - exchangeSequence: - body.exchangeSequence === undefined ? undefined : BigInt(body.exchangeSequence), + exchangeSequence: parseBtdOptionalBigInt(body.exchangeSequence, 'exchangeSequence'), }); const registry = body.commitToRegistry === true ? options.registry ?? getDefaultRegistry() : undefined; @@ -1416,7 +404,7 @@ export function buildPostBtdAssetPackLedgerAnchorRoute(options: BtdRouteOptions const draft = buildBtdAssetPackLedgerAnchorSettlement({ ...body, actorId: user.userId, - exchangeSequence: BigInt(body.exchangeSequence), + exchangeSequence: parseBtdRequiredBigInt(body.exchangeSequence, 'exchangeSequence'), }); const registry = body.commitToRegistry === true ? options.registry ?? getDefaultRegistry() : undefined; @@ -1459,13 +447,9 @@ export function buildPostBtdAssetPackExchangeRoute(options: BtdRouteOptions = {} ...body, actorId: user.userId, createdAtExchangeSequence: - body.createdAtExchangeSequence === undefined - ? undefined - : BigInt(body.createdAtExchangeSequence), + parseBtdOptionalBigInt(body.createdAtExchangeSequence, 'createdAtExchangeSequence'), settledAtExchangeSequence: - body.settledAtExchangeSequence === undefined - ? undefined - : BigInt(body.settledAtExchangeSequence), + parseBtdOptionalBigInt(body.settledAtExchangeSequence, 'settledAtExchangeSequence'), }); const registry = body.commitToRegistry === true ? options.registry ?? getDefaultRegistry() : undefined; @@ -1507,8 +491,7 @@ export function buildPostBtdTerminalJournalRoute(options: BtdRouteOptions = {}) const draft = buildBtdTerminalJournalSettlement({ ...body, actorId: user.userId, - exchangeSequence: - body.exchangeSequence === undefined ? undefined : BigInt(body.exchangeSequence), + exchangeSequence: parseBtdOptionalBigInt(body.exchangeSequence, 'exchangeSequence'), }); const registry = body.commitToRegistry === true && draft.entry @@ -1642,407 +625,8 @@ export const postBtdLedgerDatabaseReconciliation = buildPostBtdLedgerDatabaseReconciliationRoute(); export const postBtdDeploymentReadiness = buildPostBtdDeploymentReadinessRoute(); -function assertMintDraftAdmission(input: BtdMintDraftInput): void { - if (input.acceptedNeed !== true) { - throw new Error('V27 BTD mint draft requires accepted Read.'); - } - - if (input.acceptedFit !== true) { - throw new Error('V27 BTD mint draft requires accepted Fit.'); - } - - if (!input.semanticUnits.length) { - throw new Error('V27 BTD mint draft requires at least one semantic unit.'); - } - - assertNonEmptyString(input.assetPackId, 'assetPackId'); - assertNonEmptyString(input.readId, 'readId'); - assertNonEmptyString(input.sourceManifestRoot, 'sourceManifestRoot'); - assertNonEmptyString(input.fitReceiptRoot, 'fitReceiptRoot'); - assertNonEmptyString(input.proofRoot, 'proofRoot'); - assertNonEmptyString(input.dedupeReceiptRoot, 'dedupeReceiptRoot'); - assertNonEmptyString(input.settlementJournalRoot, 'settlementJournalRoot'); - assertNonEmptyString(input.exchangeReceiptRoot, 'exchangeReceiptRoot'); - assertNonEmptyString(input.accessPolicyId, 'accessPolicyId'); - assertNonEmptyString(input.accessPolicyHash, 'accessPolicyHash'); - - if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { - throw new Error('V27 BTD mint draft requires a positive Exchange sequence.'); - } -} - -function normalizeMeasureMintState(state?: BtdMeasureMintState): BtdMeasureMintState { - if (!state) { - return createBtdMeasureMintState(); - } - - return createBtdMeasureMintState({ - totalMinted: state.totalMinted, - nextTokenId: state.nextTokenId, - cumulativeAdmittedMeasurement: state.cumulativeAdmittedMeasurement, - curveParameter: state.curveParameter, - }); -} - -function buildBtcFeeReceiptForAction( - input: BtdBtcFeeTransactionInput, -): BtcFeeTransactionReceipt { - switch (input.action) { - case 'prepare': { - if (!input.receiptId) throw new Error('BTC fee prepare requires receiptId.'); - if (!input.feePurpose) throw new Error('BTC fee prepare requires feePurpose.'); - if (!input.payerSession) throw new Error('BTC fee prepare requires payerSession.'); - if (!input.psbt) throw new Error('BTC fee prepare requires psbt.'); - if (input.satsPaid === undefined) throw new Error('BTC fee prepare requires satsPaid.'); - if (typeof input.exchangeSequence !== 'bigint') { - throw new Error('BTC fee prepare requires bigint exchangeSequence.'); - } - if (!input.terminalJournalRoot) { - throw new Error('BTC fee prepare requires terminalJournalRoot.'); - } - - if (input.feeQuote) { - const feeQuote = assertBtcFeeQuoteActive(input.feeQuote, input.issuedAt); - if (feeQuote.state !== 'accepted') { - throw new Error('BTC fee prepare requires an accepted feeQuote.'); - } - if (feeQuote.feePurpose !== input.feePurpose) { - throw new Error('BTC fee quote purpose does not match prepare input.'); - } - if (feeQuote.sats !== BigInt(input.satsPaid)) { - throw new Error('BTC fee quote sats do not match prepare input.'); - } - } - - return buildPreparedBtcFeeTransactionReceipt({ - receiptId: input.receiptId, - feePurpose: input.feePurpose, - payerSession: normalizeWalletSignerSession(input.payerSession), - psbt: input.psbt, - satsPaid: input.satsPaid, - satsPerVbyte: input.satsPerVbyte, - exchangeSequence: input.exchangeSequence, - terminalJournalRoot: input.terminalJournalRoot, - relatedAssetPackId: input.relatedAssetPackId, - relatedOrderId: input.relatedOrderId, - issuedAt: input.issuedAt, - }); - } - case 'mark_signed': { - const previous = normalizeBtcFeeTransactionReceipt(input.previousReceipt); - return advanceBtcFeeTransactionReceipt(previous, { - finalityState: 'signed', - psbt: assertNonEmptyString(input.signedPsbt, 'signedPsbt'), - }); - } - case 'mark_broadcast': { - const previous = normalizeBtcFeeTransactionReceipt(input.previousReceipt); - return advanceBtcFeeTransactionReceipt(previous, { - finalityState: 'broadcast', - txid: assertNonEmptyString(input.txid, 'txid'), - vout: input.vout, - }); - } - case 'observe': { - const previous = normalizeBtcFeeTransactionReceipt(input.previousReceipt); - const observedFinalityState = input.observedFinalityState; - if ( - observedFinalityState !== 'confirmed' && - observedFinalityState !== 'replaced' && - observedFinalityState !== 'reorged' && - observedFinalityState !== 'failed' && - observedFinalityState !== 'broadcast' - ) { - throw new Error('BTC fee observe requires an observed finality state.'); - } - - return advanceBtcFeeTransactionReceipt(previous, { - finalityState: observedFinalityState, - txid: input.txid ?? previous.txid ?? undefined, - confirmations: input.confirmations, - }); - } - default: - throw new Error(`Unsupported BTC fee transaction action: ${(input as { action: string }).action}.`); - } -} - -function buildAssetPackLedgerAnchorForAction( - input: BtdAssetPackLedgerAnchorInput, -): AssetPackLedgerAnchor { - switch (input.action) { - case 'prepare': { - if (!input.anchorId) throw new Error('AssetPack ledger anchor prepare requires anchorId.'); - if (!input.assetPackId) { - throw new Error('AssetPack ledger anchor prepare requires assetPackId.'); - } - if (!input.network) throw new Error('AssetPack ledger anchor prepare requires network.'); - if (!input.commitmentRoot) { - throw new Error('AssetPack ledger anchor prepare requires commitmentRoot.'); - } - if (!input.sourceManifestRoot) { - throw new Error('AssetPack ledger anchor prepare requires sourceManifestRoot.'); - } - if (!input.proofRoot) throw new Error('AssetPack ledger anchor prepare requires proofRoot.'); - if (!input.accessPolicyHash) { - throw new Error('AssetPack ledger anchor prepare requires accessPolicyHash.'); - } - if (input.btdRangeStart === undefined || input.btdRangeEndExclusive === undefined) { - throw new Error('AssetPack ledger anchor prepare requires BTD range bounds.'); - } - - return buildPreparedAssetPackLedgerAnchor({ - anchorId: input.anchorId, - assetPackId: input.assetPackId, - chain: input.chain, - network: input.network, - commitmentMethod: input.commitmentMethod, - commitmentRoot: input.commitmentRoot, - sourceManifestRoot: input.sourceManifestRoot, - proofRoot: input.proofRoot, - accessPolicyHash: input.accessPolicyHash, - btdRangeStart: input.btdRangeStart, - btdRangeEndExclusive: input.btdRangeEndExclusive, - contractAddress: input.contractAddress, - tokenId: input.tokenId, - }); - } - case 'mark_broadcast': { - const previous = normalizeAssetPackLedgerAnchor(input.previousAnchor); - return advanceAssetPackLedgerAnchor(previous, { - finalityState: 'broadcast', - txidOrHash: assertNonEmptyString(input.txidOrHash, 'txidOrHash'), - outputIndex: input.outputIndex, - anchoredAt: input.issuedAt, - }); - } - case 'observe': { - const previous = normalizeAssetPackLedgerAnchor(input.previousAnchor); - const observedFinalityState = input.observedFinalityState; - if ( - observedFinalityState !== 'confirmed' && - observedFinalityState !== 'reorged' && - observedFinalityState !== 'failed' && - observedFinalityState !== 'broadcast' - ) { - throw new Error('AssetPack ledger anchor observe requires an observed finality state.'); - } - - return advanceAssetPackLedgerAnchor(previous, { - finalityState: observedFinalityState, - txidOrHash: input.txidOrHash ?? previous.txidOrHash ?? undefined, - confirmations: input.confirmations, - outputIndex: input.outputIndex, - anchoredAt: input.issuedAt, - }); - } - default: - throw new Error( - `Unsupported AssetPack ledger anchor action: ${(input as { action: string }).action}.`, - ); - } -} - -function buildAssetPackExchangeForAction(input: BtdAssetPackExchangeInput): { - order?: AssetPackExchangeOrder; - rightsTransfer?: AssetPackRightsTransferReceipt; - exchangeSequence: bigint; -} { - switch (input.action) { - case 'create_order': { - if (!input.orderId) throw new Error('AssetPack Exchange order creation requires orderId.'); - if (!input.orderKind) { - throw new Error('AssetPack Exchange order creation requires orderKind.'); - } - if (!input.assetPackId) { - throw new Error('AssetPack Exchange order creation requires assetPackId.'); - } - if (input.rangeStart === undefined || input.rangeEndExclusive === undefined) { - throw new Error('AssetPack Exchange order creation requires range bounds.'); - } - if (!input.makerWalletId) { - throw new Error('AssetPack Exchange order creation requires makerWalletId.'); - } - if (input.priceSats === undefined) { - throw new Error('AssetPack Exchange order creation requires priceSats.'); - } - if (!input.accessPolicyHash) { - throw new Error('AssetPack Exchange order creation requires accessPolicyHash.'); - } - if (typeof input.createdAtExchangeSequence !== 'bigint') { - throw new Error('AssetPack Exchange order creation requires createdAtExchangeSequence.'); - } - - const order = createAssetPackExchangeOrder({ - orderId: input.orderId, - orderKind: input.orderKind, - assetPackId: input.assetPackId, - rangeStart: input.rangeStart, - rangeEndExclusive: input.rangeEndExclusive, - makerWalletId: input.makerWalletId, - priceSats: input.priceSats, - accessPolicyHash: input.accessPolicyHash, - createdAtExchangeSequence: input.createdAtExchangeSequence, - }); - return { order, exchangeSequence: order.createdAtExchangeSequence }; - } - case 'cancel_order': { - const order = cancelAssetPackExchangeOrder( - normalizeAssetPackExchangeOrder(input.previousOrder), - ); - return { order, exchangeSequence: order.createdAtExchangeSequence }; - } - case 'accept_order': { - if (!input.takerWalletId) { - throw new Error('AssetPack Exchange order acceptance requires takerWalletId.'); - } - const order = acceptAssetPackExchangeOrder( - normalizeAssetPackExchangeOrder(input.previousOrder), - input.takerWalletId, - ); - return { order, exchangeSequence: order.createdAtExchangeSequence }; - } - case 'settle_order': { - if (typeof input.settledAtExchangeSequence !== 'bigint') { - throw new Error('AssetPack Exchange order settlement requires settledAtExchangeSequence.'); - } - const order = settleAssetPackExchangeOrder( - normalizeAssetPackExchangeOrder(input.previousOrder), - { - settledAtExchangeSequence: input.settledAtExchangeSequence, - ledgerAnchorId: input.ledgerAnchorId, - }, - ); - return { order, exchangeSequence: input.settledAtExchangeSequence }; - } - case 'transfer_rights': { - if (!input.receiptId) { - throw new Error('AssetPack rights transfer requires receiptId.'); - } - if (!input.fromWalletId || !input.toWalletId) { - throw new Error('AssetPack rights transfer requires fromWalletId and toWalletId.'); - } - if (!input.btcFeeReceiptId) { - throw new Error('AssetPack rights transfer requires btcFeeReceiptId.'); - } - - const rightsTransfer = buildAssetPackRightsTransferReceipt({ - receiptId: input.receiptId, - settledOrder: normalizeAssetPackExchangeOrder(input.previousOrder), - fromWalletId: input.fromWalletId, - toWalletId: input.toWalletId, - btcFeeReceiptId: input.btcFeeReceiptId, - issuedAt: input.issuedAt, - }); - return { rightsTransfer, exchangeSequence: rightsTransfer.exchangeSequence }; - } - default: - throw new Error( - `Unsupported AssetPack Exchange action: ${(input as { action: string }).action}.`, - ); - } -} - -function normalizeWalletSignerSession( - session: WalletSignerSession | BtdWalletSignerSessionInput, -): WalletSignerSession { - if ('serverCustody' in session && 'state' in session) { - return session; - } - - return createWalletSignerSession(session); -} - -function normalizeBtcFeeTransactionReceipt( - receipt: BtcFeeTransactionReceipt | undefined, -): BtcFeeTransactionReceipt { - if (!receipt) { - throw new Error('BTC fee transition requires previousReceipt.'); - } - - return assertBtcFeeTransactionReceipt({ - ...receipt, - satsPaid: BigInt(receipt.satsPaid), - exchangeSequence: BigInt(receipt.exchangeSequence), - serverCustody: false, - }); -} - -function normalizeBtcFeeQuote(quote: BtcFeeQuote | undefined): BtcFeeQuote | undefined { - if (!quote) { - return undefined; - } - - return assertBtcFeeQuote({ - ...quote, - sats: BigInt(quote.sats), - }); -} - -function normalizeAssetPackLedgerAnchor( - anchor: AssetPackLedgerAnchor | undefined, -): AssetPackLedgerAnchor { - if (!anchor) { - throw new Error('AssetPack ledger anchor transition requires previousAnchor.'); - } - - return assertAssetPackLedgerAnchor(anchor); -} - -function normalizeAssetPackExchangeOrder( - order: AssetPackExchangeOrder | undefined, -): AssetPackExchangeOrder { - if (!order) { - throw new Error('AssetPack Exchange transition requires previousOrder.'); - } - - return { - ...order, - priceSats: BigInt(order.priceSats), - createdAtExchangeSequence: BigInt(order.createdAtExchangeSequence), - settledAtExchangeSequence: - order.settledAtExchangeSequence === undefined - ? undefined - : BigInt(order.settledAtExchangeSequence), - }; -} - -function normalizeTerminalJournalEntry(entry: TerminalJournalEntry | undefined): TerminalJournalEntry { - if (!entry) { - throw new Error('Terminal journal action requires entry.'); - } - - return buildTerminalJournalEntry({ - ...entry, - exchangeSequence: BigInt(entry.exchangeSequence), - }); -} - -function requireTerminalTransactionKind( - kind: TerminalTransactionKind | undefined, -): TerminalTransactionKind { - if (!kind) { - throw new Error('Terminal journal entry requires transactionKind.'); - } - - return kind; -} - -function requireBigInt(value: bigint | undefined, label: string): bigint { - if (typeof value !== 'bigint') { - throw new Error(`${label} must be a bigint.`); - } - - return value; -} - -function stableId(prefix: string, parts: string[]): string { - const hash = createHash('sha256').update(parts.join('\u001f')).digest('hex').slice(0, 16); - return `${prefix}_${hash}`; -} - function toBadRequestMessage(error: unknown): string { - return error instanceof Error ? error.message : 'Invalid V27 BTD mint draft input'; + return error instanceof Error ? error.message : 'Invalid BTD route input'; } function toRevenueRegistryRow( @@ -2401,24 +985,3 @@ function readConfidentiality(row: Record): BtdAccessPolicy['con return 'public_proof_private_source'; } - -function toJsonSafe(value: unknown): unknown { - if (typeof value === 'bigint') { - return value.toString(); - } - - if (Array.isArray(value)) { - return value.map((entry) => toJsonSafe(entry)); - } - - if (value && typeof value === 'object') { - return Object.fromEntries( - Object.entries(value as Record).map(([key, entry]) => [ - key, - toJsonSafe(entry), - ]), - ); - } - - return value; -} diff --git a/packages/btd/README.md b/packages/btd/README.md index 5e6e3fc2c..e0d524ed0 100644 --- a/packages/btd/README.md +++ b/packages/btd/README.md @@ -14,6 +14,9 @@ This package owns: - Terminal operational health reads that compose deployment lanes, telemetry, upgrade posture, provider readiness, settlement-network posture, synthetic testnet minting, journal rows, ledger anchors, and reconciliation state +- `api-boundaries.ts`, the framework-agnostic BTD API boundary for shared route + objects, BigInt parsers, validators, settlement builders, registry snapshot + builders, read-access decision builders, and JSON-safe serialization `$BTD` is not a fungible fee token. BTC pays fees. `$BTD` represents a non-fungible AssetPack share/read-right and the measured Bitcode amount in @@ -30,6 +33,9 @@ import { buildGenerationBitcodeAccounting, BTD_MAX_MINTABLE_SUPPLY, applyBtdMeasureMint, + buildBtdMintDraft, + buildBtdRegistrySnapshot, + toBtdJsonSafe, calculateLlmBtcFeeEstimate, buildLicensedReadRevenueRoute, getBtdBalance, @@ -38,6 +44,12 @@ import { } from '@bitcode/btd'; ``` +Accepted imports point into `@bitcode/btd` or the documented +`@bitcode/btd/terminal-operational-health` subpath. API routes, Terminal, MCP, +ChatGPT App, Auxillaries, and Exchange must not copy BTD admission, receipt, +settlement, parser, validator, or serializer logic locally when this package +exports the boundary object. + Terminal should consume the operational-health subpath when it needs the client-safe read model without importing storage-backed package entry points: diff --git a/packages/btd/__tests__/api-boundaries.test.ts b/packages/btd/__tests__/api-boundaries.test.ts new file mode 100644 index 000000000..262861cc4 --- /dev/null +++ b/packages/btd/__tests__/api-boundaries.test.ts @@ -0,0 +1,122 @@ +import { + buildBtdMintDraft, + buildBtdReadAccessDecision, + buildBtdRegistrySnapshot, + createBtdMeasureMintState, + parseBtdOptionalBigInt, + parseBtdRequiredBigInt, + toBtdJsonSafe, +} from '../src'; + +const issuedAt = '2026-05-06T00:00:00.000Z'; + +describe('BTD API boundaries', () => { + it('builds package-owned mint drafts for route callers', () => { + const draft = buildBtdMintDraft({ + assetPackId: 'asset-pack-boundary-1', + readId: 'read-boundary-1', + acceptedNeed: true, + acceptedFit: true, + sourceManifestRoot: 'source-root-boundary', + fitReceiptRoot: 'fit-root-boundary', + proofRoot: 'proof-root-boundary', + dedupeReceiptRoot: 'dedupe-root-boundary', + settlementJournalRoot: 'settlement-root-boundary', + exchangeReceiptRoot: 'exchange-root-boundary', + accessPolicyId: 'policy-boundary-1', + accessPolicyHash: 'policy-boundary-hash', + semanticUnits: [ + { + unitId: 'unit-boundary-1', + proofReceiptRoot: 'proof-boundary-1', + dedupeReceiptRoot: 'dedupe-boundary-1', + fitAccepted: true, + normalizedUnits: 10_000n, + }, + ], + measureMintState: createBtdMeasureMintState({ curveParameter: 10_000n }), + exchangeSequence: 1n, + actorId: 'actor-boundary-1', + issuedAt, + }); + + expect(draft.kind).toBe('btd_mint_draft'); + expect(draft.measureMint.tokenCount).toBe(10_500_000); + expect(draft.terminalJournalEntry.transactionKind).toBe('asset_pack_mint'); + expect(draft.terminalJournalEntry.actorId).toBe('actor-boundary-1'); + }); + + it('keeps route BigInt parsing and JSON-safe serialization in the package', () => { + expect(parseBtdRequiredBigInt('42', 'exchangeSequence')).toBe(42n); + expect(parseBtdRequiredBigInt(42, 'exchangeSequence')).toBe(42n); + expect(parseBtdOptionalBigInt(null, 'exchangeSequence')).toBeUndefined(); + expect(() => parseBtdRequiredBigInt(1.25, 'exchangeSequence')).toThrow( + 'exchangeSequence must be a safe integer when supplied as a number.', + ); + + expect(toBtdJsonSafe({ count: 42n, nested: [{ value: 7n }] })).toEqual({ + count: '42', + nested: [{ value: '7' }], + }); + }); + + it('builds registry snapshots without API route policy derivation', async () => { + const snapshot = await buildBtdRegistrySnapshot({ + assetPackId: 'asset-pack-boundary-1', + registry: { + getSupplyState: async () => ({ total_minted: '10' }), + listAssetPackRanges: async (assetPackId?: string) => [ + { asset_pack_id: assetPackId, range_start: 0, range_end_exclusive: 10 }, + ], + }, + }); + + expect(snapshot.kind).toBe('btd_registry_snapshot'); + expect(snapshot.activeCanonicalPointer).toBe('V29'); + expect(snapshot.draftTargetVersion).toBe('V30'); + expect(snapshot.routePosture).toMatchObject({ + canonicalUnit: 'asset_pack_range', + feeAsset: 'BTC', + btdSpendableAsFee: false, + }); + expect(snapshot.ranges).toEqual([ + { + asset_pack_id: 'asset-pack-boundary-1', + range_start: 0, + range_end_exclusive: 10, + }, + ]); + }); + + it('returns package-owned read-access decisions for API route callers', () => { + const decision = buildBtdReadAccessDecision({ + actorId: 'actor-boundary-1', + walletId: 'wallet-boundary-reader', + assetPackId: 'asset-pack-boundary-1', + accessPolicy: { + accessPolicyId: 'policy-boundary-1', + accessPolicyHash: 'policy-boundary-hash', + ownerRead: true, + licensedRead: true, + derivativeUse: false, + redistributionAllowed: false, + confidentiality: 'public_proof_private_source', + }, + licenses: [ + { + licenseId: 'license-boundary-1', + walletId: 'wallet-boundary-reader', + assetPackId: 'asset-pack-boundary-1', + accessPolicyHash: 'policy-boundary-hash', + validFrom: '2026-05-01T00:00:00.000Z', + expiresAt: '2026-05-07T00:00:00.000Z', + }, + ], + at: issuedAt, + }); + + expect(decision.kind).toBe('btd_read_access_decision'); + expect(decision.decision.decision).toBe('licensed_read'); + expect(decision.policyDisclosure.accessPolicyHash).toBe('policy-boundary-hash'); + }); +}); diff --git a/packages/btd/src/api-boundaries.ts b/packages/btd/src/api-boundaries.ts new file mode 100644 index 000000000..4c61a214f --- /dev/null +++ b/packages/btd/src/api-boundaries.ts @@ -0,0 +1,1575 @@ +import { createHash } from 'crypto'; +import type { + BtdAccessPolicy, + BtdOwnershipClaim, + BtdReadLicense, +} from './access'; +import { evaluateBtdReadAccess } from './access'; +import type { BtdContributorMeasure } from './allocation'; +import { allocateBtdContributorCells } from './allocation'; +import type { + BtdAncestorEdgeInput, + BtdAncestorGraphEdge, +} from './ancestry'; +import { reviewBtdAncestorEdges } from './ancestry'; +import type { + BtdInterfaceAuthoritySurface, + BtdOrganizationPermissionAction, + BtdOrganizationRole, + BtdRepairApprovalState, + BtdSettlementAuthorityState, +} from './authority'; +import { evaluateBtdOrganizationInterfaceAuthority } from './authority'; +import type { + BtcFeeFinalityState, + BtcFeePurpose, + BtcFeeTransactionReceipt, +} from './bitcoin-fees'; +import { + advanceBtcFeeTransactionReceipt, + assertBtcFeeTransactionReceipt, + buildPreparedBtcFeeTransactionReceipt, +} from './bitcoin-fees'; +import type { + BtcFeeOperationPosture, + BtcFeeQuote, +} from './btc-fee-operation'; +import { + assertBtcFeeQuote, + assertBtcFeeQuoteActive, + buildBtcFeeOperationPosture, +} from './btc-fee-operation'; +import type { + BitcoinNetwork, + LedgerNetwork, +} from './constants'; +import { + BTD_MAX_MINTABLE_SUPPLY, + assertNonEmptyString, +} from './constants'; +import type { V27CryptoDeploymentLaneKind } from './deployment-lanes'; +import { + buildV27CryptoDeploymentLane, + buildV27CryptoDeploymentReadinessReceipt, +} from './deployment-lanes'; +import type { + AssetPackExchangeOrder, + AssetPackExchangeOrderKind, + AssetPackRightsTransferReceipt, +} from './exchange'; +import { + acceptAssetPackExchangeOrder, + buildAssetPackRightsTransferReceipt, + cancelAssetPackExchangeOrder, + createAssetPackExchangeOrder, + settleAssetPackExchangeOrder, +} from './exchange'; +import type { + AssetPackLedgerAnchor, + LedgerFinalityState, +} from './ledger-anchor'; +import { + advanceAssetPackLedgerAnchor, + assertAssetPackLedgerAnchor, + buildPreparedAssetPackLedgerAnchor, +} from './ledger-anchor'; +import type { BtdMeasureMintState } from './measuremint'; +import { + applyBtdMeasureMint, + createBtdMeasureMintState, +} from './measuremint'; +import { allocateAssetPackRange } from './range'; +import { buildBtdMintReceipt } from './receipts'; +import type { + DatabaseProjectedFact, + LedgerObservedFact, + MetaphysicalCanonicalFact, + ProjectionRepairReceipt, +} from './reconciliation'; +import { reconcileLedgerDatabaseProjection } from './reconciliation'; +import type { + BtdRevenueRecipientInput, + BtdRevenueRouteException, +} from './revenue'; +import { + assertLicensedReadRevenueRouteConserved, + buildLicensedReadRevenueRoute, +} from './revenue'; +import type { SemanticVolumeUnitInput } from './semantic-volume'; +import { measureProofAddressableSemanticVolume } from './semantic-volume'; +import { createBtdSupplyState } from './supply'; +import type { + V27CryptoTelemetryEvent, + V27CryptoTelemetryRecord, +} from './telemetry'; +import { buildV27CryptoTelemetryRecord } from './telemetry'; +import type { + TerminalJournalEntry, + TerminalJournalProjection, + TerminalTransactionKind, +} from './terminal-journal'; +import { + buildTerminalJournalCoverageReceipt, + buildTerminalJournalEntry, + diffTerminalJournalProjection, +} from './terminal-journal'; +import type { + BtdProtocolUpgradeReceipt, + BtdProtocolUpgradeState, +} from './upgrade'; +import { + advanceBtdProtocolUpgradeReceipt, + buildPlannedBtdProtocolUpgradeReceipt, +} from './upgrade'; +import type { WalletSignerSession } from './wallet'; +import { createWalletSignerSession } from './wallet'; + +export interface BtdRegistrySnapshotReader { + getSupplyState(): Promise; + listAssetPackRanges(assetPackId?: string): Promise; +} + +export interface BtdMintDraftInput { + assetPackId: string; + readId: string; + acceptedNeed: true; + acceptedFit: true; + sourceManifestRoot: string; + fitReceiptRoot: string; + proofRoot: string; + dedupeReceiptRoot: string; + settlementJournalRoot: string; + exchangeReceiptRoot: string; + accessPolicyId: string; + accessPolicyHash: string; + semanticUnits: SemanticVolumeUnitInput[]; + contributors?: BtdContributorMeasure[]; + measureMintState?: BtdMeasureMintState; + exchangeSequence: bigint; + actorId?: string; + issuedAt?: string; +} + +export interface BtdMintDraft { + kind: 'btd_mint_draft'; + assetPackId: string; + measurement: ReturnType; + measureMint: ReturnType['receipt']; + rangeAllocation?: ReturnType; + mintReceipt?: ReturnType; + contributorAllocation?: ReturnType; + terminalJournalEntry: ReturnType; + blocking: boolean; + zeroCell: boolean; +} + +export interface BtdReadAccessInput { + walletId: string; + assetPackId: string; + accessPolicy: BtdAccessPolicy; + ownershipClaims?: BtdOwnershipClaim[]; + licenses?: BtdReadLicense[]; + at?: string; +} + +export interface BtdReadAccessDecision { + kind: 'btd_read_access_decision'; + actorId: string; + assetPackId: string; + decision: ReturnType; + policyDisclosure: { + accessPolicyId: string; + accessPolicyHash: string; + ownerRead: boolean; + licensedRead: boolean; + derivativeUse: boolean; + redistributionAllowed: boolean; + confidentiality: BtdAccessPolicy['confidentiality']; + }; +} + +export interface BtdOrganizationInterfaceAuthorityRouteInput { + organizationId: string; + organizationRole?: BtdOrganizationRole | null; + organizationPermissionGrants?: string[]; + interfaceSurface: BtdInterfaceAuthoritySurface; + action: BtdOrganizationPermissionAction; + walletId?: string | null; + readAccessDecision?: ReturnType | null; + settlementState?: BtdSettlementAuthorityState; + confirmed?: boolean; + repairApprovalState?: BtdRepairApprovalState; + targetAnchor?: string | null; + at?: string; +} + +export type BtdOrganizationInterfaceAuthorityRouteDecision = ReturnType< + typeof evaluateBtdOrganizationInterfaceAuthority +> & { + routeKind: 'btd_organization_interface_authority_route_decision'; +}; + +export interface BtdLicensedReadRevenueInput { + paymentId: string; + assetPackId: string; + grossSats: bigint | number | string; + directRecipients: BtdRevenueRecipientInput[]; + ancestorRecipients?: BtdRevenueRecipientInput[]; + treasuryWalletId: string; + disputeHoldbackWalletId?: string; + exchangeSequence: bigint; + directSplitBps?: number; + ancestorSplitBps?: number; + treasurySplitBps?: number; + disputeHoldbackBps?: number; + pendingRoutes?: BtdRevenueRouteException[]; + failedRoutes?: BtdRevenueRouteException[]; + commitToRegistry?: boolean; + actorId?: string; + issuedAt?: string; +} + +export interface BtdAncestryReviewInput { + reviewId?: string; + childAssetPackId: string; + edges: BtdAncestorEdgeInput[]; + existingEdges?: BtdAncestorGraphEdge[]; + duplicateSourceRoots?: string[]; + minConfidenceBps?: number; + citationOnlyPayable?: boolean; + exchangeSequence: bigint; + commitToRegistry?: boolean; + actorId?: string; + issuedAt?: string; +} + +export type BtdBtcFeeTransactionAction = + | 'prepare' + | 'mark_signed' + | 'mark_broadcast' + | 'observe'; + +export type BtdWalletSignerSessionInput = Parameters[0]; + +export interface BtdBtcFeeTransactionInput { + action: BtdBtcFeeTransactionAction; + receiptId?: string; + feePurpose?: BtcFeePurpose; + payerSession?: WalletSignerSession | BtdWalletSignerSessionInput; + psbt?: string; + signedPsbt?: string; + satsPaid?: bigint | number | string; + satsPerVbyte?: number; + exchangeSequence?: bigint; + terminalJournalRoot?: string; + relatedAssetPackId?: string; + relatedOrderId?: string; + previousReceipt?: BtcFeeTransactionReceipt; + feeQuote?: BtcFeeQuote; + txid?: string; + vout?: number; + observedFinalityState?: Exclude; + confirmations?: number; + commitToRegistry?: boolean; + actorId?: string; + issuedAt?: string; +} + +export type BtdAssetPackLedgerAnchorAction = 'prepare' | 'mark_broadcast' | 'observe'; + +export interface BtdAssetPackLedgerAnchorInput { + action: BtdAssetPackLedgerAnchorAction; + anchorId?: string; + assetPackId?: string; + chain?: AssetPackLedgerAnchor['chain']; + network?: AssetPackLedgerAnchor['network']; + commitmentMethod?: AssetPackLedgerAnchor['commitmentMethod']; + commitmentRoot?: string; + sourceManifestRoot?: string; + proofRoot?: string; + accessPolicyHash?: string; + btdRangeStart?: number; + btdRangeEndExclusive?: number; + contractAddress?: string; + tokenId?: string; + previousAnchor?: AssetPackLedgerAnchor; + txidOrHash?: string; + outputIndex?: number; + observedFinalityState?: Exclude; + confirmations?: number; + exchangeSequence: bigint; + commitToRegistry?: boolean; + actorId?: string; + issuedAt?: string; +} + +export type BtdAssetPackExchangeAction = + | 'create_order' + | 'cancel_order' + | 'accept_order' + | 'settle_order' + | 'transfer_rights'; + +export type BtdTerminalJournalAction = 'commit_entry' | 'diff_projection' | 'coverage'; + +export interface BtdAssetPackExchangeInput { + action: BtdAssetPackExchangeAction; + orderId?: string; + orderKind?: AssetPackExchangeOrderKind; + assetPackId?: string; + rangeStart?: number; + rangeEndExclusive?: number; + makerWalletId?: string; + takerWalletId?: string; + priceSats?: bigint | number | string; + accessPolicyHash?: string; + createdAtExchangeSequence?: bigint; + previousOrder?: AssetPackExchangeOrder; + settledAtExchangeSequence?: bigint; + ledgerAnchorId?: string; + receiptId?: string; + fromWalletId?: string; + toWalletId?: string; + btcFeeReceiptId?: string; + commitToRegistry?: boolean; + actorId?: string; + issuedAt?: string; +} + +export interface BtdTerminalJournalInput { + action: BtdTerminalJournalAction; + journalEntryId?: string; + transactionKind?: TerminalTransactionKind; + preStateRoot?: string; + postStateRoot?: string; + receiptRoots?: string[]; + ledgerAnchorIds?: string[]; + exchangeSequence?: bigint; + entry?: TerminalJournalEntry; + projection?: TerminalJournalProjection; + coverageId?: string; + entries?: TerminalJournalEntry[]; + commitToRegistry?: boolean; + actorId?: string; + issuedAt?: string; +} + +export interface BtdLedgerDatabaseReconciliationInput { + reconciliationId: string; + ledgerFacts: LedgerObservedFact[]; + databaseFacts: DatabaseProjectedFact[]; + metaphysicalFacts?: MetaphysicalCanonicalFact[]; + settlementConservationChecks?: Parameters[0]['settlementConservationChecks']; + commitToRegistry?: boolean; + actorId?: string; + issuedAt?: string; +} + +export type BtdDeploymentReadinessAction = + | 'deployment_lane' + | 'telemetry_event' + | 'upgrade_plan' + | 'upgrade_transition'; + +export interface BtdDeploymentReadinessInput { + action: BtdDeploymentReadinessAction; + readinessId?: string; + lane?: V27CryptoDeploymentLaneKind; + bitcoinNetwork?: BitcoinNetwork; + ledgerNetwork?: LedgerNetwork; + rollbackPlanRoot?: string; + operationalApprovalRoot?: string; + presentEnvironmentKeys?: string[]; + telemetryEvent?: V27CryptoTelemetryEvent; + telemetrySubjectId?: string; + telemetryReceiptRoot?: string; + telemetryLedgerAnchorId?: string; + upgradeId?: string; + fromVersion?: string; + toVersion?: string; + migrationRoot?: string; + preStateRoot?: string; + postStateRoot?: string; + approvalReceiptRoot?: string; + previousUpgradeReceipt?: BtdProtocolUpgradeReceipt; + nextUpgradeState?: Exclude; + ledgerAnchorId?: string; + commitToRegistry?: boolean; + actorId?: string; + issuedAt?: string; +} + +export interface BtdLicensedReadRevenueSettlement { + kind: 'btd_licensed_read_revenue_settlement'; + actorId: string; + receipt: ReturnType; + terminalJournalEntry: ReturnType; + registryWrite?: unknown; + committed: boolean; +} + +export interface BtdAncestryReviewSettlement { + kind: 'btd_ancestry_review_settlement'; + actorId: string; + receipt: ReturnType; + terminalJournalEntry: ReturnType; + registryWrites?: unknown[]; + committed: boolean; +} + +export interface BtdBtcFeeTransactionSettlement { + kind: 'btd_btc_fee_transaction_settlement'; + actorId: string; + action: BtdBtcFeeTransactionAction; + receipt: BtcFeeTransactionReceipt; + operationPosture: BtcFeeOperationPosture; + terminalJournalEntry: ReturnType; + registryWrite?: unknown; + committed: boolean; +} + +export interface BtdAssetPackLedgerAnchorSettlement { + kind: 'btd_asset_pack_ledger_anchor_settlement'; + actorId: string; + action: BtdAssetPackLedgerAnchorAction; + anchor: AssetPackLedgerAnchor; + terminalJournalEntry: ReturnType; + registryWrite?: unknown; + committed: boolean; +} + +export interface BtdAssetPackExchangeSettlement { + kind: 'btd_asset_pack_exchange_settlement'; + actorId: string; + action: BtdAssetPackExchangeAction; + order?: AssetPackExchangeOrder; + rightsTransfer?: AssetPackRightsTransferReceipt; + terminalJournalEntry: ReturnType; + registryWrite?: unknown; + committed: boolean; +} + +export interface BtdTerminalJournalSettlement { + kind: 'btd_terminal_journal_settlement'; + actorId: string; + action: BtdTerminalJournalAction; + entry?: TerminalJournalEntry; + diff?: ReturnType; + coverage?: ReturnType; + registryWrite?: unknown; + committed: boolean; +} + +export interface BtdLedgerDatabaseReconciliationSettlement { + kind: 'btd_ledger_database_reconciliation_settlement'; + actorId: string; + report: ReturnType; + terminalJournalEntry: ReturnType; + registryWrites?: unknown[]; + committed: boolean; +} + +export interface BtdDeploymentReadinessSettlement { + kind: 'btd_deployment_readiness_settlement'; + actorId: string; + action: BtdDeploymentReadinessAction; + readiness?: ReturnType; + telemetry?: V27CryptoTelemetryRecord; + upgradeReceipt?: BtdProtocolUpgradeReceipt; + registryWrite?: unknown; + committed: boolean; +} + +export function buildBtdStableId(prefix: string, parts: string[]): string { + const hash = createHash('sha256').update(parts.join('\u001f')).digest('hex').slice(0, 16); + return `${prefix}_${hash}`; +} + +export function parseBtdRequiredBigInt(value: unknown, label: string): bigint { + if (typeof value === 'bigint') return value; + if (typeof value === 'number') { + if (!Number.isSafeInteger(value)) { + throw new Error(`${label} must be a safe integer when supplied as a number.`); + } + return BigInt(value); + } + if (typeof value === 'string' && /^-?\d+$/.test(value)) return BigInt(value); + throw new Error(`${label} must be an integer string, safe integer number, or bigint.`); +} + +export function parseBtdOptionalBigInt(value: unknown, label: string): bigint | undefined { + return value === undefined || value === null ? undefined : parseBtdRequiredBigInt(value, label); +} + +export async function buildBtdRegistrySnapshot(input: { + registry: BtdRegistrySnapshotReader; + assetPackId?: string | null; + activeCanonicalPointer?: string; + draftTargetVersion?: string; +}) { + const [supplyState, ranges] = await Promise.all([ + input.registry.getSupplyState(), + input.registry.listAssetPackRanges(input.assetPackId || undefined), + ]); + + return { + kind: 'btd_registry_snapshot', + activeCanonicalPointer: input.activeCanonicalPointer ?? 'V29', + draftTargetVersion: input.draftTargetVersion ?? 'V30', + maxSupply: BTD_MAX_MINTABLE_SUPPLY, + supplyState, + ranges, + routePosture: { + canonicalUnit: 'asset_pack_range', + feeAsset: 'BTC', + btdSpendableAsFee: false, + valueBearingMainnetRequiresOperationalApproval: true, + }, + }; +} + +export function buildBtdMintDraft(input: BtdMintDraftInput): BtdMintDraft { + assertMintDraftAdmission(input); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const measurementId = buildBtdStableId('btd-semantic-volume', [ + input.assetPackId, + input.readId, + input.semanticUnits.map((unit) => `${unit.unitId}:${unit.proofReceiptRoot}`).join('|'), + ]); + const measurement = measureProofAddressableSemanticVolume({ + measurementId, + assetPackId: input.assetPackId, + units: input.semanticUnits, + issuedAt, + }); + const measureMint = applyBtdMeasureMint({ + state: normalizeMeasureMintState(input.measureMintState), + assetPackId: input.assetPackId, + semanticVolume: measurement, + proofRoot: input.proofRoot, + settlementJournalRoot: input.settlementJournalRoot, + accessPolicyHash: input.accessPolicyHash, + exchangeSequence: input.exchangeSequence, + issuedAt, + }); + + const rangeAllocation = + measureMint.receipt.tokenCount > 0 + ? allocateAssetPackRange( + createBtdSupplyState({ + totalMinted: measureMint.receipt.totalMintedBefore, + nextTokenId: measureMint.receipt.totalMintedBefore, + cumulativeAdmittedMeasurement: measureMint.receipt.cumulativeMeasurementBefore, + residualMintCredit: measureMint.previousState.residualMintCredit, + curveParameter: measureMint.previousState.curveParameter, + }), + { + assetPackId: input.assetPackId, + readId: input.readId, + acceptedNeed: input.acceptedNeed, + acceptedFit: input.acceptedFit, + sourceManifestRoot: input.sourceManifestRoot, + measurementReceiptRoot: measurement.measurementId, + fitReceiptRoot: input.fitReceiptRoot, + proofRoot: input.proofRoot, + dedupeReceiptRoot: input.dedupeReceiptRoot, + settlementJournalRoot: input.settlementJournalRoot, + exchangeReceiptRoot: input.exchangeReceiptRoot, + accessPolicyId: input.accessPolicyId, + accessPolicyHash: input.accessPolicyHash, + normalizedBitcodeVolume: measurement.normalizedBitcodeVolume, + tokenCount: measureMint.receipt.tokenCount, + mintedAtExchangeSequence: input.exchangeSequence, + }, + ) + : undefined; + const mintReceipt = rangeAllocation ? buildBtdMintReceipt(rangeAllocation, issuedAt) : undefined; + const contributorAllocation = + rangeAllocation && input.contributors?.length + ? allocateBtdContributorCells({ + assetPackId: input.assetPackId, + rangeStart: rangeAllocation.range.rangeStart, + rangeEndExclusive: rangeAllocation.range.rangeEndExclusive, + contributors: input.contributors, + issuedAt, + }) + : undefined; + const receiptRoots = [ + measurement.measurementId, + buildBtdStableId('btd-measure-mint', [input.assetPackId, input.exchangeSequence.toString()]), + mintReceipt ? buildBtdStableId('btd-asset-pack-mint', [input.assetPackId, mintReceipt.issuedAt]) : null, + contributorAllocation + ? buildBtdStableId('btd-contributor-allocation', [input.assetPackId, contributorAllocation.issuedAt]) + : null, + ].filter((value): value is string => Boolean(value)); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-mint-draft', [ + input.assetPackId, + input.exchangeSequence.toString(), + ]), + transactionKind: measureMint.receipt.tokenCount > 0 ? 'asset_pack_mint' : 'measure_mint_tail', + actorId: input.actorId ?? 'system:btd-mint-draft', + preStateRoot: buildBtdStableId('btd-pre-state', [measureMint.receipt.totalMintedBefore.toString()]), + postStateRoot: buildBtdStableId('btd-post-state', [ + measureMint.receipt.totalMintedAfter.toString(), + measureMint.receipt.cumulativeMeasurementAfter.toString(), + ]), + receiptRoots, + ledgerAnchorIds: [], + exchangeSequence: input.exchangeSequence, + issuedAt, + }); + + return { + kind: 'btd_mint_draft', + assetPackId: input.assetPackId, + measurement, + measureMint: measureMint.receipt, + rangeAllocation, + mintReceipt, + contributorAllocation, + terminalJournalEntry, + blocking: false, + zeroCell: measureMint.receipt.tokenCount === 0, + }; +} + +export function assertBtdMintDraft(draft: BtdMintDraft): BtdMintDraft { + if (draft.kind !== 'btd_mint_draft') { + throw new Error('Invalid BTD mint draft kind.'); + } + assertNonEmptyString(draft.assetPackId, 'assetPackId'); + if (!draft.measurement || draft.measurement.kind !== 'btd.semantic_volume_measurement') { + throw new Error('BTD mint draft requires a semantic-volume measurement receipt.'); + } + if (!draft.measureMint || draft.measureMint.kind !== 'btd.measure_mint') { + throw new Error('BTD mint draft requires a measuremint receipt.'); + } + if (!draft.terminalJournalEntry?.journalEntryId) { + throw new Error('BTD mint draft requires a terminal journal entry.'); + } + return draft; +} + +export function buildBtdReadAccessDecision( + input: BtdReadAccessInput & { actorId: string }, +): BtdReadAccessDecision { + assertNonEmptyString(input.actorId, 'actorId'); + assertNonEmptyString(input.walletId, 'walletId'); + assertNonEmptyString(input.assetPackId, 'assetPackId'); + const decision = evaluateBtdReadAccess(input); + + return { + kind: 'btd_read_access_decision', + actorId: input.actorId, + assetPackId: input.assetPackId, + decision, + policyDisclosure: { + accessPolicyId: input.accessPolicy.accessPolicyId, + accessPolicyHash: input.accessPolicy.accessPolicyHash, + ownerRead: input.accessPolicy.ownerRead, + licensedRead: input.accessPolicy.licensedRead, + derivativeUse: input.accessPolicy.derivativeUse, + redistributionAllowed: input.accessPolicy.redistributionAllowed, + confidentiality: input.accessPolicy.confidentiality, + }, + }; +} + +export function buildBtdOrganizationInterfaceAuthorityDecision( + input: BtdOrganizationInterfaceAuthorityRouteInput & { actorId: string }, +): BtdOrganizationInterfaceAuthorityRouteDecision { + const decision = evaluateBtdOrganizationInterfaceAuthority({ + ...input, + actorId: assertNonEmptyString(input.actorId, 'actorId'), + }); + + return { + ...decision, + routeKind: 'btd_organization_interface_authority_route_decision', + }; +} + +export function buildBtdLicensedReadRevenueSettlement( + input: BtdLicensedReadRevenueInput & { actorId: string }, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + const receipt = assertLicensedReadRevenueRouteConserved( + buildLicensedReadRevenueRoute({ + paymentId: input.paymentId, + assetPackId: input.assetPackId, + grossSats: input.grossSats, + directRecipients: input.directRecipients, + ancestorRecipients: input.ancestorRecipients, + treasuryWalletId: input.treasuryWalletId, + disputeHoldbackWalletId: input.disputeHoldbackWalletId, + exchangeSequence: input.exchangeSequence, + directSplitBps: input.directSplitBps, + ancestorSplitBps: input.ancestorSplitBps, + treasurySplitBps: input.treasurySplitBps, + disputeHoldbackBps: input.disputeHoldbackBps, + pendingRoutes: input.pendingRoutes, + failedRoutes: input.failedRoutes, + issuedAt: input.issuedAt, + }), + ); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-licensed-read-revenue', [ + receipt.assetPackId, + receipt.paymentId, + receipt.exchangeSequence.toString(), + ]), + transactionKind: 'settlement_finalization', + actorId, + preStateRoot: buildBtdStableId('btd-revenue-pre-state', [receipt.paymentId]), + postStateRoot: buildBtdStableId('btd-revenue-post-state', [ + receipt.paymentId, + receipt.grossSats.toString(), + receipt.routeState, + ]), + receiptRoots: [ + buildBtdStableId('btd-licensed-read-revenue-route', [ + receipt.assetPackId, + receipt.paymentId, + receipt.issuedAt, + ]), + ], + ledgerAnchorIds: [], + exchangeSequence: receipt.exchangeSequence, + issuedAt: receipt.issuedAt, + }); + + return { + kind: 'btd_licensed_read_revenue_settlement', + actorId, + receipt, + terminalJournalEntry, + }; +} + +export function buildBtdAncestryReviewSettlement( + input: BtdAncestryReviewInput & { actorId: string }, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + assertNonEmptyString(input.childAssetPackId, 'childAssetPackId'); + if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { + throw new Error('BTD ancestry review requires a positive Exchange sequence.'); + } + + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const reviewId = + input.reviewId ?? + buildBtdStableId('btd-ancestry-review', [input.childAssetPackId, input.exchangeSequence.toString()]); + const receipt = reviewBtdAncestorEdges({ + reviewId, + childAssetPackId: input.childAssetPackId, + edges: input.edges, + existingEdges: input.existingEdges, + duplicateSourceRoots: input.duplicateSourceRoots, + minConfidenceBps: input.minConfidenceBps, + citationOnlyPayable: input.citationOnlyPayable, + issuedAt, + }); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-ancestry-review', [ + receipt.childAssetPackId, + receipt.reviewId, + ]), + transactionKind: 'settlement_finalization', + actorId, + preStateRoot: buildBtdStableId('btd-ancestry-pre-state', [receipt.childAssetPackId]), + postStateRoot: buildBtdStableId('btd-ancestry-post-state', [ + receipt.childAssetPackId, + String(receipt.payableEdgeCount), + String(receipt.recordedUnpaidEdgeCount), + String(receipt.rejectedEdgeCount), + ]), + receiptRoots: [receipt.reviewId], + ledgerAnchorIds: [], + exchangeSequence: input.exchangeSequence, + issuedAt, + }); + + return { + kind: 'btd_ancestry_review_settlement', + actorId, + receipt, + terminalJournalEntry, + }; +} + +export function buildBtdBtcFeeTransactionSettlement( + input: BtdBtcFeeTransactionInput & { actorId: string }, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const feeQuote = normalizeBtcFeeQuote(input.feeQuote); + const receipt = buildBtcFeeReceiptForAction({ ...input, feeQuote, issuedAt }); + const payerSession = input.payerSession ? normalizeWalletSignerSession(input.payerSession) : undefined; + const operationPosture = buildBtcFeeOperationPosture({ + quote: feeQuote, + receipt, + payerSession, + at: issuedAt, + }); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-btc-fee', [ + receipt.receiptId, + receipt.finalityState, + receipt.exchangeSequence.toString(), + ]), + transactionKind: 'btc_fee_payment', + actorId, + preStateRoot: buildBtdStableId('btc-fee-pre-state', [ + input.previousReceipt?.receiptId ?? receipt.receiptId, + input.previousReceipt?.finalityState ?? 'none', + ]), + postStateRoot: buildBtdStableId('btc-fee-post-state', [ + receipt.receiptId, + receipt.finalityState, + receipt.txid ?? 'no-txid', + String(receipt.confirmations), + ]), + receiptRoots: [receipt.receiptId], + ledgerAnchorIds: receipt.txid ? [receipt.txid] : [], + exchangeSequence: receipt.exchangeSequence, + issuedAt, + }); + + return { + kind: 'btd_btc_fee_transaction_settlement', + actorId, + action: input.action, + receipt, + operationPosture, + terminalJournalEntry, + }; +} + +export function buildBtdAssetPackLedgerAnchorSettlement( + input: BtdAssetPackLedgerAnchorInput & { actorId: string }, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { + throw new Error('AssetPack ledger anchor settlement requires a positive Exchange sequence.'); + } + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const anchor = buildAssetPackLedgerAnchorForAction(input); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-asset-pack-anchor', [ + anchor.anchorId, + anchor.finalityState, + input.exchangeSequence.toString(), + ]), + transactionKind: 'asset_pack_anchor', + actorId, + preStateRoot: buildBtdStableId('asset-pack-anchor-pre-state', [ + input.previousAnchor?.anchorId ?? anchor.anchorId, + input.previousAnchor?.finalityState ?? 'none', + ]), + postStateRoot: buildBtdStableId('asset-pack-anchor-post-state', [ + anchor.anchorId, + anchor.finalityState, + anchor.txidOrHash ?? 'no-ledger-id', + String(anchor.confirmations), + ]), + receiptRoots: [anchor.anchorId], + ledgerAnchorIds: anchor.txidOrHash ? [anchor.txidOrHash] : [], + exchangeSequence: input.exchangeSequence, + issuedAt, + }); + + return { + kind: 'btd_asset_pack_ledger_anchor_settlement', + actorId, + action: input.action, + anchor, + terminalJournalEntry, + }; +} + +export function buildBtdAssetPackExchangeSettlement( + input: BtdAssetPackExchangeInput & { actorId: string }, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + const { order, rightsTransfer, exchangeSequence } = buildAssetPackExchangeForAction(input); + const receiptRoot = rightsTransfer?.receiptId ?? order?.orderId; + if (!receiptRoot) { + throw new Error('AssetPack Exchange settlement requires an order or rights-transfer receipt.'); + } + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-asset-pack-exchange', [ + input.action, + receiptRoot, + exchangeSequence.toString(), + ]), + transactionKind: rightsTransfer ? 'rights_transfer' : 'exchange_order', + actorId, + preStateRoot: buildBtdStableId('asset-pack-exchange-pre-state', [ + input.previousOrder?.orderId ?? input.orderId ?? receiptRoot, + input.previousOrder?.orderState ?? 'none', + ]), + postStateRoot: buildBtdStableId('asset-pack-exchange-post-state', [ + order?.orderId ?? rightsTransfer?.orderId ?? receiptRoot, + order?.orderState ?? 'rights_transfer', + rightsTransfer?.btcFeeReceiptId ?? 'no-fee', + ]), + receiptRoots: [receiptRoot], + ledgerAnchorIds: [order?.ledgerAnchorId, rightsTransfer?.ledgerAnchorId].filter( + (value): value is string => Boolean(value), + ), + exchangeSequence, + issuedAt: input.issuedAt, + }); + + return { + kind: 'btd_asset_pack_exchange_settlement', + actorId, + action: input.action, + order, + rightsTransfer, + terminalJournalEntry, + }; +} + +export function buildBtdTerminalJournalSettlement( + input: BtdTerminalJournalInput & { actorId: string }, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + + switch (input.action) { + case 'commit_entry': { + const entry = + input.entry ?? + buildTerminalJournalEntry({ + journalEntryId: assertNonEmptyString(input.journalEntryId, 'journalEntryId'), + transactionKind: requireTerminalTransactionKind(input.transactionKind), + actorId, + preStateRoot: assertNonEmptyString(input.preStateRoot, 'preStateRoot'), + postStateRoot: assertNonEmptyString(input.postStateRoot, 'postStateRoot'), + receiptRoots: input.receiptRoots ?? [], + ledgerAnchorIds: input.ledgerAnchorIds, + exchangeSequence: requireBigInt(input.exchangeSequence, 'exchangeSequence'), + issuedAt: input.issuedAt, + }); + + return { + kind: 'btd_terminal_journal_settlement', + actorId, + action: input.action, + entry: normalizeTerminalJournalEntry(entry), + }; + } + case 'diff_projection': { + const entry = normalizeTerminalJournalEntry(input.entry); + if (!input.projection) { + throw new Error('Terminal journal diff requires projection.'); + } + + return { + kind: 'btd_terminal_journal_settlement', + actorId, + action: input.action, + entry, + diff: diffTerminalJournalProjection(entry, input.projection), + }; + } + case 'coverage': { + if (!input.coverageId) throw new Error('Terminal journal coverage requires coverageId.'); + if (!input.entries?.length) { + throw new Error('Terminal journal coverage requires entries.'); + } + + return { + kind: 'btd_terminal_journal_settlement', + actorId, + action: input.action, + coverage: buildTerminalJournalCoverageReceipt({ + coverageId: input.coverageId, + entries: input.entries.map((entry) => normalizeTerminalJournalEntry(entry)), + issuedAt: input.issuedAt, + }), + }; + } + default: + throw new Error( + `Unsupported Terminal journal action: ${(input as { action: string }).action}.`, + ); + } +} + +export function buildBtdLedgerDatabaseReconciliationSettlement( + input: BtdLedgerDatabaseReconciliationInput & { actorId: string }, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + const report = reconcileLedgerDatabaseProjection({ + reconciliationId: input.reconciliationId, + ledgerFacts: input.ledgerFacts, + databaseFacts: input.databaseFacts, + metaphysicalFacts: input.metaphysicalFacts, + settlementConservationChecks: input.settlementConservationChecks, + issuedAt: input.issuedAt, + }); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-reconciliation', [ + report.reconciliationId, + String(report.repairs.length), + String(report.blocking), + ]), + transactionKind: 'ledger_database_reconciliation', + actorId, + preStateRoot: buildBtdStableId('reconciliation-pre-state', [ + report.reconciliationId, + String(input.databaseFacts.length), + ]), + postStateRoot: buildBtdStableId('reconciliation-post-state', [ + report.reconciliationId, + String(report.repairs.length), + String(report.blocking), + String(report.metaphysicalFacts.length), + ]), + receiptRoots: [ + report.reconciliationId, + ...report.repairs.map((repair) => repair.repairId), + ...report.metaphysicalFacts.map((fact) => fact.receiptRoot ?? fact.canonicalRoot), + report.proofRoots.ledgerObservedRoot, + report.proofRoots.databaseProjectionRoot, + report.proofRoots.repairPlanRoot, + report.proofRoots.settlementConservationRoot, + ], + ledgerAnchorIds: input.ledgerFacts.map((fact) => fact.factId), + exchangeSequence: BigInt(Math.max(1, input.ledgerFacts.length + input.databaseFacts.length)), + issuedAt: input.issuedAt, + }); + + return { + kind: 'btd_ledger_database_reconciliation_settlement', + actorId, + report, + terminalJournalEntry, + }; +} + +export function buildBtdDeploymentReadinessSettlement( + input: BtdDeploymentReadinessInput & { actorId: string }, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + + switch (input.action) { + case 'deployment_lane': { + if (!input.readinessId) throw new Error('Deployment readiness requires readinessId.'); + if (!input.lane) throw new Error('Deployment readiness requires lane.'); + if (!input.bitcoinNetwork) throw new Error('Deployment readiness requires bitcoinNetwork.'); + if (!input.ledgerNetwork) throw new Error('Deployment readiness requires ledgerNetwork.'); + if (!input.rollbackPlanRoot) { + throw new Error('Deployment readiness requires rollbackPlanRoot.'); + } + + const lane = buildV27CryptoDeploymentLane({ + lane: input.lane, + bitcoinNetwork: input.bitcoinNetwork, + ledgerNetwork: input.ledgerNetwork, + rollbackPlanRoot: input.rollbackPlanRoot, + operationalApprovalRoot: input.operationalApprovalRoot, + }); + + return { + kind: 'btd_deployment_readiness_settlement', + actorId, + action: input.action, + readiness: buildV27CryptoDeploymentReadinessReceipt({ + readinessId: input.readinessId, + lane, + presentEnvironmentKeys: input.presentEnvironmentKeys ?? [], + issuedAt: input.issuedAt, + }), + }; + } + case 'telemetry_event': { + if (!input.telemetryEvent) throw new Error('Telemetry settlement requires event.'); + if (!input.telemetrySubjectId) { + throw new Error('Telemetry settlement requires subjectId.'); + } + + return { + kind: 'btd_deployment_readiness_settlement', + actorId, + action: input.action, + telemetry: buildV27CryptoTelemetryRecord({ + event: input.telemetryEvent, + subjectId: input.telemetrySubjectId, + receiptRoot: input.telemetryReceiptRoot, + ledgerAnchorId: input.telemetryLedgerAnchorId, + issuedAt: input.issuedAt, + }), + }; + } + case 'upgrade_plan': { + if (!input.upgradeId) throw new Error('Upgrade plan requires upgradeId.'); + if (!input.fromVersion) throw new Error('Upgrade plan requires fromVersion.'); + if (!input.toVersion) throw new Error('Upgrade plan requires toVersion.'); + if (!input.ledgerNetwork) throw new Error('Upgrade plan requires ledgerNetwork.'); + if (!input.migrationRoot) throw new Error('Upgrade plan requires migrationRoot.'); + if (!input.preStateRoot) throw new Error('Upgrade plan requires preStateRoot.'); + if (!input.approvalReceiptRoot) { + throw new Error('Upgrade plan requires approvalReceiptRoot.'); + } + if (!input.rollbackPlanRoot) throw new Error('Upgrade plan requires rollbackPlanRoot.'); + + return { + kind: 'btd_deployment_readiness_settlement', + actorId, + action: input.action, + upgradeReceipt: buildPlannedBtdProtocolUpgradeReceipt({ + upgradeId: input.upgradeId, + fromVersion: input.fromVersion, + toVersion: input.toVersion, + network: input.ledgerNetwork, + migrationRoot: input.migrationRoot, + preStateRoot: input.preStateRoot, + approvalReceiptRoot: input.approvalReceiptRoot, + rollbackPlanRoot: input.rollbackPlanRoot, + issuedAt: input.issuedAt, + }), + }; + } + case 'upgrade_transition': { + if (!input.previousUpgradeReceipt) { + throw new Error('Upgrade transition requires previousUpgradeReceipt.'); + } + if (!input.nextUpgradeState) { + throw new Error('Upgrade transition requires nextUpgradeState.'); + } + + return { + kind: 'btd_deployment_readiness_settlement', + actorId, + action: input.action, + upgradeReceipt: advanceBtdProtocolUpgradeReceipt(input.previousUpgradeReceipt, { + upgradeState: input.nextUpgradeState, + postStateRoot: input.postStateRoot, + ledgerAnchorId: input.ledgerAnchorId, + }), + }; + } + default: + throw new Error( + `Unsupported deployment readiness action: ${(input as { action: string }).action}.`, + ); + } +} + +export function toBtdJsonSafe(value: unknown): unknown { + if (typeof value === 'bigint') { + return value.toString(); + } + + if (Array.isArray(value)) { + return value.map((entry) => toBtdJsonSafe(entry)); + } + + if (value && typeof value === 'object') { + return Object.fromEntries( + Object.entries(value as Record).map(([key, entry]) => [ + key, + toBtdJsonSafe(entry), + ]), + ); + } + + return value; +} + +function assertMintDraftAdmission(input: BtdMintDraftInput): void { + if (input.acceptedNeed !== true) { + throw new Error('BTD mint draft requires accepted Read.'); + } + + if (input.acceptedFit !== true) { + throw new Error('BTD mint draft requires accepted Finding Fits result.'); + } + + if (!input.semanticUnits.length) { + throw new Error('BTD mint draft requires at least one semantic unit.'); + } + + assertNonEmptyString(input.assetPackId, 'assetPackId'); + assertNonEmptyString(input.readId, 'readId'); + assertNonEmptyString(input.sourceManifestRoot, 'sourceManifestRoot'); + assertNonEmptyString(input.fitReceiptRoot, 'fitReceiptRoot'); + assertNonEmptyString(input.proofRoot, 'proofRoot'); + assertNonEmptyString(input.dedupeReceiptRoot, 'dedupeReceiptRoot'); + assertNonEmptyString(input.settlementJournalRoot, 'settlementJournalRoot'); + assertNonEmptyString(input.exchangeReceiptRoot, 'exchangeReceiptRoot'); + assertNonEmptyString(input.accessPolicyId, 'accessPolicyId'); + assertNonEmptyString(input.accessPolicyHash, 'accessPolicyHash'); + + if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { + throw new Error('BTD mint draft requires a positive Exchange sequence.'); + } +} + +function normalizeMeasureMintState(state?: BtdMeasureMintState): BtdMeasureMintState { + if (!state) { + return createBtdMeasureMintState(); + } + + return createBtdMeasureMintState({ + totalMinted: state.totalMinted, + nextTokenId: state.nextTokenId, + cumulativeAdmittedMeasurement: state.cumulativeAdmittedMeasurement, + curveParameter: state.curveParameter, + }); +} + +function buildBtcFeeReceiptForAction( + input: BtdBtcFeeTransactionInput, +): BtcFeeTransactionReceipt { + switch (input.action) { + case 'prepare': { + if (!input.receiptId) throw new Error('BTC fee prepare requires receiptId.'); + if (!input.feePurpose) throw new Error('BTC fee prepare requires feePurpose.'); + if (!input.payerSession) throw new Error('BTC fee prepare requires payerSession.'); + if (!input.psbt) throw new Error('BTC fee prepare requires psbt.'); + if (input.satsPaid === undefined) throw new Error('BTC fee prepare requires satsPaid.'); + if (typeof input.exchangeSequence !== 'bigint') { + throw new Error('BTC fee prepare requires bigint exchangeSequence.'); + } + if (!input.terminalJournalRoot) { + throw new Error('BTC fee prepare requires terminalJournalRoot.'); + } + + if (input.feeQuote) { + const feeQuote = assertBtcFeeQuoteActive(input.feeQuote, input.issuedAt); + if (feeQuote.state !== 'accepted') { + throw new Error('BTC fee prepare requires an accepted feeQuote.'); + } + if (feeQuote.feePurpose !== input.feePurpose) { + throw new Error('BTC fee quote purpose does not match prepare input.'); + } + if (feeQuote.sats !== BigInt(input.satsPaid)) { + throw new Error('BTC fee quote sats do not match prepare input.'); + } + } + + return buildPreparedBtcFeeTransactionReceipt({ + receiptId: input.receiptId, + feePurpose: input.feePurpose, + payerSession: normalizeWalletSignerSession(input.payerSession), + psbt: input.psbt, + satsPaid: input.satsPaid, + satsPerVbyte: input.satsPerVbyte, + exchangeSequence: input.exchangeSequence, + terminalJournalRoot: input.terminalJournalRoot, + relatedAssetPackId: input.relatedAssetPackId, + relatedOrderId: input.relatedOrderId, + issuedAt: input.issuedAt, + }); + } + case 'mark_signed': { + const previous = normalizeBtcFeeTransactionReceipt(input.previousReceipt); + return advanceBtcFeeTransactionReceipt(previous, { + finalityState: 'signed', + psbt: assertNonEmptyString(input.signedPsbt, 'signedPsbt'), + }); + } + case 'mark_broadcast': { + const previous = normalizeBtcFeeTransactionReceipt(input.previousReceipt); + return advanceBtcFeeTransactionReceipt(previous, { + finalityState: 'broadcast', + txid: assertNonEmptyString(input.txid, 'txid'), + vout: input.vout, + }); + } + case 'observe': { + const previous = normalizeBtcFeeTransactionReceipt(input.previousReceipt); + const observedFinalityState = input.observedFinalityState; + if ( + observedFinalityState !== 'confirmed' && + observedFinalityState !== 'replaced' && + observedFinalityState !== 'reorged' && + observedFinalityState !== 'failed' && + observedFinalityState !== 'broadcast' + ) { + throw new Error('BTC fee observe requires an observed finality state.'); + } + + return advanceBtcFeeTransactionReceipt(previous, { + finalityState: observedFinalityState, + txid: input.txid ?? previous.txid ?? undefined, + confirmations: input.confirmations, + }); + } + default: + throw new Error(`Unsupported BTC fee transaction action: ${(input as { action: string }).action}.`); + } +} + +function buildAssetPackLedgerAnchorForAction( + input: BtdAssetPackLedgerAnchorInput, +): AssetPackLedgerAnchor { + switch (input.action) { + case 'prepare': { + if (!input.anchorId) throw new Error('AssetPack ledger anchor prepare requires anchorId.'); + if (!input.assetPackId) { + throw new Error('AssetPack ledger anchor prepare requires assetPackId.'); + } + if (!input.network) throw new Error('AssetPack ledger anchor prepare requires network.'); + if (!input.commitmentRoot) { + throw new Error('AssetPack ledger anchor prepare requires commitmentRoot.'); + } + if (!input.sourceManifestRoot) { + throw new Error('AssetPack ledger anchor prepare requires sourceManifestRoot.'); + } + if (!input.proofRoot) throw new Error('AssetPack ledger anchor prepare requires proofRoot.'); + if (!input.accessPolicyHash) { + throw new Error('AssetPack ledger anchor prepare requires accessPolicyHash.'); + } + if (input.btdRangeStart === undefined || input.btdRangeEndExclusive === undefined) { + throw new Error('AssetPack ledger anchor prepare requires BTD range bounds.'); + } + + return buildPreparedAssetPackLedgerAnchor({ + anchorId: input.anchorId, + assetPackId: input.assetPackId, + chain: input.chain, + network: input.network, + commitmentMethod: input.commitmentMethod, + commitmentRoot: input.commitmentRoot, + sourceManifestRoot: input.sourceManifestRoot, + proofRoot: input.proofRoot, + accessPolicyHash: input.accessPolicyHash, + btdRangeStart: input.btdRangeStart, + btdRangeEndExclusive: input.btdRangeEndExclusive, + contractAddress: input.contractAddress, + tokenId: input.tokenId, + }); + } + case 'mark_broadcast': { + const previous = normalizeAssetPackLedgerAnchor(input.previousAnchor); + return advanceAssetPackLedgerAnchor(previous, { + finalityState: 'broadcast', + txidOrHash: assertNonEmptyString(input.txidOrHash, 'txidOrHash'), + outputIndex: input.outputIndex, + anchoredAt: input.issuedAt, + }); + } + case 'observe': { + const previous = normalizeAssetPackLedgerAnchor(input.previousAnchor); + const observedFinalityState = input.observedFinalityState; + if ( + observedFinalityState !== 'confirmed' && + observedFinalityState !== 'reorged' && + observedFinalityState !== 'failed' && + observedFinalityState !== 'broadcast' + ) { + throw new Error('AssetPack ledger anchor observe requires an observed finality state.'); + } + + return advanceAssetPackLedgerAnchor(previous, { + finalityState: observedFinalityState, + txidOrHash: input.txidOrHash ?? previous.txidOrHash ?? undefined, + confirmations: input.confirmations, + outputIndex: input.outputIndex, + anchoredAt: input.issuedAt, + }); + } + default: + throw new Error( + `Unsupported AssetPack ledger anchor action: ${(input as { action: string }).action}.`, + ); + } +} + +function buildAssetPackExchangeForAction(input: BtdAssetPackExchangeInput): { + order?: AssetPackExchangeOrder; + rightsTransfer?: AssetPackRightsTransferReceipt; + exchangeSequence: bigint; +} { + switch (input.action) { + case 'create_order': { + if (!input.orderId) throw new Error('AssetPack Exchange order creation requires orderId.'); + if (!input.orderKind) { + throw new Error('AssetPack Exchange order creation requires orderKind.'); + } + if (!input.assetPackId) { + throw new Error('AssetPack Exchange order creation requires assetPackId.'); + } + if (input.rangeStart === undefined || input.rangeEndExclusive === undefined) { + throw new Error('AssetPack Exchange order creation requires range bounds.'); + } + if (!input.makerWalletId) { + throw new Error('AssetPack Exchange order creation requires makerWalletId.'); + } + if (input.priceSats === undefined) { + throw new Error('AssetPack Exchange order creation requires priceSats.'); + } + if (!input.accessPolicyHash) { + throw new Error('AssetPack Exchange order creation requires accessPolicyHash.'); + } + if (typeof input.createdAtExchangeSequence !== 'bigint') { + throw new Error('AssetPack Exchange order creation requires createdAtExchangeSequence.'); + } + + const order = createAssetPackExchangeOrder({ + orderId: input.orderId, + orderKind: input.orderKind, + assetPackId: input.assetPackId, + rangeStart: input.rangeStart, + rangeEndExclusive: input.rangeEndExclusive, + makerWalletId: input.makerWalletId, + priceSats: input.priceSats, + accessPolicyHash: input.accessPolicyHash, + createdAtExchangeSequence: input.createdAtExchangeSequence, + }); + return { order, exchangeSequence: order.createdAtExchangeSequence }; + } + case 'cancel_order': { + const order = cancelAssetPackExchangeOrder( + normalizeAssetPackExchangeOrder(input.previousOrder), + ); + return { order, exchangeSequence: order.createdAtExchangeSequence }; + } + case 'accept_order': { + if (!input.takerWalletId) { + throw new Error('AssetPack Exchange order acceptance requires takerWalletId.'); + } + const order = acceptAssetPackExchangeOrder( + normalizeAssetPackExchangeOrder(input.previousOrder), + input.takerWalletId, + ); + return { order, exchangeSequence: order.createdAtExchangeSequence }; + } + case 'settle_order': { + if (typeof input.settledAtExchangeSequence !== 'bigint') { + throw new Error('AssetPack Exchange order settlement requires settledAtExchangeSequence.'); + } + const order = settleAssetPackExchangeOrder( + normalizeAssetPackExchangeOrder(input.previousOrder), + { + settledAtExchangeSequence: input.settledAtExchangeSequence, + ledgerAnchorId: input.ledgerAnchorId, + }, + ); + return { order, exchangeSequence: input.settledAtExchangeSequence }; + } + case 'transfer_rights': { + if (!input.receiptId) { + throw new Error('AssetPack rights transfer requires receiptId.'); + } + if (!input.fromWalletId || !input.toWalletId) { + throw new Error('AssetPack rights transfer requires fromWalletId and toWalletId.'); + } + if (!input.btcFeeReceiptId) { + throw new Error('AssetPack rights transfer requires btcFeeReceiptId.'); + } + + const rightsTransfer = buildAssetPackRightsTransferReceipt({ + receiptId: input.receiptId, + settledOrder: normalizeAssetPackExchangeOrder(input.previousOrder), + fromWalletId: input.fromWalletId, + toWalletId: input.toWalletId, + btcFeeReceiptId: input.btcFeeReceiptId, + issuedAt: input.issuedAt, + }); + return { rightsTransfer, exchangeSequence: rightsTransfer.exchangeSequence }; + } + default: + throw new Error( + `Unsupported AssetPack Exchange action: ${(input as { action: string }).action}.`, + ); + } +} + +function normalizeWalletSignerSession( + session: WalletSignerSession | BtdWalletSignerSessionInput, +): WalletSignerSession { + if ('serverCustody' in session && 'state' in session) { + return session; + } + + return createWalletSignerSession(session); +} + +function normalizeBtcFeeTransactionReceipt( + receipt: BtcFeeTransactionReceipt | undefined, +): BtcFeeTransactionReceipt { + if (!receipt) { + throw new Error('BTC fee transition requires previousReceipt.'); + } + + return assertBtcFeeTransactionReceipt({ + ...receipt, + satsPaid: BigInt(receipt.satsPaid), + exchangeSequence: BigInt(receipt.exchangeSequence), + serverCustody: false, + }); +} + +function normalizeBtcFeeQuote(quote: BtcFeeQuote | undefined): BtcFeeQuote | undefined { + if (!quote) { + return undefined; + } + + return assertBtcFeeQuote({ + ...quote, + sats: BigInt(quote.sats), + }); +} + +function normalizeAssetPackLedgerAnchor( + anchor: AssetPackLedgerAnchor | undefined, +): AssetPackLedgerAnchor { + if (!anchor) { + throw new Error('AssetPack ledger anchor transition requires previousAnchor.'); + } + + return assertAssetPackLedgerAnchor(anchor); +} + +function normalizeAssetPackExchangeOrder( + order: AssetPackExchangeOrder | undefined, +): AssetPackExchangeOrder { + if (!order) { + throw new Error('AssetPack Exchange transition requires previousOrder.'); + } + + return { + ...order, + priceSats: BigInt(order.priceSats), + createdAtExchangeSequence: BigInt(order.createdAtExchangeSequence), + settledAtExchangeSequence: + order.settledAtExchangeSequence === undefined + ? undefined + : BigInt(order.settledAtExchangeSequence), + }; +} + +function normalizeTerminalJournalEntry(entry: TerminalJournalEntry | undefined): TerminalJournalEntry { + if (!entry) { + throw new Error('Terminal journal action requires entry.'); + } + + return buildTerminalJournalEntry({ + ...entry, + exchangeSequence: BigInt(entry.exchangeSequence), + }); +} + +function requireTerminalTransactionKind( + kind: TerminalTransactionKind | undefined, +): TerminalTransactionKind { + if (!kind) { + throw new Error('Terminal journal entry requires transactionKind.'); + } + + return kind; +} + +function requireBigInt(value: bigint | undefined, label: string): bigint { + if (typeof value !== 'bigint') { + throw new Error(`${label} must be a bigint.`); + } + + return value; +} diff --git a/packages/btd/src/index.ts b/packages/btd/src/index.ts index 113852887..dcdeeacc7 100644 --- a/packages/btd/src/index.ts +++ b/packages/btd/src/index.ts @@ -160,6 +160,7 @@ export * from './bitcoin-provider'; export * from './access'; export * from './allocation'; export * from './ancestry'; +export * from './api-boundaries'; export * from './authority'; export * from './constants'; export * from './deployment-lanes'; diff --git a/scripts/check-v30-gate2-protocol-package-api-boundaries.mjs b/scripts/check-v30-gate2-protocol-package-api-boundaries.mjs new file mode 100644 index 000000000..be24414d7 --- /dev/null +++ b/scripts/check-v30-gate2-protocol-package-api-boundaries.mjs @@ -0,0 +1,236 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 2 package-owned BTD API builders, route delegation, docs, tests, and commercial runtime demonstration boundary posture.' + ].join('\n') + ); + process.stdout.write('\n'); +} + +function collectSourceFiles(root, startRelativePath) { + const start = path.join(root, startRelativePath); + if (!existsSync(start)) return []; + + const results = []; + const stack = [start]; + while (stack.length) { + const current = stack.pop(); + const relative = path.relative(root, current); + const stat = statSync(current); + + if (stat.isDirectory()) { + if ( + relative.includes(`${path.sep}_legacy${path.sep}`) || + relative.includes(`${path.sep}node_modules${path.sep}`) || + relative.includes(`${path.sep}tmp${path.sep}`) || + relative.includes(`${path.sep}__tests__${path.sep}`) || + relative.endsWith(`${path.sep}__tests__`) + ) { + continue; + } + + for (const entry of readdirSync(current)) { + stack.push(path.join(current, entry)); + } + continue; + } + + if (/\.(?:mjs|cjs|js|jsx|ts|tsx)$/u.test(current)) { + results.push(current); + } + } + + return results; +} + +function findStandaloneDemonstrationImports(root) { + const importPattern = + /(?:from\s+|import\s*\(|require\s*\()\s*['"][^'"]*(?:@bitcode\/protocol-demonstration|protocol-demonstration\/src)/u; + const sourceRoots = ['packages', 'uapi/app', 'uapi/components', 'uapi/lib']; + return sourceRoots.flatMap((sourceRoot) => + collectSourceFiles(root, sourceRoot).flatMap((filePath) => { + const source = readFileSync(filePath, 'utf8'); + return importPattern.test(source) ? [path.relative(root, filePath)] : []; + }), + ); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.` + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-2-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 2 work must occur on version/v30 or v30/gate-2-* branches. Observed ${branch || 'detached HEAD'}.` + ); + } + + for (const relativePath of [ + 'packages/btd/src/api-boundaries.ts', + 'packages/btd/src/index.ts', + 'packages/btd/__tests__/api-boundaries.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'packages/btd/README.md', + 'packages/api/README.md', + 'packages/protocol/README.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + 'BITCODE_SPEC_V30_NOTES.md' + ]) { + assertCheck(failures, fileExists(root, relativePath), `Missing V30 Gate 2 file: ${relativePath}`); + } + + const btdBoundary = read(root, 'packages/btd/src/api-boundaries.ts'); + const btdIndex = read(root, 'packages/btd/src/index.ts'); + const btdTest = read(root, 'packages/btd/__tests__/api-boundaries.test.ts'); + const apiRoute = read(root, 'packages/api/src/routes/btd-crypto.ts'); + const apiRouteTest = read(root, 'packages/api/src/routes/__tests__/btd-crypto.test.ts'); + const btdReadme = read(root, 'packages/btd/README.md'); + const apiReadme = read(root, 'packages/api/README.md'); + const protocolReadme = read(root, 'packages/protocol/README.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + for (const symbol of [ + 'buildBtdMintDraft', + 'buildBtdRegistrySnapshot', + 'buildBtdReadAccessDecision', + 'buildBtdBtcFeeTransactionSettlement', + 'parseBtdRequiredBigInt', + 'parseBtdOptionalBigInt', + 'toBtdJsonSafe' + ]) { + assertCheck( + failures, + btdBoundary.includes(`export ${symbol}`) || + btdBoundary.includes(`export function ${symbol}`) || + btdBoundary.includes(`export async function ${symbol}`), + `BTD boundary must export ${symbol}.` + ); + } + + assertCheck(failures, btdBoundary.includes('BtdOrganizationInterfaceAuthorityRouteInput'), 'BTD boundary must distinguish route body input from the actor-bound authority primitive input.'); + assertCheck(failures, btdIndex.includes("export * from './api-boundaries';"), 'BTD package index must export api-boundaries.'); + assertCheck(failures, btdTest.includes("from '../src'"), 'BTD API-boundary tests must exercise package exports.'); + assertCheck(failures, btdTest.includes('parseBtdRequiredBigInt'), 'BTD API-boundary tests must cover BigInt parsers.'); + assertCheck(failures, btdTest.includes('toBtdJsonSafe'), 'BTD API-boundary tests must cover JSON-safe serialization.'); + + assertCheck(failures, apiRoute.includes("from '@bitcode/btd'"), 'BTD route must import package-owned builders from @bitcode/btd.'); + for (const localRouteImplementation of [ + 'export interface BtdMintDraftInput', + 'function assertMintDraftAdmission', + 'function buildBtcFeeReceiptForAction', + 'function toJsonSafe' + ]) { + assertCheck(failures, !apiRoute.includes(localRouteImplementation), `BTD route must not own ${localRouteImplementation}.`); + } + assertCheck(failures, apiRoute.includes('toBtdJsonSafe as toJsonSafe'), 'BTD route must delegate JSON-safe conversion to @bitcode/btd.'); + assertCheck(failures, apiRoute.includes('parseBtdRequiredBigInt'), 'BTD route must delegate BigInt parsing to @bitcode/btd.'); + assertCheck( + failures, + !/import\s*\{[^}]*buildBtdMintDraft[^}]*\}\s*from\s*['"]\.\.\/btd-crypto['"]/su.test(apiRouteTest), + 'BTD route tests must not import package-owned builders from the route module.' + ); + assertCheck(failures, apiRouteTest.includes("from '@bitcode/btd'"), 'BTD route tests must import package-owned builders from @bitcode/btd.'); + + const demonstrationImportViolations = findStandaloneDemonstrationImports(root); + assertCheck( + failures, + demonstrationImportViolations.length === 0, + `Commercial runtime source must not import protocol-demonstration/src or @bitcode/protocol-demonstration: ${demonstrationImportViolations.join(', ')}` + ); + + assertCheck(failures, btdReadme.includes('api-boundaries.ts'), 'BTD README must name the API-boundary module.'); + assertCheck(failures, btdReadme.includes('@bitcode/btd'), 'BTD README must name accepted package imports.'); + assertCheck(failures, apiReadme.includes('@bitcode/btd'), 'API README must state BTD route delegation to @bitcode/btd.'); + assertCheck(failures, apiReadme.includes('route-owned'), 'API README must distinguish route-owned work from package-owned policy.'); + assertCheck(failures, protocolReadme.includes('@bitcode/protocol'), 'Protocol README must keep accepted commercial imports explicit.'); + assertCheck(failures, protocolReadme.includes('must not import `protocol-demonstration/src/*`'), 'Protocol README must forbid standalone demonstration runtime imports.'); + + assertCheck(failures, delta.includes('Gate 2: Protocol Package API Boundaries'), 'V30 DELTA must retain Gate 2 scope.'); + assertCheck(failures, delta.includes('packages/btd/src/api-boundaries.ts'), 'V30 DELTA must name the BTD API-boundary implementation.'); + assertCheck(failures, parity.includes('## Gate 2 Parity'), 'V30 PARITY must include Gate 2 parity evidence.'); + assertCheck(failures, parity.includes('packages/btd/src/api-boundaries.ts'), 'V30 PARITY must cite the BTD API-boundary implementation.'); + assertCheck(failures, notes.includes('Gate 2 protocol package API boundary notes'), 'V30 NOTES must include Gate 2 implementation notes.'); + + assertCheck(failures, packageJson.includes('"check:v30-gate2"'), 'package.json must expose check:v30-gate2.'); + assertCheck(failures, gateWorkflow.includes('check-v30-gate2-protocol-package-api-boundaries.mjs'), 'Gate workflow must run the V30 Gate 2 checker.'); + + if (failures.length) { + process.stderr.write('V30 Gate 2 package API boundary check failed:\n'); + for (const failure of failures) { + process.stderr.write(`- ${failure}\n`); + } + process.exit(1); + } + + process.stdout.write('V30 Gate 2 package API boundary check passed.\n'); +} + +main(); From 309c87e52f2938db4413b26e19cb45b137607a0f Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 17:34:55 -0300 Subject: [PATCH 03/15] V30 Gate 3: Harden BTC fee PSBT posture Adds package-owned BTC fee network policy and Taproot PSBT posture types, enforces quote timestamp windows and signed-PSBT evidence, extends BTD/API tests for no-custody handoff, replacement, reorg, and mainnet blocking, and wires V30 Gate 3 specification parity plus checker/workflow coverage. --- .github/workflows/bitcode-gate-quality.yml | 1 + BITCODE_SPEC_V30.md | 8 +- BITCODE_SPEC_V30_DELTA.md | 16 ++ BITCODE_SPEC_V30_NOTES.md | 18 ++ BITCODE_SPEC_V30_PARITY_MATRIX.md | 22 +- package.json | 1 + .../src/routes/__tests__/btd-crypto.test.ts | 17 ++ packages/btd/README.md | 3 + .../btd/__tests__/btc-fee-operation.test.ts | 135 +++++++++- packages/btd/src/bitcoin-fees.ts | 4 + packages/btd/src/btc-fee-operation.ts | 251 +++++++++++++++++- ...0-gate3-bitcoin-taproot-psbt-fee-rigor.mjs | 199 ++++++++++++++ 12 files changed, 662 insertions(+), 13 deletions(-) create mode 100644 scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 86736a6d7..0a963ea8b 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -81,6 +81,7 @@ jobs: node scripts/check-v29-gate10-local-staging-promotion-readiness.mjs --promotion-mode --skip-branch-check node scripts/check-v30-gate1-roadmap-and-gating.mjs --skip-branch-check node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs --skip-branch-check + node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index cf08d4820..cf19bc197 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -183,7 +183,9 @@ The V30 domain model extends V29 operationally: - `SettlementUnlock`: BTC fee proof, BTD range/read-license/right transfer, paid disclosure decision, delivery admission, and reconciliation state. - `BtcFeeQuote`: deterministic BTC fee quote with quote root, measurement root, purpose, network, sats, pricing version, expiration, and lifecycle state. - `WalletSignerSessionRecovery`: signer-session posture proving whether the Reader wallet can sign a PSBT without server custody. -- `BtcFeeOperationPosture`: operational state over quote, signer, PSBT, broadcast, finality, replacement, reorg, failure, and blocked readiness. +- `BtcFeeNetworkPolicy`: proof-rooted environment and network admission posture over local, staging-testnet, and production-mainnet value-bearing BTC settlement. +- `BtcFeeTaprootPsbtPosture`: proof-rooted Taproot commitment, script path, PSBT handoff, broadcast observation, replacement, reorg, and finality posture. +- `BtcFeeOperationPosture`: operational state over quote, signer, network policy, Taproot/script posture, PSBT, broadcast, finality, replacement, reorg, failure, and blocked readiness. - `BtdAssetPackMintReceipt`: typed receipt binding AssetPack id, BTD range, depositor ownership, source-safe preview root, mint measurement root, settlement conservation root, and ledger projection root. - `BtdReadReceipt`: typed receipt binding Reader, read request, accepted Need, Finding Fits result root, source-safe preview root, paid/unpaid disclosure state, read-right state, and delivery admission. - `BtdRightsTransferReceipt`: typed receipt binding BTC fee finality, BTD owner or license transition, range projection, paid unlock, delivery proof, and reconciliation status. @@ -317,7 +319,9 @@ The operation model must contain: - quote lifecycle: quoted, accepted, expired, superseded, and failed; - deterministic quote root over quote id, purpose, network, sats, measurement root, issue time, and expiration; - signer recovery: missing, prepared authorization required, stored authorization requiring live reconnect, expired, revoked, failed, network mismatch, capability missing, server-custody rejected, or live authorized; -- PSBT handoff: accepted quote prepares a PSBT; the wallet signs; the signed PSBT broadcasts; +- network policy: local and staging-testnet may exercise value-bearing BTC settlement for QA; production-mainnet value-bearing settlement remains blocked until explicit operational approval is attached and proof-rooted; +- Taproot/script posture: Bitcoin fee and anchor paths default to Taproot, name the admitted script path, and expose non-Taproot posture as audit evidence rather than silently treating it as equivalent; +- PSBT handoff: accepted quote prepares an unsigned PSBT; the wallet signs; the signed PSBT is ready for broadcast; broadcast and finality observations are separate states; - finality states: prepared, signed, broadcast, confirmed, replaced, reorged, and failed; - blocked-readiness receipts naming the blocker id, summary, required action, quote id, wallet session id, receipt id, and no-server-custody posture; - Terminal read rows and metrics for state, network, sats, confirmations, quote root, wallet session, payer wallet, PSBT handoff, txid, server custody, and next action. diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 09f9a3010..1fc889af9 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -116,6 +116,22 @@ Closure acceptance: - testnet/mainnet distinction is policy-enforced and proof-rooted; - focused BTD/API tests prove fee lifecycle and blocked-readiness behavior. +Gate 3 implementation centers these semantics in +`packages/btd/src/btc-fee-operation.ts` and `packages/btd/src/bitcoin-fees.ts`. +`BtcFeeNetworkPolicy` admits local and staging-testnet fee operation while +blocking value-bearing production-mainnet settlement unless explicit operational +approval is attached. `BtcFeeTaprootPsbtPosture` names the Bitcoin commitment +method, script path, PSBT handoff state, and broadcast observation state so +prepared, signed, broadcast, confirmed, replaced, reorged, and failed receipts +remain distinguishable. Signed receipts require a signed PSBT, quote timestamps +must be usable for PSBT preparation, and server-custody signer sessions remain +fail-closed before handoff. + +Gate 3 evidence is covered by +`packages/btd/__tests__/btc-fee-operation.test.ts`, +`packages/api/src/routes/__tests__/btd-crypto.test.ts`, and +`scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs`. + ### Gate 4: BTD AssetPack Mint And Read Receipts Gate 4 creates typed BTD receipt boundaries. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index 994b27279..a465d589d 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -90,6 +90,24 @@ standalone demonstration imports. 3. **Gate 3: Bitcoin Taproot PSBT Fee Rigor** - Harden BTC fee quote, signer recovery, PSBT, Taproot/script posture, broadcast, replacement, reorg, finality, and testnet/mainnet boundaries. +## Gate 3 Bitcoin Taproot PSBT fee rigor notes + +Gate 3 makes BTC fee operation inspectable before any later BTD receipt, +projection, or interface depends on it. `BtcFeeOperationPosture` now carries the +network policy, Taproot/PSBT posture, PSBT handoff state, and broadcast +observation state beside quote, signer, receipt, and blocked-readiness data. + +The network policy deliberately treats staging-testnet as the operational lane +for current QA. Production-mainnet value-bearing settlement is not admitted by +default. It must carry explicit operational approval before the posture leaves +blocked-readiness, and that approval state contributes to the policy proof root. + +The PSBT path distinguishes prepared unsigned PSBT, signed ready-to-broadcast +PSBT, broadcast submission, finality observation, replacement/reorg repair, and +failure. Signed receipt advancement requires a signed PSBT. Broadcast, +confirmed, replaced, and reorged observations require transaction id evidence. +Server-custody signer posture remains rejected before PSBT handoff. + 4. **Gate 4: BTD AssetPack Mint And Read Receipts** - Make BTD mint, read, and rights-transfer receipts typed, proof-rooted, stored, streamed, and source-safe. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index 091db6b1f..f5da18708 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -56,7 +56,7 @@ No `_legacy/` source is active source truth. | Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V30.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v30/gate-1-roadmap-and-gating` | drafted | V30 family validates in draft mode over active V29 and `check:v30-gate1` passes. | | Roadmap truth | Gate 1 | `SPECIFICATIONS_ROADMAP.md`, README, PR template, workflow posture | drafted | Roadmap states V29 active, V30 draft, and coherent V31-V37 responsibilities. | | Protocol package API boundaries | Gate 2 | `packages/btd/src/api-boundaries.ts`, `packages/api/src/routes/btd-crypto.ts`, package READMEs/tests | drafted | Shared Protocol/BTD objects have package-owned builders, parsers, validators, JSON-safe serializers, and tests. | -| Bitcoin Taproot PSBT fee rigor | Gate 3 | BTD fee/signer/PSBT primitives, API route adapters, tests | pending | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, and proof-rooted. | +| Bitcoin Taproot PSBT fee rigor | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, `packages/btd/src/bitcoin-fees.ts`, BTD/API tests, gate checker | drafted | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, Taproot/PSBT aware, and proof-rooted. | | BTD AssetPack mint/read receipts | Gate 4 | BTD receipt primitives, asset-pack postprocess, harness evidence, Terminal/API readback | pending | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | | Testnet ledger projection hardening | Gate 5 | BTD reconciliation, Supabase readback, object-storage evidence, repair tests | pending | Ledger/database/object-storage projections are synchronized or blocked with deterministic repair posture. | | Source-to-shares proof cleanup | Gate 6 | BTD/source-to-shares proof primitives, settlement conservation tests | pending | Measurement contribution, fee allocation, zero-cell/refit tail, and conservation invariants are testable. | @@ -112,6 +112,26 @@ No `_legacy/` source is active source truth. - Gate 2 does not introduce bridge chain-of-record behavior. - Gate 2 does not admit value-bearing mainnet settlement. - Gate 2 does not remove existing API route persistence adapters; it narrows their policy and receipt derivation responsibilities to package calls. + +## Gate 3 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| BTC fee quotes validate PSBT-usable timestamp windows | `packages/btd/src/btc-fee-operation.ts`, `packages/btd/__tests__/btc-fee-operation.test.ts` | drafted | +| Wallet signer recovery rejects server custody explicitly | `buildWalletSignerSessionRecovery`, `packages/btd/__tests__/btc-fee-operation.test.ts` | drafted | +| PSBT handoff is typed across prepared, signed, broadcast, finality, replacement/reorg repair, and failure | `BtcFeePsbtHandoffState`, `deriveBtcFeePsbtHandoffState`, `BtcFeeOperationPosture` | drafted | +| Taproot/script posture is proof-rooted and attached to fee operation posture | `BtcFeeTaprootPsbtPosture`, `buildBtcFeeTaprootPsbtPosture`, API route tests | drafted | +| Testnet/mainnet distinction blocks value-bearing production-mainnet settlement unless explicitly approved | `BtcFeeNetworkPolicy`, `buildBtcFeeNetworkPolicy`, `network-policy` blocked-readiness tests | drafted | +| Signed receipts require signed PSBT evidence before broadcast | `packages/btd/src/bitcoin-fees.ts`, `packages/btd/__tests__/btc-fee-operation.test.ts` | drafted | +| API settlement route serializes the added operation posture safely | `packages/api/src/routes/__tests__/btd-crypto.test.ts` | drafted | +| Gate checker protects the BTC fee rigor surface | `scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs`, `pnpm run check:v30-gate3`, gate-quality workflow | drafted | + +## Gate 3 accepted boundaries + +- Gate 3 does not admit value-bearing production-mainnet settlement by default. +- Gate 3 does not implement a bridge chain-of-record path. +- Gate 3 does not custody Reader private keys or sign PSBTs server-side. +- Gate 3 does not replace later Gate 4 BTD mint, read, and rights-transfer receipts. - Gate 1 does not promote `BITCODE_SPEC.txt` to V30. - Gate 1 may retarget workflows to active V29 / draft V30 so later gates are greenable. - Gate 1 may update roadmap scope for V31-V37 to align with V28/V29 promotion learning without opening those versions. diff --git a/package.json b/package.json index dfa971654..ccdeca31b 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "check:v29-gate10": "node scripts/check-v29-gate10-local-staging-promotion-readiness.mjs", "check:v30-gate1": "node scripts/check-v30-gate1-roadmap-and-gating.mjs", "check:v30-gate2": "node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs", + "check:v30-gate3": "node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/api/src/routes/__tests__/btd-crypto.test.ts b/packages/api/src/routes/__tests__/btd-crypto.test.ts index ad928c2ec..487502b9b 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -667,6 +667,17 @@ describe('BTD crypto API builders', () => { phase: 'psbt_ready', canSignPsbt: true, noServerCustody: true, + psbtHandoffState: 'prepared_unsigned', + broadcastState: 'not_broadcast', + networkPolicy: { + admitted: true, + environment: 'staging-testnet', + mainnet: false, + }, + taprootScriptPosture: { + commitmentMethod: 'taproot', + taprootAdmitted: true, + }, quote: { quoteId: 'quote-api-1' }, }); expect(prepared.terminalJournalEntry.transactionKind).toBe('btc_fee_payment'); @@ -1069,6 +1080,12 @@ describe('BTD crypto API builders', () => { expect(body.operationPosture).toMatchObject({ phase: 'psbt_ready', canSignPsbt: true, + psbtHandoffState: 'prepared_unsigned', + broadcastState: 'not_broadcast', + networkPolicy: { + admitted: true, + environment: 'staging-testnet', + }, quote: { quoteId: 'quote-api-1', sats: '1200', diff --git a/packages/btd/README.md b/packages/btd/README.md index e0d524ed0..7832ec4d9 100644 --- a/packages/btd/README.md +++ b/packages/btd/README.md @@ -11,6 +11,9 @@ This package owns: - contributor allocation, access evaluation, ancestry review, and revenue routing - wallet-signed BTC fee receipts, ledger anchors, Exchange rights transfers, Terminal journals, reconciliation, telemetry, and upgrade receipts +- BTC fee operation posture, including quote lifecycle, signer recovery, + no-server-custody PSBT handoff, Taproot/script posture, broadcast/finality + observation, replacement/reorg repair, and testnet/mainnet network policy - Terminal operational health reads that compose deployment lanes, telemetry, upgrade posture, provider readiness, settlement-network posture, synthetic testnet minting, journal rows, ledger anchors, and reconciliation state diff --git a/packages/btd/__tests__/btc-fee-operation.test.ts b/packages/btd/__tests__/btc-fee-operation.test.ts index 952a7c362..692f92965 100644 --- a/packages/btd/__tests__/btc-fee-operation.test.ts +++ b/packages/btd/__tests__/btc-fee-operation.test.ts @@ -1,8 +1,10 @@ import { advanceBtcFeeQuote, advanceBtcFeeTransactionReceipt, + buildBtcFeeNetworkPolicy, buildBtcFeeOperationPosture, buildBtcFeeQuote, + buildBtcFeeTaprootPsbtPosture, buildPreparedBtcFeeTransactionReceipt, buildWalletSignerSessionRecovery, createWalletSignerSession, @@ -31,7 +33,7 @@ function authorizedSession(overrides = {}) { }); } -function acceptedQuote() { +function acceptedQuote(overrides = {}) { return advanceBtcFeeQuote( buildBtcFeeQuote({ quoteId: 'quote-1', @@ -43,6 +45,7 @@ function acceptedQuote() { relatedAssetPackId: 'asset-pack-1', issuedAt, expiresAt, + ...overrides, }), { state: 'accepted' }, ); @@ -92,6 +95,109 @@ describe('BTC fee quote lifecycle', () => { /Invalid BTC fee quote transition/, ); }); + + it('fails closed when quote timestamps cannot support PSBT preparation', () => { + expect(() => + buildBtcFeeQuote({ + quoteId: 'quote-expired-at-issue', + feePurpose: 'licensed_read', + network: 'testnet', + sats: 1200n, + measurementRoot: 'need-fit-measurement-root', + issuedAt, + expiresAt: issuedAt, + }), + ).toThrow('BTC fee quote expiresAt must be after issuedAt.'); + }); + + it('models PSBT handoff, replacement, and reorg repair states explicitly', () => { + const prepared = preparedReceipt(); + expect(() => + advanceBtcFeeTransactionReceipt(prepared, { finalityState: 'signed' } as never), + ).toThrow('signedPsbt must be a non-empty string.'); + + const signed = advanceBtcFeeTransactionReceipt(prepared, { + finalityState: 'signed', + psbt: 'signed-psbt', + }); + const broadcast = advanceBtcFeeTransactionReceipt(signed, { + finalityState: 'broadcast', + txid: 'txid-repair', + }); + const replaced = advanceBtcFeeTransactionReceipt(broadcast, { + finalityState: 'replaced', + txid: 'replacement-txid', + }); + + expect(buildBtcFeeTaprootPsbtPosture({ network: 'testnet', receipt: prepared })).toMatchObject({ + psbtHandoffState: 'prepared_unsigned', + broadcastState: 'not_broadcast', + taprootRequired: true, + }); + expect(buildBtcFeeTaprootPsbtPosture({ network: 'testnet', receipt: signed })).toMatchObject({ + psbtHandoffState: 'signed_ready_to_broadcast', + broadcastState: 'not_broadcast', + }); + expect(buildBtcFeeTaprootPsbtPosture({ network: 'testnet', receipt: replaced })).toMatchObject({ + psbtHandoffState: 'replacement_or_reorg_repair_required', + broadcastState: 'replaced', + }); + }); + + it('blocks value-bearing mainnet settlement unless operationally approved', () => { + expect( + buildBtcFeeNetworkPolicy({ + network: 'mainnet', + environment: 'production-mainnet', + }), + ).toMatchObject({ + admitted: false, + operationalApprovalRequired: true, + mainnet: true, + proofRoot: expect.stringMatching(/^btc-fee-network-policy-/), + }); + + const mainnetQuote = acceptedQuote({ network: 'mainnet', quoteId: 'quote-mainnet-1' }); + const mainnetSession = authorizedSession({ + walletSessionId: 'wallet-session-mainnet', + walletId: 'wallet-mainnet', + address: 'bc1qbitcodereader0000000000000000000000000', + network: 'mainnet', + }); + const blocked = buildBtcFeeOperationPosture({ + quote: mainnetQuote, + payerSession: mainnetSession, + environment: 'production-mainnet', + at: issuedAt, + }); + expect(blocked).toMatchObject({ + phase: 'blocked', + networkPolicy: { + admitted: false, + blocker: 'Value-bearing BTC fee settlement on mainnet requires explicit operational approval.', + }, + blockedReadiness: { + blockerId: 'network-policy', + noServerCustody: true, + }, + }); + + expect( + buildBtcFeeOperationPosture({ + quote: mainnetQuote, + payerSession: mainnetSession, + environment: 'production-mainnet', + valueBearingMainnetApproved: true, + at: issuedAt, + }), + ).toMatchObject({ + phase: 'quoted', + networkPolicy: { + admitted: true, + operationalApprovalRequired: true, + }, + }); + }); }); describe('wallet signer recovery', () => { @@ -133,6 +239,23 @@ describe('wallet signer recovery', () => { canSign: false, }); }); + + it('rejects server-custody signer sessions before PSBT handoff', () => { + const recovery = buildWalletSignerSessionRecovery({ + session: { + ...authorizedSession(), + serverCustody: true, + } as never, + network: 'testnet', + at: issuedAt, + }); + + expect(recovery).toMatchObject({ + state: 'server_custody_rejected', + canSign: false, + blocker: 'Wallet signer session implies server custody.', + }); + }); }); describe('BTC fee operation posture', () => { @@ -195,6 +318,8 @@ describe('BTC fee operation posture', () => { phase: 'psbt_ready', canSignPsbt: true, canBroadcast: false, + psbtHandoffState: 'prepared_unsigned', + broadcastState: 'not_broadcast', }); const signed = advanceBtcFeeTransactionReceipt(prepared, { @@ -220,6 +345,12 @@ describe('BTC fee operation posture', () => { ).toMatchObject({ phase: 'broadcast', canObserveFinality: true, + psbtHandoffState: 'broadcast_submitted', + broadcastState: 'broadcast', + taprootScriptPosture: { + commitmentMethod: 'taproot', + taprootAdmitted: true, + }, }); expect( buildBtcFeeOperationPosture({ @@ -232,6 +363,8 @@ describe('BTC fee operation posture', () => { phase: 'confirmed', canSettle: true, noServerCustody: true, + psbtHandoffState: 'finality_observed', + broadcastState: 'confirmed', }); }); }); diff --git a/packages/btd/src/bitcoin-fees.ts b/packages/btd/src/bitcoin-fees.ts index f0e2111a5..9a82afc2d 100644 --- a/packages/btd/src/bitcoin-fees.ts +++ b/packages/btd/src/bitcoin-fees.ts @@ -124,6 +124,10 @@ export function advanceBtcFeeTransactionReceipt( const txid = next.txid ?? receipt.txid; const confirmations = next.confirmations ?? receipt.confirmations; + if (next.finalityState === 'signed') { + assertNonEmptyString(next.psbt, 'signedPsbt'); + } + if (['broadcast', 'confirmed', 'replaced', 'reorged'].includes(next.finalityState)) { assertNonEmptyString(txid, 'txid'); } diff --git a/packages/btd/src/btc-fee-operation.ts b/packages/btd/src/btc-fee-operation.ts index 3a6a918ce..c60f882ba 100644 --- a/packages/btd/src/btc-fee-operation.ts +++ b/packages/btd/src/btc-fee-operation.ts @@ -45,6 +45,61 @@ export type WalletSignerSessionRecoveryState = | 'capability_missing' | 'server_custody_rejected'; +export type BtcFeeNetworkEnvironment = + | 'local' + | 'staging-testnet' + | 'production-mainnet'; + +export type BtcFeePsbtHandoffState = + | 'not_prepared' + | 'prepared_unsigned' + | 'signed_ready_to_broadcast' + | 'broadcast_submitted' + | 'finality_observed' + | 'replacement_or_reorg_repair_required' + | 'failed'; + +export type BtcFeeBroadcastObservationState = + | 'not_broadcast' + | 'broadcast' + | 'confirmed' + | 'replaced' + | 'reorged' + | 'failed'; + +export type BtcFeeBitcoinCommitmentMethod = + | 'taproot' + | 'op_return' + | 'standard_output_commitment' + | 'unknown'; + +export type BtcFeeTaprootScriptPath = 'key_path' | 'script_path' | 'unknown'; + +export interface BtcFeeNetworkPolicy { + kind: 'btc.fee_network_policy'; + network: BitcoinNetwork | null; + environment: BtcFeeNetworkEnvironment; + valueBearing: boolean; + admitted: boolean; + operationalApprovalRequired: boolean; + mainnet: boolean; + proofRoot: string; + blocker: string | null; +} + +export interface BtcFeeTaprootPsbtPosture { + kind: 'btc.fee_taproot_psbt_posture'; + chain: 'bitcoin'; + network: BitcoinNetwork | null; + commitmentMethod: BtcFeeBitcoinCommitmentMethod; + scriptPath: BtcFeeTaprootScriptPath; + taprootRequired: boolean; + taprootAdmitted: boolean; + psbtHandoffState: BtcFeePsbtHandoffState; + broadcastState: BtcFeeBroadcastObservationState; + proofRoot: string; +} + export interface WalletSignerSessionRecovery { state: WalletSignerSessionRecoveryState; canSign: boolean; @@ -74,6 +129,7 @@ export type BtcFeeBlockedReadinessBlockerId = | 'wallet-network' | 'wallet-capability' | 'wallet-server-custody' + | 'network-policy' | 'fee-quote' | 'fee-quote-expired' | 'fee-quote-not-accepted' @@ -101,6 +157,10 @@ export interface BtcFeeOperationPosture { quote: BtcFeeQuote | null; receipt: BtcFeeTransactionReceipt | null; signerRecovery: WalletSignerSessionRecovery; + networkPolicy: BtcFeeNetworkPolicy; + taprootScriptPosture: BtcFeeTaprootPsbtPosture; + psbtHandoffState: BtcFeePsbtHandoffState; + broadcastState: BtcFeeBroadcastObservationState; blockedReadiness: BtcFeeBlockedReadinessReceipt | null; canPreparePsbt: boolean; canSignPsbt: boolean; @@ -131,30 +191,35 @@ export function buildBtcFeeQuote(input: { relatedAssetPackId?: string; relatedOrderId?: string; }): BtcFeeQuote { + const quoteId = assertNonEmptyString(input.quoteId, 'quoteId'); + const network = assertBitcoinNetwork(input.network); + const measurementRoot = assertNonEmptyString(input.measurementRoot, 'measurementRoot'); + const expiresAt = assertNonEmptyString(input.expiresAt, 'expiresAt'); const sats = toBigIntAmount(input.sats, 'sats'); if (sats <= 0n) { throw new Error('BTC fee quote sats must be positive.'); } const issuedAt = input.issuedAt ?? new Date().toISOString(); + assertBtcFeeQuoteTimestamps(issuedAt, expiresAt); const quoteRoot = stableBtcOperationRoot('btc-fee-quote', [ - input.quoteId, + quoteId, input.feePurpose, - input.network, + network, sats.toString(), - input.measurementRoot, + measurementRoot, issuedAt, - input.expiresAt, + expiresAt, ]); return { kind: 'btc.fee_quote', - quoteId: assertNonEmptyString(input.quoteId, 'quoteId'), + quoteId, feePurpose: input.feePurpose, - network: assertBitcoinNetwork(input.network), + network, sats, satsPerVbyte: input.satsPerVbyte, - measurementRoot: assertNonEmptyString(input.measurementRoot, 'measurementRoot'), + measurementRoot, quoteRoot, pricingVersion: 'measurement-weight-volume', state: 'quoted', @@ -162,7 +227,7 @@ export function buildBtcFeeQuote(input: { relatedAssetPackId: input.relatedAssetPackId, relatedOrderId: input.relatedOrderId, issuedAt, - expiresAt: assertNonEmptyString(input.expiresAt, 'expiresAt'), + expiresAt, }; } @@ -198,6 +263,7 @@ export function assertBtcFeeQuote(quote: BtcFeeQuote): BtcFeeQuote { assertNonEmptyString(quote.quoteRoot, 'quoteRoot'); assertNonEmptyString(quote.issuedAt, 'issuedAt'); assertNonEmptyString(quote.expiresAt, 'expiresAt'); + assertBtcFeeQuoteTimestamps(quote.issuedAt, quote.expiresAt); return quote; } @@ -350,16 +416,131 @@ export function buildBtcFeeBlockedReadinessReceipt(input: { }; } +export function buildBtcFeeNetworkPolicy(input: { + network?: BitcoinNetwork | null; + environment?: BtcFeeNetworkEnvironment; + valueBearing?: boolean; + valueBearingMainnetApproved?: boolean; +}): BtcFeeNetworkPolicy { + const network = input.network ? assertBitcoinNetwork(input.network) : null; + const environment = input.environment ?? 'staging-testnet'; + const valueBearing = input.valueBearing !== false; + const mainnet = network === 'mainnet'; + const operationalApprovalRequired = mainnet && valueBearing; + const admitted = !operationalApprovalRequired || input.valueBearingMainnetApproved === true; + const blocker = admitted + ? null + : 'Value-bearing BTC fee settlement on mainnet requires explicit operational approval.'; + + return { + kind: 'btc.fee_network_policy', + network, + environment, + valueBearing, + admitted, + operationalApprovalRequired, + mainnet, + proofRoot: stableBtcOperationRoot('btc-fee-network-policy', [ + network ?? 'no-network', + environment, + valueBearing ? 'value-bearing' : 'non-value-bearing', + input.valueBearingMainnetApproved === true ? 'approved' : 'not-approved', + ]), + blocker, + }; +} + +export function deriveBtcFeePsbtHandoffState( + receipt?: BtcFeeTransactionReceipt | null, +): BtcFeePsbtHandoffState { + if (!receipt) return 'not_prepared'; + switch (receipt.finalityState) { + case 'prepared': + return 'prepared_unsigned'; + case 'signed': + return 'signed_ready_to_broadcast'; + case 'broadcast': + return 'broadcast_submitted'; + case 'confirmed': + return 'finality_observed'; + case 'replaced': + case 'reorged': + return 'replacement_or_reorg_repair_required'; + case 'failed': + return 'failed'; + } +} + +export function deriveBtcFeeBroadcastState( + receipt?: BtcFeeTransactionReceipt | null, +): BtcFeeBroadcastObservationState { + if (!receipt) return 'not_broadcast'; + if (receipt.finalityState === 'prepared' || receipt.finalityState === 'signed') { + return 'not_broadcast'; + } + return receipt.finalityState; +} + +export function buildBtcFeeTaprootPsbtPosture(input: { + network?: BitcoinNetwork | null; + receipt?: BtcFeeTransactionReceipt | null; + commitmentMethod?: BtcFeeBitcoinCommitmentMethod; + scriptPath?: BtcFeeTaprootScriptPath; +}): BtcFeeTaprootPsbtPosture { + const network = input.network ? assertBitcoinNetwork(input.network) : null; + const commitmentMethod = input.commitmentMethod ?? 'taproot'; + const scriptPath = input.scriptPath ?? (commitmentMethod === 'taproot' ? 'key_path' : 'unknown'); + const psbtHandoffState = deriveBtcFeePsbtHandoffState(input.receipt); + const broadcastState = deriveBtcFeeBroadcastState(input.receipt); + const taprootRequired = true; + const taprootAdmitted = commitmentMethod === 'taproot'; + + return { + kind: 'btc.fee_taproot_psbt_posture', + chain: 'bitcoin', + network, + commitmentMethod, + scriptPath, + taprootRequired, + taprootAdmitted, + psbtHandoffState, + broadcastState, + proofRoot: stableBtcOperationRoot('btc-fee-taproot-psbt-posture', [ + network ?? 'no-network', + commitmentMethod, + scriptPath, + psbtHandoffState, + broadcastState, + ]), + }; +} + export function buildBtcFeeOperationPosture(input: { quote?: BtcFeeQuote | null; receipt?: BtcFeeTransactionReceipt | null; payerSession?: WalletSignerSession | null; at?: string; allowStoredAuthorizedSession?: boolean; + environment?: BtcFeeNetworkEnvironment; + valueBearingMainnetApproved?: boolean; + commitmentMethod?: BtcFeeBitcoinCommitmentMethod; + scriptPath?: BtcFeeTaprootScriptPath; }): BtcFeeOperationPosture { const quote = input.quote ? assertBtcFeeQuote(input.quote) : null; const receipt = input.receipt || null; const network = quote?.network || receipt?.network || input.payerSession?.network || null; + const networkPolicy = buildBtcFeeNetworkPolicy({ + network, + environment: input.environment, + valueBearing: Boolean(quote || receipt), + valueBearingMainnetApproved: input.valueBearingMainnetApproved, + }); + const taprootScriptPosture = buildBtcFeeTaprootPsbtPosture({ + network, + receipt, + commitmentMethod: input.commitmentMethod, + scriptPath: input.scriptPath, + }); const signerRecovery = buildWalletSignerSessionRecovery({ session: input.payerSession, network, @@ -372,17 +553,34 @@ export function buildBtcFeeOperationPosture(input: { quote, receipt, signerRecovery, + networkPolicy, + taprootScriptPosture, blockerId: signerBlockerId(signerRecovery.state), summary: signerRecovery.blocker || 'Wallet signer session is not ready.', requiredAction: signerRecovery.nextAction, }); } + if (!networkPolicy.admitted) { + return blockedPosture({ + quote, + receipt, + signerRecovery, + networkPolicy, + taprootScriptPosture, + blockerId: 'network-policy', + summary: networkPolicy.blocker || 'BTC fee network policy is blocked.', + requiredAction: 'Use testnet/signet or obtain value-bearing mainnet operational approval.', + }); + } + if (!quote) { return blockedPosture({ quote, receipt, signerRecovery, + networkPolicy, + taprootScriptPosture, blockerId: 'fee-quote', summary: 'No BTC fee quote is attached.', requiredAction: 'Create a BTC fee quote before preparing a PSBT.', @@ -396,6 +594,8 @@ export function buildBtcFeeOperationPosture(input: { quote, receipt, signerRecovery, + networkPolicy, + taprootScriptPosture, blockerId: error instanceof Error && /expired/i.test(error.message) ? 'fee-quote-expired' : 'fee-quote', summary: error instanceof Error ? error.message : 'BTC fee quote is not active.', requiredAction: 'Refresh the BTC fee quote before preparing settlement.', @@ -407,6 +607,8 @@ export function buildBtcFeeOperationPosture(input: { quote, receipt, signerRecovery, + networkPolicy, + taprootScriptPosture, blockerId: 'fee-quote-not-accepted', summary: 'BTC fee quote has not been accepted for PSBT handoff.', requiredAction: 'Accept the BTC fee quote before preparing a PSBT.', @@ -419,6 +621,8 @@ export function buildBtcFeeOperationPosture(input: { quote, receipt, signerRecovery, + networkPolicy, + taprootScriptPosture, canPreparePsbt: true, canSignPsbt: false, canBroadcast: false, @@ -434,6 +638,8 @@ export function buildBtcFeeOperationPosture(input: { quote, receipt, signerRecovery, + networkPolicy, + taprootScriptPosture, canPreparePsbt: false, canSignPsbt: receipt.finalityState === 'prepared', canBroadcast: receipt.finalityState === 'signed', @@ -476,6 +682,8 @@ function blockedPosture(input: { quote: BtcFeeQuote | null; receipt: BtcFeeTransactionReceipt | null; signerRecovery: WalletSignerSessionRecovery; + networkPolicy: BtcFeeNetworkPolicy; + taprootScriptPosture: BtcFeeTaprootPsbtPosture; blockerId: BtcFeeBlockedReadinessBlockerId; summary: string; requiredAction: string; @@ -485,6 +693,8 @@ function blockedPosture(input: { quote: input.quote, receipt: input.receipt, signerRecovery: input.signerRecovery, + networkPolicy: input.networkPolicy, + taprootScriptPosture: input.taprootScriptPosture, blockedReadiness: buildBtcFeeBlockedReadinessReceipt({ blockerId: input.blockerId, summary: input.summary, @@ -503,7 +713,16 @@ function blockedPosture(input: { } type BtcFeeOperationPostureDraft = - Omit & { + Omit< + BtcFeeOperationPosture, + | 'kind' + | 'feeAsset' + | 'network' + | 'noServerCustody' + | 'blockedReadiness' + | 'psbtHandoffState' + | 'broadcastState' + > & { blockedReadiness?: BtcFeeBlockedReadinessReceipt | null; }; @@ -514,6 +733,8 @@ function operationPosture(input: BtcFeeOperationPostureDraft): BtcFeeOperationPo network: input.quote?.network || input.receipt?.network || input.signerRecovery.network, noServerCustody: true, ...input, + psbtHandoffState: input.taprootScriptPosture.psbtHandoffState, + broadcastState: input.taprootScriptPosture.broadcastState, blockedReadiness: input.blockedReadiness || null, }; } @@ -551,3 +772,15 @@ function stableBtcOperationRoot(prefix: string, parts: string[]): string { } return `${prefix}-${(hash >>> 0).toString(16).padStart(8, '0')}`; } + +function assertBtcFeeQuoteTimestamps(issuedAt: string, expiresAt: string): void { + if (!Number.isFinite(Date.parse(issuedAt))) { + throw new Error('BTC fee quote issuedAt must be a valid timestamp.'); + } + if (!Number.isFinite(Date.parse(expiresAt))) { + throw new Error('BTC fee quote expiresAt must be a valid timestamp.'); + } + if (Date.parse(expiresAt) <= Date.parse(issuedAt)) { + throw new Error('BTC fee quote expiresAt must be after issuedAt.'); + } +} diff --git a/scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs b/scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs new file mode 100644 index 000000000..fdce7b415 --- /dev/null +++ b/scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs @@ -0,0 +1,199 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 3 BTC fee quote, signer, PSBT handoff, Taproot posture, network policy, API serialization, docs, and workflow readiness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-3-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 3 work must occur on version/v30 or v30/gate-3-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + 'packages/btd/src/btc-fee-operation.ts', + 'packages/btd/src/bitcoin-fees.ts', + 'packages/btd/__tests__/btc-fee-operation.test.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'packages/btd/README.md', + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + ]) { + assertCheck(failures, fileExists(root, relativePath), `Missing V30 Gate 3 file: ${relativePath}`); + } + + const feeOperation = read(root, 'packages/btd/src/btc-fee-operation.ts'); + const bitcoinFees = read(root, 'packages/btd/src/bitcoin-fees.ts'); + const btdTest = read(root, 'packages/btd/__tests__/btc-fee-operation.test.ts'); + const apiTest = read(root, 'packages/api/src/routes/__tests__/btd-crypto.test.ts'); + const btdReadme = read(root, 'packages/btd/README.md'); + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + for (const symbol of [ + 'BtcFeeNetworkEnvironment', + 'BtcFeePsbtHandoffState', + 'BtcFeeBroadcastObservationState', + 'BtcFeeNetworkPolicy', + 'BtcFeeTaprootPsbtPosture', + 'buildBtcFeeNetworkPolicy', + 'buildBtcFeeTaprootPsbtPosture', + 'deriveBtcFeePsbtHandoffState', + 'deriveBtcFeeBroadcastState', + ]) { + assertCheck(failures, feeOperation.includes(symbol), `BTC fee operation must define/export ${symbol}.`); + } + + for (const field of [ + 'networkPolicy: BtcFeeNetworkPolicy', + 'taprootScriptPosture: BtcFeeTaprootPsbtPosture', + 'psbtHandoffState: BtcFeePsbtHandoffState', + 'broadcastState: BtcFeeBroadcastObservationState', + ]) { + assertCheck(failures, feeOperation.includes(field), `BtcFeeOperationPosture must include ${field}.`); + } + + assertCheck( + failures, + feeOperation.includes("blockerId: 'network-policy'"), + 'BTC fee operation posture must block on network-policy when production-mainnet value-bearing settlement is not admitted.', + ); + assertCheck( + failures, + feeOperation.includes('assertBtcFeeQuoteTimestamps'), + 'BTC fee quotes must validate issuedAt/expiresAt timestamp windows.', + ); + assertCheck( + failures, + bitcoinFees.includes("next.finalityState === 'signed'") && bitcoinFees.includes('signedPsbt'), + 'Signed BTC fee receipt advancement must require signed PSBT evidence.', + ); + + for (const expectedEvidence of [ + 'server_custody_rejected', + 'prepared_unsigned', + 'signed_ready_to_broadcast', + 'replacement_or_reorg_repair_required', + 'production-mainnet', + 'network-policy', + 'BTC fee quote expiresAt must be after issuedAt', + 'signedPsbt must be a non-empty string', + ]) { + assertCheck(failures, btdTest.includes(expectedEvidence), `BTD fee tests must cover ${expectedEvidence}.`); + } + + for (const expectedEvidence of [ + 'psbtHandoffState', + 'broadcastState', + 'networkPolicy', + 'taprootScriptPosture', + 'staging-testnet', + ]) { + assertCheck(failures, apiTest.includes(expectedEvidence), `API route tests must serialize ${expectedEvidence}.`); + } + + assertCheck(failures, btdReadme.includes('BTC fee operation posture'), 'BTD README must document BTC fee operation posture ownership.'); + assertCheck(failures, spec.includes('BtcFeeNetworkPolicy'), 'V30 SPEC must name BtcFeeNetworkPolicy.'); + assertCheck(failures, spec.includes('BtcFeeTaprootPsbtPosture'), 'V30 SPEC must name BtcFeeTaprootPsbtPosture.'); + assertCheck(failures, delta.includes('Gate 3 implementation centers'), 'V30 DELTA must include Gate 3 implementation evidence.'); + assertCheck(failures, notes.includes('Gate 3 Bitcoin Taproot PSBT fee rigor notes'), 'V30 NOTES must include Gate 3 implementation notes.'); + assertCheck(failures, parity.includes('## Gate 3 Parity'), 'V30 PARITY must include Gate 3 parity evidence.'); + assertCheck(failures, parity.includes('Gate 3 accepted boundaries'), 'V30 PARITY must include Gate 3 accepted boundaries.'); + assertCheck(failures, packageJson.includes('"check:v30-gate3"'), 'package.json must expose check:v30-gate3.'); + assertCheck( + failures, + gateWorkflow.includes('check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs'), + 'Gate workflow must run the V30 Gate 3 checker.', + ); + + if (failures.length) { + process.stderr.write('V30 Gate 3 Bitcoin Taproot PSBT fee rigor check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V30 Gate 3 Bitcoin Taproot PSBT fee rigor check passed.\n'); +} + +try { + main(); +} catch (error) { + const detail = error instanceof Error ? error.message : String(error); + process.stderr.write(`${detail}\n`); + process.exitCode = 1; +} From 04a095bedb7d3c1cbb375337ffa27347369a8c70 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 18:03:44 -0300 Subject: [PATCH 04/15] V30 Gate 4: Type AssetPack read receipts Add package-owned BTD AssetPack mint, read, and rights-transfer receipt primitives with source-safe preview, paid unlock, delivery admission, ledger projection, and BTC finality boundaries. Expose receipt construction through BTD API boundaries, stream/store mint/read receipt evidence from the Sandbox harness, and surface receipt payloads through Terminal detail/read models. Update V30 spec family, BTD documentation, gate workflow, and add the Gate 4 checker plus BTD/API/Terminal coverage. --- .github/workflows/bitcode-gate-quality.yml | 1 + BITCODE_SPEC_V30.md | 12 + BITCODE_SPEC_V30_DELTA.md | 24 + BITCODE_SPEC_V30_NOTES.md | 29 + BITCODE_SPEC_V30_PARITY_MATRIX.md | 30 +- package.json | 1 + packages/btd/README.md | 6 + packages/btd/__tests__/api-boundaries.test.ts | 138 +++++ packages/btd/src/api-boundaries.ts | 213 ++++++- packages/btd/src/receipts.ts | 568 ++++++++++++++++++ .../pipeline-hosts/src/asset-pack-harness.ts | 105 +++- ...gate4-btd-assetpack-mint-read-receipts.mjs | 238 ++++++++ .../terminal-transaction-detail-snapshot.ts | 23 + .../terminal-transaction-read-model.ts | 19 +- .../terminalTransactionDetailSnapshot.test.ts | 25 + .../terminalTransactionReadModel.test.ts | 16 + 16 files changed, 1426 insertions(+), 22 deletions(-) create mode 100644 scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 0a963ea8b..dbdda501d 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -82,6 +82,7 @@ jobs: node scripts/check-v30-gate1-roadmap-and-gating.mjs --skip-branch-check node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs --skip-branch-check node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs --skip-branch-check + node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index cf19bc197..219cc4109 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -209,6 +209,18 @@ V30 closes through ten gates: 9. **Gate 9: Interface Integration And Regression Proof** proves current interfaces consume package-owned objects without V29 behavior regression. 10. **Gate 10: V30 Promotion Readiness** validates local/staging proof, generated artifacts, V30 promotion workflow support, and post-promotion V30 active / V31 draft posture. +Gate 4 receipt precision: + +- Mint receipts are source-safe by construction. They may bind a paid unlock + root later, but their own `protectedSourceVisible` posture is always false. +- Read receipts can represent preview, blocked, or paid-unlocked reading. Any + paid delivery admission must include a paid unlock root, delivery admission + root, read right, and ledger projection root. +- Rights-transfer receipts require confirmed BTC fee finality before the BTD + right/license transfer can admit protected source visibility to the Reader. + Prepared, signed, broadcast, replaced, reorged, and failed fee receipts do + not unlock protected source. + ## V30 whole Bitcode operator chain The V30 Terminal operator chain is: diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 1fc889af9..589887915 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -143,6 +143,30 @@ Closure acceptance: - protected source remains hidden before settlement; - receipts are stored, streamed, and rendered through existing execution and Terminal surfaces. +Gate 4 implementation centers on `packages/btd/src/receipts.ts` and the +package API boundary in `packages/btd/src/api-boundaries.ts`. +`BtdAssetPackMintReceipt` extends mint evidence with depositor identity, +source-safe preview root, Finding Fits result root, settlement conservation +root, paid unlock root, delivery admission root, and ledger projection root. +`BtdReadReceipt` records the Reader/Depositor boundary for source-safe preview +or paid unlock and rejects protected source visibility before paid unlock. +`BtdRightsTransferReceipt` requires confirmed BTC fee finality, a read license, +paid unlock, delivery admission, range projection, and ledger projection before +protected source can cross to the Reader. + +The Sandbox harness now stores typed mint/read receipt payloads in settlement +evidence and emits receipt roots in readback telemetry. Terminal detail +snapshots coerce mint/read/rights-transfer receipts from settlement payloads, +and the Terminal transaction read model counts those receipts in closure and +journal surfaces so operators can inspect them through the existing rich +execution detail UI. + +Gate 4 evidence is covered by +`packages/btd/__tests__/api-boundaries.test.ts`, +`uapi/tests/terminalTransactionDetailSnapshot.test.ts`, +`uapi/tests/terminalTransactionReadModel.test.ts`, and +`scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs`. + ### Gate 5: Testnet Ledger Projection Hardening Gate 5 hardens ledger/database/object-storage projection and repair. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index a465d589d..5a4f8b653 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -108,6 +108,35 @@ failure. Signed receipt advancement requires a signed PSBT. Broadcast, confirmed, replaced, and reorged observations require transaction id evidence. Server-custody signer posture remains rejected before PSBT handoff. +## Gate 4 BTD AssetPack mint and read receipt notes + +Gate 4 moves BTD receipt posture from route/runtime convention into package +owned primitives: + +- `BtdAssetPackMintReceipt` binds the deposited AssetPack id, BTD range, + depositor wallet, source manifest root, source-safe preview root, Finding + Fits result root, proof root, settlement conservation root, access policy, + and ledger projection root. It is always source-safe and never exposes + protected source. +- `BtdReadReceipt` binds the Reader wallet, Depositor wallet, accepted Need + root, Finding Fits root, source-safe preview root, paid unlock state, read + right state, delivery admission state, and ledger projection root. It rejects + protected source visibility unless the read is paid-unlocked. +- `BtdRightsTransferReceipt` binds the settled BTD range and read license to a + confirmed BTC fee receipt, paid unlock root, delivery admission root, ledger + anchor, ledger projection root, and Reader/Depositor identities. It is the + receipt boundary where protected source can become visible to the paying + Reader. + +The package API boundary exposes builders for mint receipts, read-receipt +settlements, and rights-transfer receipts so API routes and harness code do not +reimplement receipt policy. The Sandbox harness emits mint/read receipt payloads +and receipt roots inside ledger settlement evidence; rights-transfer receipts +remain absent until BTC fee finality is confirmed. Terminal detail snapshots +coerce receipt payloads under camelCase or database-style snake_case keys, and +the transaction read model counts receipt payloads in closure and journal +availability. + 4. **Gate 4: BTD AssetPack Mint And Read Receipts** - Make BTD mint, read, and rights-transfer receipts typed, proof-rooted, stored, streamed, and source-safe. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index f5da18708..ad6b2cb5b 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -57,7 +57,7 @@ No `_legacy/` source is active source truth. | Roadmap truth | Gate 1 | `SPECIFICATIONS_ROADMAP.md`, README, PR template, workflow posture | drafted | Roadmap states V29 active, V30 draft, and coherent V31-V37 responsibilities. | | Protocol package API boundaries | Gate 2 | `packages/btd/src/api-boundaries.ts`, `packages/api/src/routes/btd-crypto.ts`, package READMEs/tests | drafted | Shared Protocol/BTD objects have package-owned builders, parsers, validators, JSON-safe serializers, and tests. | | Bitcoin Taproot PSBT fee rigor | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, `packages/btd/src/bitcoin-fees.ts`, BTD/API tests, gate checker | drafted | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, Taproot/PSBT aware, and proof-rooted. | -| BTD AssetPack mint/read receipts | Gate 4 | BTD receipt primitives, asset-pack postprocess, harness evidence, Terminal/API readback | pending | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | +| BTD AssetPack mint/read receipts | Gate 4 | `packages/btd/src/receipts.ts`, `packages/btd/src/api-boundaries.ts`, asset-pack harness evidence, Terminal detail snapshot/read model tests, gate checker | drafted | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | | Testnet ledger projection hardening | Gate 5 | BTD reconciliation, Supabase readback, object-storage evidence, repair tests | pending | Ledger/database/object-storage projections are synchronized or blocked with deterministic repair posture. | | Source-to-shares proof cleanup | Gate 6 | BTD/source-to-shares proof primitives, settlement conservation tests | pending | Measurement contribution, fee allocation, zero-cell/refit tail, and conservation invariants are testable. | | Bridge-readiness research boundaries | Gate 7 | Protocol/BTD research notes, policy posture tests, docs | pending | Bridge paths are documented as research until admitted by explicit future proof and policy. | @@ -93,6 +93,9 @@ No `_legacy/` source is active source truth. - Gate 1 does not implement Protocol/BTD package hardening. - Gate 1 does not create `BITCODE_SPEC_V30_PROVEN.md`. +- Gate 1 does not promote `BITCODE_SPEC.txt` to V30. +- Gate 1 may retarget workflows to active V29 / draft V30 so later gates are greenable. +- Gate 1 may update roadmap scope for V31-V37 to align with V28/V29 promotion learning without opening those versions. ## Gate 2 Parity @@ -132,9 +135,28 @@ No `_legacy/` source is active source truth. - Gate 3 does not implement a bridge chain-of-record path. - Gate 3 does not custody Reader private keys or sign PSBTs server-side. - Gate 3 does not replace later Gate 4 BTD mint, read, and rights-transfer receipts. -- Gate 1 does not promote `BITCODE_SPEC.txt` to V30. -- Gate 1 may retarget workflows to active V29 / draft V30 so later gates are greenable. -- Gate 1 may update roadmap scope for V31-V37 to align with V28/V29 promotion learning without opening those versions. + +## Gate 4 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| BTD package owns typed AssetPack mint, read, and rights-transfer receipts | `packages/btd/src/receipts.ts` exports `BtdAssetPackMintReceipt`, `BtdReadReceipt`, `BtdRightsTransferReceipt`, and their builders/assertions | drafted | +| Receipts bind AssetPack ids, BTD ranges, Reader/Depositor identities, source-safe preview roots, paid unlock, delivery admission, and ledger projection roots | Receipt interfaces/builders require those roots and identities, with BTD range conservation checks | drafted | +| Protected source remains hidden before paid unlock | `assertReadDisclosureBoundary` rejects protected source visibility before `paid_unlocked`; `BtdAssetPackMintReceipt` is always `source_safe_preview` | drafted | +| Rights transfer requires confirmed BTC finality before protected source unlock | `buildBtdRightsTransferReceipt` and API-boundary tests require `btcFeeFinalityState: 'confirmed'` | drafted | +| API boundary exposes package-owned receipt construction | `buildBtdMintDraft`, `buildBtdReadReceiptBoundarySettlement`, and `buildBtdAssetPackExchangeSettlement` compose receipt builders | drafted | +| Sandbox harness stores and streams receipt evidence | `packages/pipeline-hosts/src/asset-pack-harness.ts` stores mint/read receipt payloads in ledger settlement evidence and emits receipt roots in readback telemetry | drafted | +| Terminal renders receipt readback through existing detail surfaces | `terminal-transaction-detail-snapshot.ts` coerces receipt payloads and `terminal-transaction-read-model.ts` counts them in closure/journal sections | drafted | +| Tests cover package and Terminal receipt posture | `packages/btd/__tests__/api-boundaries.test.ts`, `uapi/tests/terminalTransactionDetailSnapshot.test.ts`, and `uapi/tests/terminalTransactionReadModel.test.ts` | drafted | +| Gate checker protects the receipt surface | `scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs`, `pnpm run check:v30-gate4`, gate-quality workflow | drafted | + +## Gate 4 accepted boundaries + +- Gate 4 does not require production-mainnet BTC settlement. +- Gate 4 does not broadcast Bitcoin transactions or custody wallet keys. +- Gate 4 does not make protected source visible before paid unlock and delivery admission. +- Gate 4 does not harden all ledger/database/object-storage projection repair; Gate 5 owns that. +- Gate 4 does not finish source-to-shares contribution cleanup; Gate 6 owns that. ## completion condition diff --git a/package.json b/package.json index ccdeca31b..7bdfbaa29 100644 --- a/package.json +++ b/package.json @@ -57,6 +57,7 @@ "check:v30-gate1": "node scripts/check-v30-gate1-roadmap-and-gating.mjs", "check:v30-gate2": "node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs", "check:v30-gate3": "node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs", + "check:v30-gate4": "node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/btd/README.md b/packages/btd/README.md index 7832ec4d9..3cea896d8 100644 --- a/packages/btd/README.md +++ b/packages/btd/README.md @@ -11,6 +11,10 @@ This package owns: - contributor allocation, access evaluation, ancestry review, and revenue routing - wallet-signed BTC fee receipts, ledger anchors, Exchange rights transfers, Terminal journals, reconciliation, telemetry, and upgrade receipts +- typed AssetPack mint/read/rights-transfer receipts that bind BTD ranges, + Reader and Depositor identities, source-safe preview roots, paid unlock, + delivery admission, and ledger projection roots without leaking protected + source before settlement - BTC fee operation posture, including quote lifecycle, signer recovery, no-server-custody PSBT handoff, Taproot/script posture, broadcast/finality observation, replacement/reorg repair, and testnet/mainnet network policy @@ -37,6 +41,8 @@ import { BTD_MAX_MINTABLE_SUPPLY, applyBtdMeasureMint, buildBtdMintDraft, + buildBtdReadReceiptBoundarySettlement, + buildBtdRightsTransferReceipt, buildBtdRegistrySnapshot, toBtdJsonSafe, calculateLlmBtcFeeEstimate, diff --git a/packages/btd/__tests__/api-boundaries.test.ts b/packages/btd/__tests__/api-boundaries.test.ts index 262861cc4..75ce0fab3 100644 --- a/packages/btd/__tests__/api-boundaries.test.ts +++ b/packages/btd/__tests__/api-boundaries.test.ts @@ -1,6 +1,8 @@ import { + buildBtdAssetPackExchangeSettlement, buildBtdMintDraft, buildBtdReadAccessDecision, + buildBtdReadReceiptBoundarySettlement, buildBtdRegistrySnapshot, createBtdMeasureMintState, parseBtdOptionalBigInt, @@ -38,10 +40,26 @@ describe('BTD API boundaries', () => { exchangeSequence: 1n, actorId: 'actor-boundary-1', issuedAt, + depositorWalletId: 'wallet-depositor-boundary', + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', + findingFitsResultRoot: 'finding-fits-root-boundary', + settlementConservationRoot: 'settlement-conservation-root-boundary', + ledgerProjectionRoot: 'ledger-projection-root-boundary', }); expect(draft.kind).toBe('btd_mint_draft'); expect(draft.measureMint.tokenCount).toBe(10_500_000); + expect(draft.assetPackMintReceipt).toMatchObject({ + kind: 'btd.asset_pack_mint_receipt', + depositorWalletId: 'wallet-depositor-boundary', + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', + findingFitsResultRoot: 'finding-fits-root-boundary', + ledgerProjectionRoot: 'ledger-projection-root-boundary', + protectedSourceVisible: false, + }); + expect(draft.terminalJournalEntry.receiptRoots).toContain( + draft.assetPackMintReceipt?.receiptRoot, + ); expect(draft.terminalJournalEntry.transactionKind).toBe('asset_pack_mint'); expect(draft.terminalJournalEntry.actorId).toBe('actor-boundary-1'); }); @@ -119,4 +137,124 @@ describe('BTD API boundaries', () => { expect(decision.decision.decision).toBe('licensed_read'); expect(decision.policyDisclosure.accessPolicyHash).toBe('policy-boundary-hash'); }); + + it('binds source-safe read receipts and paid rights-transfer receipts at package boundaries', () => { + const preview = buildBtdReadReceiptBoundarySettlement({ + actorId: 'actor-boundary-1', + assetPackId: 'asset-pack-boundary-1', + readId: 'read-boundary-1', + readRequestId: 'read-request-boundary-1', + acceptedNeedRoot: 'accepted-need-root-boundary', + findingFitsResultRoot: 'finding-fits-root-boundary', + readerWalletId: 'wallet-reader-boundary', + depositorWalletId: 'wallet-depositor-boundary', + rangeStart: 0, + rangeEndExclusive: 10, + sourceManifestRoot: 'source-root-boundary', + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', + accessPolicyHash: 'policy-boundary-hash', + disclosureState: 'source_safe_preview', + readRightState: 'none', + deliveryAdmissionState: 'blocked', + ledgerProjectionRoot: 'ledger-projection-root-boundary', + exchangeSequence: 4n, + issuedAt, + }); + + expect(preview.readReceipt).toMatchObject({ + kind: 'btd.read_receipt', + disclosureState: 'source_safe_preview', + deliveryAdmissionState: 'blocked', + protectedSourceVisible: false, + paidUnlockRoot: null, + }); + expect(preview.terminalJournalEntry.transactionKind).toBe('read_submission'); + expect(preview.terminalJournalEntry.receiptRoots).toContain(preview.readReceipt.receiptRoot); + + expect(() => + buildBtdReadReceiptBoundarySettlement({ + ...preview.readReceipt, + actorId: 'actor-boundary-1', + exchangeSequence: 5n, + protectedSourceVisible: true, + }), + ).toThrow('Protected source cannot be visible before paid unlock.'); + + const created = buildBtdAssetPackExchangeSettlement({ + action: 'create_order', + orderId: 'order-boundary-1', + orderKind: 'sell', + assetPackId: 'asset-pack-boundary-1', + rangeStart: 0, + rangeEndExclusive: 10, + makerWalletId: 'wallet-depositor-boundary', + priceSats: '1200', + accessPolicyHash: 'policy-boundary-hash', + createdAtExchangeSequence: 6n, + actorId: 'actor-boundary-1', + issuedAt, + }); + const accepted = buildBtdAssetPackExchangeSettlement({ + action: 'accept_order', + previousOrder: created.order, + takerWalletId: 'wallet-reader-boundary', + actorId: 'actor-boundary-1', + issuedAt, + }); + const settled = buildBtdAssetPackExchangeSettlement({ + action: 'settle_order', + previousOrder: accepted.order, + settledAtExchangeSequence: 7n, + ledgerAnchorId: 'ledger-anchor-boundary-1', + actorId: 'actor-boundary-1', + issuedAt, + }); + const transferred = buildBtdAssetPackExchangeSettlement({ + action: 'transfer_rights', + previousOrder: settled.order, + receiptId: 'legacy-transfer-boundary-1', + fromWalletId: 'wallet-depositor-boundary', + toWalletId: 'wallet-reader-boundary', + btcFeeReceiptId: 'btc-fee-boundary-1', + btcFeeFinalityState: 'confirmed', + readLicenseId: 'read-license-boundary-1', + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', + paidUnlockRoot: 'paid-unlock-root-boundary', + deliveryAdmissionRoot: 'delivery-admission-root-boundary', + ledgerProjectionRoot: 'ledger-projection-root-boundary', + actorId: 'actor-boundary-1', + issuedAt, + }); + + expect(transferred.btdRightsTransferReceipt).toMatchObject({ + kind: 'btd.rights_transfer_receipt', + readerWalletId: 'wallet-reader-boundary', + depositorWalletId: 'wallet-depositor-boundary', + btcFeeFinalityState: 'confirmed', + deliveryAdmissionState: 'admitted', + protectedSourceVisible: true, + }); + expect(transferred.terminalJournalEntry.receiptRoots).toContain( + transferred.btdRightsTransferReceipt?.receiptRoot, + ); + + expect(() => + buildBtdAssetPackExchangeSettlement({ + action: 'transfer_rights', + previousOrder: settled.order, + receiptId: 'legacy-transfer-boundary-2', + fromWalletId: 'wallet-depositor-boundary', + toWalletId: 'wallet-reader-boundary', + btcFeeReceiptId: 'btc-fee-boundary-2', + btcFeeFinalityState: 'broadcast', + readLicenseId: 'read-license-boundary-2', + sourceSafePreviewRoot: 'source-safe-preview-root-boundary', + paidUnlockRoot: 'paid-unlock-root-boundary', + deliveryAdmissionRoot: 'delivery-admission-root-boundary', + ledgerProjectionRoot: 'ledger-projection-root-boundary', + actorId: 'actor-boundary-1', + issuedAt, + }), + ).toThrow('Rights transfer receipt requires confirmed BTC fee finality.'); + }); }); diff --git a/packages/btd/src/api-boundaries.ts b/packages/btd/src/api-boundaries.ts index 4c61a214f..5fab4b18a 100644 --- a/packages/btd/src/api-boundaries.ts +++ b/packages/btd/src/api-boundaries.ts @@ -79,7 +79,12 @@ import { createBtdMeasureMintState, } from './measuremint'; import { allocateAssetPackRange } from './range'; -import { buildBtdMintReceipt } from './receipts'; +import { + buildBtdAssetPackMintReceipt, + buildBtdMintReceipt, + buildBtdReadReceipt, + buildBtdRightsTransferReceipt, +} from './receipts'; import type { DatabaseProjectedFact, LedgerObservedFact, @@ -148,6 +153,13 @@ export interface BtdMintDraftInput { exchangeSequence: bigint; actorId?: string; issuedAt?: string; + depositorWalletId?: string; + sourceSafePreviewRoot?: string; + findingFitsResultRoot?: string; + settlementConservationRoot?: string; + ledgerProjectionRoot?: string; + paidUnlockRoot?: string | null; + deliveryAdmissionRoot?: string | null; } export interface BtdMintDraft { @@ -157,12 +169,50 @@ export interface BtdMintDraft { measureMint: ReturnType['receipt']; rangeAllocation?: ReturnType; mintReceipt?: ReturnType; + assetPackMintReceipt?: ReturnType; contributorAllocation?: ReturnType; terminalJournalEntry: ReturnType; blocking: boolean; zeroCell: boolean; } +export interface BtdReadReceiptBoundaryInput { + actorId: string; + receiptId?: string; + assetPackId: string; + readId: string; + readRequestId: string; + acceptedNeedRoot: string; + findingFitsResultRoot: string; + readerWalletId: string; + depositorWalletId: string; + rangeStart: number; + rangeEndExclusive: number; + tokenCount?: number; + sourceManifestRoot: string; + sourceSafePreviewRoot: string; + accessPolicyHash: string; + disclosureState: Parameters[0]['disclosureState']; + readRightState: Parameters[0]['readRightState']; + paidUnlockRoot?: string | null; + deliveryAdmissionState: Parameters[0]['deliveryAdmissionState']; + deliveryAdmissionRoot?: string | null; + ledgerProjectionRoot: string; + protectedSourceVisible?: boolean; + exchangeSequence: bigint; + commitToRegistry?: boolean; + issuedAt?: string; +} + +export interface BtdReadReceiptBoundarySettlement { + kind: 'btd_read_receipt_boundary_settlement'; + actorId: string; + readReceipt: ReturnType; + terminalJournalEntry: ReturnType; + registryWrite?: unknown; + committed: boolean; +} + export interface BtdReadAccessInput { walletId: string; assetPackId: string; @@ -331,6 +381,15 @@ export interface BtdAssetPackExchangeInput { fromWalletId?: string; toWalletId?: string; btcFeeReceiptId?: string; + btcFeeFinalityState?: BtcFeeFinalityState; + readLicenseId?: string; + readerWalletId?: string; + depositorWalletId?: string; + sourceSafePreviewRoot?: string; + paidUnlockRoot?: string; + deliveryAdmissionRoot?: string; + ledgerProjectionRoot?: string; + protectedSourceVisible?: boolean; commitToRegistry?: boolean; actorId?: string; issuedAt?: string; @@ -444,6 +503,7 @@ export interface BtdAssetPackExchangeSettlement { action: BtdAssetPackExchangeAction; order?: AssetPackExchangeOrder; rightsTransfer?: AssetPackRightsTransferReceipt; + btdRightsTransferReceipt?: ReturnType; terminalJournalEntry: ReturnType; registryWrite?: unknown; committed: boolean; @@ -584,6 +644,21 @@ export function buildBtdMintDraft(input: BtdMintDraftInput): BtdMintDraft { ) : undefined; const mintReceipt = rangeAllocation ? buildBtdMintReceipt(rangeAllocation, issuedAt) : undefined; + const assetPackMintReceipt = + mintReceipt && shouldBuildAssetPackMintReceipt(input) + ? buildBtdAssetPackMintReceipt({ + mintReceipt, + readId: input.readId, + depositorWalletId: input.depositorWalletId, + sourceSafePreviewRoot: input.sourceSafePreviewRoot, + findingFitsResultRoot: input.findingFitsResultRoot ?? input.fitReceiptRoot, + settlementConservationRoot: input.settlementConservationRoot, + ledgerProjectionRoot: input.ledgerProjectionRoot, + paidUnlockRoot: input.paidUnlockRoot, + deliveryAdmissionRoot: input.deliveryAdmissionRoot, + issuedAt, + }) + : undefined; const contributorAllocation = rangeAllocation && input.contributors?.length ? allocateBtdContributorCells({ @@ -598,6 +673,7 @@ export function buildBtdMintDraft(input: BtdMintDraftInput): BtdMintDraft { measurement.measurementId, buildBtdStableId('btd-measure-mint', [input.assetPackId, input.exchangeSequence.toString()]), mintReceipt ? buildBtdStableId('btd-asset-pack-mint', [input.assetPackId, mintReceipt.issuedAt]) : null, + assetPackMintReceipt?.receiptRoot ?? null, contributorAllocation ? buildBtdStableId('btd-contributor-allocation', [input.assetPackId, contributorAllocation.issuedAt]) : null, @@ -627,6 +703,7 @@ export function buildBtdMintDraft(input: BtdMintDraftInput): BtdMintDraft { measureMint: measureMint.receipt, rangeAllocation, mintReceipt, + assetPackMintReceipt, contributorAllocation, terminalJournalEntry, blocking: false, @@ -676,6 +753,71 @@ export function buildBtdReadAccessDecision( }; } +export function buildBtdReadReceiptBoundarySettlement( + input: BtdReadReceiptBoundaryInput, +): Omit { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + const readReceipt = buildBtdReadReceipt({ + receiptId: input.receiptId, + assetPackId: input.assetPackId, + readId: input.readId, + readRequestId: input.readRequestId, + acceptedNeedRoot: input.acceptedNeedRoot, + findingFitsResultRoot: input.findingFitsResultRoot, + readerWalletId: input.readerWalletId, + depositorWalletId: input.depositorWalletId, + rangeStart: input.rangeStart, + rangeEndExclusive: input.rangeEndExclusive, + tokenCount: input.tokenCount, + sourceManifestRoot: input.sourceManifestRoot, + sourceSafePreviewRoot: input.sourceSafePreviewRoot, + accessPolicyHash: input.accessPolicyHash, + disclosureState: input.disclosureState, + readRightState: input.readRightState, + paidUnlockRoot: input.paidUnlockRoot, + deliveryAdmissionState: input.deliveryAdmissionState, + deliveryAdmissionRoot: input.deliveryAdmissionRoot, + ledgerProjectionRoot: input.ledgerProjectionRoot, + protectedSourceVisible: input.protectedSourceVisible, + issuedAt: input.issuedAt, + }); + const transactionKind = + readReceipt.deliveryAdmissionState === 'admitted' + ? 'licensed_read_purchase' + : 'read_submission'; + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-read-receipt', [ + readReceipt.assetPackId, + readReceipt.readId, + readReceipt.readerWalletId, + readReceipt.disclosureState, + ]), + transactionKind, + actorId, + preStateRoot: buildBtdStableId('btd-read-receipt-pre-state', [ + readReceipt.assetPackId, + readReceipt.readId, + ]), + postStateRoot: buildBtdStableId('btd-read-receipt-post-state', [ + readReceipt.assetPackId, + readReceipt.readId, + readReceipt.disclosureState, + readReceipt.deliveryAdmissionState, + ]), + receiptRoots: [readReceipt.receiptRoot], + ledgerAnchorIds: [], + exchangeSequence: input.exchangeSequence, + issuedAt: input.issuedAt, + }); + + return { + kind: 'btd_read_receipt_boundary_settlement', + actorId, + readReceipt, + terminalJournalEntry, + }; +} + export function buildBtdOrganizationInterfaceAuthorityDecision( input: BtdOrganizationInterfaceAuthorityRouteInput & { actorId: string }, ): BtdOrganizationInterfaceAuthorityRouteDecision { @@ -893,6 +1035,32 @@ export function buildBtdAssetPackExchangeSettlement( ): Omit { const actorId = assertNonEmptyString(input.actorId, 'actorId'); const { order, rightsTransfer, exchangeSequence } = buildAssetPackExchangeForAction(input); + const btdRightsTransferReceipt = + rightsTransfer && shouldBuildBtdRightsTransferReceipt(input) + ? buildBtdRightsTransferReceipt({ + orderId: rightsTransfer.orderId, + assetPackId: rightsTransfer.assetPackId, + rangeStart: rightsTransfer.rangeStart, + rangeEndExclusive: rightsTransfer.rangeEndExclusive, + fromWalletId: rightsTransfer.fromWalletId, + toWalletId: rightsTransfer.toWalletId, + readerWalletId: input.readerWalletId ?? rightsTransfer.toWalletId, + depositorWalletId: input.depositorWalletId ?? rightsTransfer.fromWalletId, + priceSats: rightsTransfer.priceSats, + accessPolicyHash: rightsTransfer.accessPolicyHash, + btcFeeReceiptId: rightsTransfer.btcFeeReceiptId, + btcFeeFinalityState: input.btcFeeFinalityState, + readLicenseId: input.readLicenseId, + sourceSafePreviewRoot: input.sourceSafePreviewRoot, + paidUnlockRoot: input.paidUnlockRoot, + deliveryAdmissionRoot: input.deliveryAdmissionRoot, + ledgerAnchorId: rightsTransfer.ledgerAnchorId, + ledgerProjectionRoot: input.ledgerProjectionRoot, + exchangeSequence: rightsTransfer.exchangeSequence, + protectedSourceVisible: input.protectedSourceVisible, + issuedAt: input.issuedAt, + }) + : undefined; const receiptRoot = rightsTransfer?.receiptId ?? order?.orderId; if (!receiptRoot) { throw new Error('AssetPack Exchange settlement requires an order or rights-transfer receipt.'); @@ -912,9 +1080,11 @@ export function buildBtdAssetPackExchangeSettlement( postStateRoot: buildBtdStableId('asset-pack-exchange-post-state', [ order?.orderId ?? rightsTransfer?.orderId ?? receiptRoot, order?.orderState ?? 'rights_transfer', - rightsTransfer?.btcFeeReceiptId ?? 'no-fee', + btdRightsTransferReceipt?.paidUnlockRoot ?? rightsTransfer?.btcFeeReceiptId ?? 'no-fee', ]), - receiptRoots: [receiptRoot], + receiptRoots: [receiptRoot, btdRightsTransferReceipt?.receiptRoot].filter( + (value): value is string => Boolean(value), + ), ledgerAnchorIds: [order?.ledgerAnchorId, rightsTransfer?.ledgerAnchorId].filter( (value): value is string => Boolean(value), ), @@ -928,6 +1098,7 @@ export function buildBtdAssetPackExchangeSettlement( action: input.action, order, rightsTransfer, + btdRightsTransferReceipt, terminalJournalEntry, }; } @@ -1209,6 +1380,22 @@ function assertMintDraftAdmission(input: BtdMintDraftInput): void { } } +function shouldBuildAssetPackMintReceipt( + input: BtdMintDraftInput, +): input is BtdMintDraftInput & { + depositorWalletId: string; + sourceSafePreviewRoot: string; + settlementConservationRoot: string; + ledgerProjectionRoot: string; +} { + return Boolean( + input.depositorWalletId && + input.sourceSafePreviewRoot && + input.settlementConservationRoot && + input.ledgerProjectionRoot, + ); +} + function normalizeMeasureMintState(state?: BtdMeasureMintState): BtdMeasureMintState { if (!state) { return createBtdMeasureMintState(); @@ -1481,6 +1668,26 @@ function buildAssetPackExchangeForAction(input: BtdAssetPackExchangeInput): { } } +function shouldBuildBtdRightsTransferReceipt( + input: BtdAssetPackExchangeInput, +): input is BtdAssetPackExchangeInput & { + btcFeeFinalityState: BtcFeeFinalityState; + readLicenseId: string; + sourceSafePreviewRoot: string; + paidUnlockRoot: string; + deliveryAdmissionRoot: string; + ledgerProjectionRoot: string; +} { + return Boolean( + input.btcFeeFinalityState && + input.readLicenseId && + input.sourceSafePreviewRoot && + input.paidUnlockRoot && + input.deliveryAdmissionRoot && + input.ledgerProjectionRoot, + ); +} + function normalizeWalletSignerSession( session: WalletSignerSession | BtdWalletSignerSessionInput, ): WalletSignerSession { diff --git a/packages/btd/src/receipts.ts b/packages/btd/src/receipts.ts index f85c28c52..cc6450110 100644 --- a/packages/btd/src/receipts.ts +++ b/packages/btd/src/receipts.ts @@ -1,9 +1,14 @@ +import { createHash } from 'crypto'; +import type { BtcFeeFinalityState } from './bitcoin-fees'; import { + BITCODE_FEE_ASSET, BTD_MAX_MINTABLE_SUPPLY, BtdTokenId, assertNonEmptyString, assertNonNegativeSafeInteger, + assertPositiveBigInt, assertPositiveSafeInteger, + toBigIntAmount, } from './constants'; import { BtdRangeAllocationResult } from './range'; @@ -106,3 +111,566 @@ export function assertBtdMintReceipt(receipt: BtdMintReceipt): BtdMintReceipt { return receipt; } + +export type BtdAssetPackDisclosureState = + | 'blocked' + | 'source_safe_preview' + | 'paid_unlocked'; + +export type BtdReadRightState = 'none' | 'owner_read' | 'licensed_read'; + +export type BtdDeliveryAdmissionState = 'blocked' | 'admitted'; + +export interface BtdAssetPackMintReceiptInput { + receiptId?: string; + mintReceipt: BtdMintReceipt; + readId: string; + depositorWalletId: string; + sourceSafePreviewRoot: string; + findingFitsResultRoot?: string; + settlementConservationRoot: string; + ledgerProjectionRoot: string; + paidUnlockRoot?: string | null; + deliveryAdmissionRoot?: string | null; + issuedAt?: string; +} + +export interface BtdAssetPackMintReceipt { + kind: 'btd.asset_pack_mint_receipt'; + receiptId: string; + assetPackId: string; + readId: string; + depositorWalletId: string; + rangeStart: BtdTokenId; + rangeEndExclusive: BtdTokenId; + tokenCount: number; + totalMintedBefore: number; + totalMintedAfter: number; + maxSupply: typeof BTD_MAX_MINTABLE_SUPPLY; + sourceManifestRoot: string; + sourceSafePreviewRoot: string; + measurementReceiptRoot: string; + findingFitsResultRoot: string; + proofRoot: string; + settlementJournalRoot: string; + settlementConservationRoot: string; + dedupeReceiptRoot: string; + exchangeReceiptRoot: string; + accessPolicyId: string; + accessPolicyHash: string; + ledgerProjectionRoot: string; + paidUnlockRoot: string | null; + deliveryAdmissionRoot: string | null; + disclosureState: Extract; + protectedSourceVisible: false; + mintedAtExchangeSequence: bigint; + receiptRoot: string; + issuedAt: string; +} + +export interface BtdReadReceiptInput { + receiptId?: string; + assetPackId: string; + readId: string; + readRequestId: string; + acceptedNeedRoot: string; + findingFitsResultRoot: string; + readerWalletId: string; + depositorWalletId: string; + rangeStart: BtdTokenId; + rangeEndExclusive: BtdTokenId; + tokenCount?: number; + sourceManifestRoot: string; + sourceSafePreviewRoot: string; + accessPolicyHash: string; + disclosureState: BtdAssetPackDisclosureState; + readRightState: BtdReadRightState; + paidUnlockRoot?: string | null; + deliveryAdmissionState: BtdDeliveryAdmissionState; + deliveryAdmissionRoot?: string | null; + ledgerProjectionRoot: string; + protectedSourceVisible?: boolean; + issuedAt?: string; +} + +export interface BtdReadReceipt { + kind: 'btd.read_receipt'; + receiptId: string; + assetPackId: string; + readId: string; + readRequestId: string; + acceptedNeedRoot: string; + findingFitsResultRoot: string; + readerWalletId: string; + depositorWalletId: string; + rangeStart: BtdTokenId; + rangeEndExclusive: BtdTokenId; + tokenCount: number; + sourceManifestRoot: string; + sourceSafePreviewRoot: string; + accessPolicyHash: string; + disclosureState: BtdAssetPackDisclosureState; + readRightState: BtdReadRightState; + paidUnlockRoot: string | null; + deliveryAdmissionState: BtdDeliveryAdmissionState; + deliveryAdmissionRoot: string | null; + ledgerProjectionRoot: string; + protectedSourceVisible: boolean; + receiptRoot: string; + issuedAt: string; +} + +export interface BtdRightsTransferReceiptInput { + receiptId?: string; + orderId: string; + assetPackId: string; + rangeStart: BtdTokenId; + rangeEndExclusive: BtdTokenId; + tokenCount?: number; + fromWalletId: string; + toWalletId: string; + readerWalletId: string; + depositorWalletId: string; + priceSats: bigint | number | string; + accessPolicyHash: string; + btcFeeReceiptId: string; + btcFeeFinalityState: BtcFeeFinalityState; + readLicenseId: string; + sourceSafePreviewRoot: string; + paidUnlockRoot: string; + deliveryAdmissionRoot: string; + ledgerAnchorId: string; + ledgerProjectionRoot: string; + exchangeSequence: bigint; + protectedSourceVisible?: boolean; + issuedAt?: string; +} + +export interface BtdRightsTransferReceipt { + kind: 'btd.rights_transfer_receipt'; + receiptId: string; + orderId: string; + assetPackId: string; + rangeStart: BtdTokenId; + rangeEndExclusive: BtdTokenId; + tokenCount: number; + fromWalletId: string; + toWalletId: string; + readerWalletId: string; + depositorWalletId: string; + priceAsset: typeof BITCODE_FEE_ASSET; + priceSats: bigint; + accessPolicyHash: string; + btcFeeReceiptId: string; + btcFeeFinalityState: Extract; + readLicenseId: string; + sourceSafePreviewRoot: string; + paidUnlockRoot: string; + deliveryAdmissionState: Extract; + deliveryAdmissionRoot: string; + ledgerAnchorId: string; + ledgerProjectionRoot: string; + protectedSourceVisible: boolean; + exchangeSequence: bigint; + receiptRoot: string; + issuedAt: string; +} + +export function buildBtdAssetPackMintReceipt( + input: BtdAssetPackMintReceiptInput, +): BtdAssetPackMintReceipt { + const mintReceipt = assertBtdMintReceipt(input.mintReceipt); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const findingFitsResultRoot = assertNonEmptyString( + input.findingFitsResultRoot ?? mintReceipt.fitReceiptRoot, + 'findingFitsResultRoot', + ); + const paidUnlockRoot = normalizeOptionalRoot(input.paidUnlockRoot, 'paidUnlockRoot'); + const deliveryAdmissionRoot = normalizeOptionalRoot( + input.deliveryAdmissionRoot, + 'deliveryAdmissionRoot', + ); + const receiptId = + input.receiptId ?? + buildBtdReceiptStableId('btd-asset-pack-mint-receipt', [ + mintReceipt.assetPackId, + input.readId, + mintReceipt.rangeStart, + mintReceipt.rangeEndExclusive, + mintReceipt.mintedAtExchangeSequence, + ]); + const receiptRoot = buildBtdReceiptStableId('btd-asset-pack-mint-root', [ + receiptId, + mintReceipt.sourceManifestRoot, + input.sourceSafePreviewRoot, + findingFitsResultRoot, + input.ledgerProjectionRoot, + ]); + + return assertBtdAssetPackMintReceipt({ + kind: 'btd.asset_pack_mint_receipt', + receiptId, + assetPackId: mintReceipt.assetPackId, + readId: assertNonEmptyString(input.readId, 'readId'), + depositorWalletId: assertNonEmptyString(input.depositorWalletId, 'depositorWalletId'), + rangeStart: mintReceipt.rangeStart, + rangeEndExclusive: mintReceipt.rangeEndExclusive, + tokenCount: mintReceipt.tokenCount, + totalMintedBefore: mintReceipt.totalMintedBefore, + totalMintedAfter: mintReceipt.totalMintedAfter, + maxSupply: mintReceipt.maxSupply, + sourceManifestRoot: mintReceipt.sourceManifestRoot, + sourceSafePreviewRoot: assertNonEmptyString(input.sourceSafePreviewRoot, 'sourceSafePreviewRoot'), + measurementReceiptRoot: mintReceipt.measurementReceiptRoot, + findingFitsResultRoot, + proofRoot: mintReceipt.proofRoot, + settlementJournalRoot: mintReceipt.settlementJournalRoot, + settlementConservationRoot: assertNonEmptyString( + input.settlementConservationRoot, + 'settlementConservationRoot', + ), + dedupeReceiptRoot: mintReceipt.dedupeReceiptRoot, + exchangeReceiptRoot: mintReceipt.exchangeReceiptRoot, + accessPolicyId: mintReceipt.accessPolicyId, + accessPolicyHash: mintReceipt.accessPolicyHash, + ledgerProjectionRoot: assertNonEmptyString(input.ledgerProjectionRoot, 'ledgerProjectionRoot'), + paidUnlockRoot, + deliveryAdmissionRoot, + disclosureState: 'source_safe_preview', + protectedSourceVisible: false, + mintedAtExchangeSequence: mintReceipt.mintedAtExchangeSequence, + receiptRoot, + issuedAt, + }); +} + +export function assertBtdAssetPackMintReceipt( + receipt: BtdAssetPackMintReceipt, +): BtdAssetPackMintReceipt { + if (receipt.kind !== 'btd.asset_pack_mint_receipt') { + throw new Error('Invalid BTD AssetPack mint receipt kind.'); + } + assertCommonAssetPackReceiptFields(receipt); + assertNonEmptyString(receipt.readId, 'readId'); + assertNonEmptyString(receipt.depositorWalletId, 'depositorWalletId'); + assertNonEmptyString(receipt.sourceManifestRoot, 'sourceManifestRoot'); + assertNonEmptyString(receipt.sourceSafePreviewRoot, 'sourceSafePreviewRoot'); + assertNonEmptyString(receipt.measurementReceiptRoot, 'measurementReceiptRoot'); + assertNonEmptyString(receipt.findingFitsResultRoot, 'findingFitsResultRoot'); + assertNonEmptyString(receipt.proofRoot, 'proofRoot'); + assertNonEmptyString(receipt.settlementJournalRoot, 'settlementJournalRoot'); + assertNonEmptyString(receipt.settlementConservationRoot, 'settlementConservationRoot'); + assertNonEmptyString(receipt.dedupeReceiptRoot, 'dedupeReceiptRoot'); + assertNonEmptyString(receipt.exchangeReceiptRoot, 'exchangeReceiptRoot'); + assertNonEmptyString(receipt.accessPolicyId, 'accessPolicyId'); + assertNonEmptyString(receipt.accessPolicyHash, 'accessPolicyHash'); + assertNonEmptyString(receipt.ledgerProjectionRoot, 'ledgerProjectionRoot'); + assertNonEmptyString(receipt.receiptRoot, 'receiptRoot'); + assertNonEmptyString(receipt.issuedAt, 'issuedAt'); + assertReceiptRange(receipt); + assertNonNegativeSafeInteger(receipt.totalMintedBefore, 'totalMintedBefore'); + assertPositiveSafeInteger(receipt.totalMintedAfter, 'totalMintedAfter'); + if (receipt.maxSupply !== BTD_MAX_MINTABLE_SUPPLY) { + throw new Error(`AssetPack mint receipt maxSupply must be ${BTD_MAX_MINTABLE_SUPPLY}.`); + } + if (receipt.totalMintedAfter !== receipt.totalMintedBefore + receipt.tokenCount) { + throw new Error('AssetPack mint receipt does not conserve supply.'); + } + if (receipt.disclosureState !== 'source_safe_preview' || receipt.protectedSourceVisible !== false) { + throw new Error('AssetPack mint receipt must remain source-safe before settlement.'); + } + assertPositiveBigInt(receipt.mintedAtExchangeSequence, 'mintedAtExchangeSequence'); + return receipt; +} + +export function buildBtdReadReceipt(input: BtdReadReceiptInput): BtdReadReceipt { + const range = normalizeReceiptRange(input); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const paidUnlockRoot = normalizeOptionalRoot(input.paidUnlockRoot, 'paidUnlockRoot'); + const deliveryAdmissionRoot = normalizeOptionalRoot( + input.deliveryAdmissionRoot, + 'deliveryAdmissionRoot', + ); + const protectedSourceVisible = Boolean(input.protectedSourceVisible); + assertReadDisclosureBoundary({ + disclosureState: input.disclosureState, + readRightState: input.readRightState, + paidUnlockRoot, + deliveryAdmissionState: input.deliveryAdmissionState, + deliveryAdmissionRoot, + protectedSourceVisible, + }); + const receiptId = + input.receiptId ?? + buildBtdReceiptStableId('btd-read-receipt', [ + input.assetPackId, + input.readId, + input.readRequestId, + input.readerWalletId, + range.rangeStart, + range.rangeEndExclusive, + input.disclosureState, + ]); + const receiptRoot = buildBtdReceiptStableId('btd-read-receipt-root', [ + receiptId, + input.acceptedNeedRoot, + input.findingFitsResultRoot, + input.sourceSafePreviewRoot, + paidUnlockRoot ?? 'unpaid', + input.ledgerProjectionRoot, + ]); + + return assertBtdReadReceipt({ + kind: 'btd.read_receipt', + receiptId, + assetPackId: assertNonEmptyString(input.assetPackId, 'assetPackId'), + readId: assertNonEmptyString(input.readId, 'readId'), + readRequestId: assertNonEmptyString(input.readRequestId, 'readRequestId'), + acceptedNeedRoot: assertNonEmptyString(input.acceptedNeedRoot, 'acceptedNeedRoot'), + findingFitsResultRoot: assertNonEmptyString(input.findingFitsResultRoot, 'findingFitsResultRoot'), + readerWalletId: assertNonEmptyString(input.readerWalletId, 'readerWalletId'), + depositorWalletId: assertNonEmptyString(input.depositorWalletId, 'depositorWalletId'), + rangeStart: range.rangeStart, + rangeEndExclusive: range.rangeEndExclusive, + tokenCount: range.tokenCount, + sourceManifestRoot: assertNonEmptyString(input.sourceManifestRoot, 'sourceManifestRoot'), + sourceSafePreviewRoot: assertNonEmptyString(input.sourceSafePreviewRoot, 'sourceSafePreviewRoot'), + accessPolicyHash: assertNonEmptyString(input.accessPolicyHash, 'accessPolicyHash'), + disclosureState: input.disclosureState, + readRightState: input.readRightState, + paidUnlockRoot, + deliveryAdmissionState: input.deliveryAdmissionState, + deliveryAdmissionRoot, + ledgerProjectionRoot: assertNonEmptyString(input.ledgerProjectionRoot, 'ledgerProjectionRoot'), + protectedSourceVisible, + receiptRoot, + issuedAt, + }); +} + +export function assertBtdReadReceipt(receipt: BtdReadReceipt): BtdReadReceipt { + if (receipt.kind !== 'btd.read_receipt') { + throw new Error('Invalid BTD read receipt kind.'); + } + assertCommonAssetPackReceiptFields(receipt); + assertNonEmptyString(receipt.readId, 'readId'); + assertNonEmptyString(receipt.readRequestId, 'readRequestId'); + assertNonEmptyString(receipt.acceptedNeedRoot, 'acceptedNeedRoot'); + assertNonEmptyString(receipt.findingFitsResultRoot, 'findingFitsResultRoot'); + assertNonEmptyString(receipt.readerWalletId, 'readerWalletId'); + assertNonEmptyString(receipt.depositorWalletId, 'depositorWalletId'); + assertNonEmptyString(receipt.sourceManifestRoot, 'sourceManifestRoot'); + assertNonEmptyString(receipt.sourceSafePreviewRoot, 'sourceSafePreviewRoot'); + assertNonEmptyString(receipt.accessPolicyHash, 'accessPolicyHash'); + assertNonEmptyString(receipt.ledgerProjectionRoot, 'ledgerProjectionRoot'); + assertNonEmptyString(receipt.receiptRoot, 'receiptRoot'); + assertNonEmptyString(receipt.issuedAt, 'issuedAt'); + assertReceiptRange(receipt); + assertReadDisclosureBoundary(receipt); + return receipt; +} + +export function buildBtdRightsTransferReceipt( + input: BtdRightsTransferReceiptInput, +): BtdRightsTransferReceipt { + const range = normalizeReceiptRange(input); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const priceSats = toBigIntAmount(input.priceSats, 'priceSats'); + if (priceSats <= 0n) { + throw new Error('Rights transfer receipt priceSats must be positive.'); + } + if (input.btcFeeFinalityState !== 'confirmed') { + throw new Error('Rights transfer receipt requires confirmed BTC fee finality.'); + } + const receiptId = + input.receiptId ?? + buildBtdReceiptStableId('btd-rights-transfer-receipt', [ + input.orderId, + input.assetPackId, + input.fromWalletId, + input.toWalletId, + input.exchangeSequence, + ]); + const receiptRoot = buildBtdReceiptStableId('btd-rights-transfer-receipt-root', [ + receiptId, + input.btcFeeReceiptId, + input.readLicenseId, + input.paidUnlockRoot, + input.deliveryAdmissionRoot, + input.ledgerProjectionRoot, + ]); + + return assertBtdRightsTransferReceipt({ + kind: 'btd.rights_transfer_receipt', + receiptId, + orderId: assertNonEmptyString(input.orderId, 'orderId'), + assetPackId: assertNonEmptyString(input.assetPackId, 'assetPackId'), + rangeStart: range.rangeStart, + rangeEndExclusive: range.rangeEndExclusive, + tokenCount: range.tokenCount, + fromWalletId: assertNonEmptyString(input.fromWalletId, 'fromWalletId'), + toWalletId: assertNonEmptyString(input.toWalletId, 'toWalletId'), + readerWalletId: assertNonEmptyString(input.readerWalletId, 'readerWalletId'), + depositorWalletId: assertNonEmptyString(input.depositorWalletId, 'depositorWalletId'), + priceAsset: BITCODE_FEE_ASSET, + priceSats, + accessPolicyHash: assertNonEmptyString(input.accessPolicyHash, 'accessPolicyHash'), + btcFeeReceiptId: assertNonEmptyString(input.btcFeeReceiptId, 'btcFeeReceiptId'), + btcFeeFinalityState: input.btcFeeFinalityState, + readLicenseId: assertNonEmptyString(input.readLicenseId, 'readLicenseId'), + sourceSafePreviewRoot: assertNonEmptyString(input.sourceSafePreviewRoot, 'sourceSafePreviewRoot'), + paidUnlockRoot: assertNonEmptyString(input.paidUnlockRoot, 'paidUnlockRoot'), + deliveryAdmissionState: 'admitted', + deliveryAdmissionRoot: assertNonEmptyString(input.deliveryAdmissionRoot, 'deliveryAdmissionRoot'), + ledgerAnchorId: assertNonEmptyString(input.ledgerAnchorId, 'ledgerAnchorId'), + ledgerProjectionRoot: assertNonEmptyString(input.ledgerProjectionRoot, 'ledgerProjectionRoot'), + protectedSourceVisible: input.protectedSourceVisible ?? true, + exchangeSequence: assertPositiveBigInt(input.exchangeSequence, 'exchangeSequence'), + receiptRoot, + issuedAt, + }); +} + +export function assertBtdRightsTransferReceipt( + receipt: BtdRightsTransferReceipt, +): BtdRightsTransferReceipt { + if (receipt.kind !== 'btd.rights_transfer_receipt') { + throw new Error('Invalid BTD rights transfer receipt kind.'); + } + assertCommonAssetPackReceiptFields(receipt); + assertNonEmptyString(receipt.orderId, 'orderId'); + assertNonEmptyString(receipt.fromWalletId, 'fromWalletId'); + assertNonEmptyString(receipt.toWalletId, 'toWalletId'); + assertNonEmptyString(receipt.readerWalletId, 'readerWalletId'); + assertNonEmptyString(receipt.depositorWalletId, 'depositorWalletId'); + assertNonEmptyString(receipt.accessPolicyHash, 'accessPolicyHash'); + assertNonEmptyString(receipt.btcFeeReceiptId, 'btcFeeReceiptId'); + assertNonEmptyString(receipt.readLicenseId, 'readLicenseId'); + assertNonEmptyString(receipt.sourceSafePreviewRoot, 'sourceSafePreviewRoot'); + assertNonEmptyString(receipt.paidUnlockRoot, 'paidUnlockRoot'); + assertNonEmptyString(receipt.deliveryAdmissionRoot, 'deliveryAdmissionRoot'); + assertNonEmptyString(receipt.ledgerAnchorId, 'ledgerAnchorId'); + assertNonEmptyString(receipt.ledgerProjectionRoot, 'ledgerProjectionRoot'); + assertNonEmptyString(receipt.receiptRoot, 'receiptRoot'); + assertNonEmptyString(receipt.issuedAt, 'issuedAt'); + assertReceiptRange(receipt); + if (receipt.priceAsset !== BITCODE_FEE_ASSET) { + throw new Error('Rights transfer receipt must price in BTC.'); + } + if (receipt.priceSats <= 0n) { + throw new Error('Rights transfer receipt priceSats must be positive.'); + } + if (receipt.btcFeeFinalityState !== 'confirmed') { + throw new Error('Rights transfer receipt requires confirmed BTC fee finality.'); + } + if (receipt.deliveryAdmissionState !== 'admitted') { + throw new Error('Rights transfer receipt requires delivery admission.'); + } + if (!receipt.protectedSourceVisible) { + throw new Error('Rights transfer receipt must unlock protected source after settlement.'); + } + assertPositiveBigInt(receipt.exchangeSequence, 'exchangeSequence'); + return receipt; +} + +type ReceiptRangeInput = { + rangeStart: BtdTokenId; + rangeEndExclusive: BtdTokenId; + tokenCount?: number; +}; + +function normalizeReceiptRange(input: ReceiptRangeInput) { + const rangeStart = assertNonNegativeSafeInteger(input.rangeStart, 'rangeStart') as BtdTokenId; + const rangeEndExclusive = assertPositiveSafeInteger( + input.rangeEndExclusive, + 'rangeEndExclusive', + ) as BtdTokenId; + if (rangeEndExclusive <= rangeStart) { + throw new Error('BTD receipt range must be non-empty.'); + } + const tokenCount = input.tokenCount ?? rangeEndExclusive - rangeStart; + assertPositiveSafeInteger(tokenCount, 'tokenCount'); + if (tokenCount !== rangeEndExclusive - rangeStart) { + throw new Error('BTD receipt tokenCount does not match range boundaries.'); + } + return { rangeStart, rangeEndExclusive, tokenCount }; +} + +function assertReceiptRange(receipt: ReceiptRangeInput): void { + normalizeReceiptRange(receipt); +} + +function assertCommonAssetPackReceiptFields(receipt: { + receiptId: string; + assetPackId: string; +}): void { + assertNonEmptyString(receipt.receiptId, 'receiptId'); + assertNonEmptyString(receipt.assetPackId, 'assetPackId'); +} + +function normalizeOptionalRoot(value: string | null | undefined, label: string): string | null { + return value === undefined || value === null ? null : assertNonEmptyString(value, label); +} + +function assertReadDisclosureBoundary(input: { + disclosureState: BtdAssetPackDisclosureState; + readRightState: BtdReadRightState; + paidUnlockRoot: string | null; + deliveryAdmissionState: BtdDeliveryAdmissionState; + deliveryAdmissionRoot: string | null; + protectedSourceVisible: boolean; +}): void { + assertDisclosureState(input.disclosureState); + assertReadRightState(input.readRightState); + assertDeliveryAdmissionState(input.deliveryAdmissionState); + + if (input.protectedSourceVisible && input.disclosureState !== 'paid_unlocked') { + throw new Error('Protected source cannot be visible before paid unlock.'); + } + + if (input.disclosureState === 'paid_unlocked' && !input.paidUnlockRoot) { + throw new Error('Paid-unlocked read receipt requires paidUnlockRoot.'); + } + + if (input.deliveryAdmissionState === 'admitted') { + if (!input.deliveryAdmissionRoot) { + throw new Error('Delivery-admitted read receipt requires deliveryAdmissionRoot.'); + } + if (!input.paidUnlockRoot) { + throw new Error('Delivery-admitted read receipt requires paidUnlockRoot.'); + } + if (input.readRightState === 'none') { + throw new Error('Delivery-admitted read receipt requires a read right.'); + } + if (input.disclosureState !== 'paid_unlocked') { + throw new Error('Delivery-admitted read receipt requires paid unlock.'); + } + } +} + +function assertDisclosureState(state: BtdAssetPackDisclosureState): void { + if (state !== 'blocked' && state !== 'source_safe_preview' && state !== 'paid_unlocked') { + throw new Error(`Unsupported BTD disclosure state: ${state}.`); + } +} + +function assertReadRightState(state: BtdReadRightState): void { + if (state !== 'none' && state !== 'owner_read' && state !== 'licensed_read') { + throw new Error(`Unsupported BTD read right state: ${state}.`); + } +} + +function assertDeliveryAdmissionState(state: BtdDeliveryAdmissionState): void { + if (state !== 'blocked' && state !== 'admitted') { + throw new Error(`Unsupported BTD delivery admission state: ${state}.`); + } +} + +function buildBtdReceiptStableId( + prefix: string, + parts: Array, +): string { + const normalizedParts = parts.map((part) => (part === null || part === undefined ? '' : String(part))); + const hash = createHash('sha256').update(normalizedParts.join('\u001f')).digest('hex').slice(0, 16); + return `${prefix}_${hash}`; +} diff --git a/packages/pipeline-hosts/src/asset-pack-harness.ts b/packages/pipeline-hosts/src/asset-pack-harness.ts index 754856051..c65dae3ee 100644 --- a/packages/pipeline-hosts/src/asset-pack-harness.ts +++ b/packages/pipeline-hosts/src/asset-pack-harness.ts @@ -395,6 +395,9 @@ let lastCheckpointAt = 0; let readingPipelineObservabilityInventory = null; let resolveReadingPipelineTelemetryProjectionFn = null; let summarizeReadingPipelineObservabilityCoverageFn = null; +let buildBtdAssetPackMintReceiptFn = null; +let buildBtdReadReceiptFn = null; +let buildBtdRightsTransferReceiptFn = null; function normalizeResultState(candidate) { return ['worthy_fit', 'no_worthy_fit', 'blocked_readiness'].includes(candidate) @@ -1172,6 +1175,83 @@ async function settleAssetPackLedger(pipelineResultState) { userId, }); const walletSessionId = ledgerWallet('reader-session', process.env.BITCODE_PIPELINE_WALLET_SESSION_ID, runId); + const sourceSafePreviewRoot = rootOf({ + assetPackId, + sourceSafePreview: output?.sourceSafePreview || output?.assetPackDisclosureReview || null, + protectedSourceVisible: false, + }); + const acceptedNeedRoot = + manifest.readNeed?.measurementRoot || + manifest.readNeed?.needRoot || + rootOf({ read: manifest.read, sourceRevision: manifest.sourceRevision }); + const settlementConservationRoot = rootOf({ + assetPackId, + btcFeeSats, + rangeStart, + rangeEndExclusive, + exchangeSequence, + }); + const ledgerProjectionRoot = rootOf({ + assetPackId, + ledgerAnchorId, + btcFeeReceiptId, + btdMintReceiptId, + ownershipEventId, + readLicenseId, + journalEntryIds, + }); + const assetPackMintReceipt = buildBtdAssetPackMintReceiptFn({ + mintReceipt: { + kind: 'btd.asset_pack_mint', + assetPackId, + rangeStart, + rangeEndExclusive, + tokenCount, + totalMintedBefore: rangeStart, + totalMintedAfter: rangeEndExclusive, + maxSupply, + sourceManifestRoot, + measurementReceiptRoot, + fitReceiptRoot, + proofRoot, + settlementJournalRoot, + dedupeReceiptRoot, + exchangeReceiptRoot, + accessPolicyId, + accessPolicyHash, + mintedAtExchangeSequence: BigInt(exchangeSequence), + issuedAt, + }, + readId: manifest.read?.id || runId, + depositorWalletId, + sourceSafePreviewRoot, + findingFitsResultRoot: fitReceiptRoot, + settlementConservationRoot, + ledgerProjectionRoot, + issuedAt, + }); + const readReceipt = buildBtdReadReceiptFn({ + assetPackId, + readId: manifest.read?.id || runId, + readRequestId: manifest.read?.requestId || manifest.read?.id || runId, + acceptedNeedRoot, + findingFitsResultRoot: fitReceiptRoot, + readerWalletId, + depositorWalletId, + rangeStart, + rangeEndExclusive, + tokenCount, + sourceManifestRoot, + sourceSafePreviewRoot, + accessPolicyHash, + disclosureState: 'source_safe_preview', + readRightState: 'none', + deliveryAdmissionState: 'blocked', + ledgerProjectionRoot, + protectedSourceVisible: false, + issuedAt, + }); + const rightsTransferReceipt = null; const measurementReceipt = { schema: 'bitcode.btd.semantic-volume-measurement', @@ -1262,15 +1342,7 @@ async function settleAssetPackLedger(pipelineResultState) { await upsertAndReadLedgerRow('btd_mint_receipts', 'receipt_id', btdMintReceiptId, { receipt_id: btdMintReceiptId, asset_pack_id: assetPackId, - receipt: { - schema: 'bitcode.btd.mint-receipt', - runId, - rangeStart, - rangeEndExclusive, - tokenCount, - proofRoot, - measurementReceiptRoot, - }, + receipt: assetPackMintReceipt, issued_at: issuedAt, }); @@ -1394,7 +1466,7 @@ async function settleAssetPackLedger(pipelineResultState) { actor_id: depositorWalletId, pre_state_root: rootOf({ before: 'asset_pack_mint', totalMinted: rangeStart }), post_state_root: rootOf({ after: 'asset_pack_mint', totalMinted: rangeEndExclusive }), - receipt_roots: [measurementReceiptRoot, proofRoot, exchangeReceiptRoot], + receipt_roots: [measurementReceiptRoot, proofRoot, exchangeReceiptRoot, assetPackMintReceipt.receiptRoot], ledger_anchor_ids: [ledgerAnchorId], exchange_sequence: exchangeSequence, issued_at: issuedAt, @@ -1427,7 +1499,7 @@ async function settleAssetPackLedger(pipelineResultState) { actor_id: readerWalletId, pre_state_root: rootOf({ before: 'settlement_finalization', assetPackId }), post_state_root: rootOf({ after: 'settlement_finalization', assetPackId, readLicenseId }), - receipt_roots: [measurementReceiptRoot, fitReceiptRoot, proofRoot, rootOf({ readLicenseId, btcFeeReceiptId })], + receipt_roots: [measurementReceiptRoot, fitReceiptRoot, proofRoot, readReceipt.receiptRoot, rootOf({ readLicenseId, btcFeeReceiptId })], ledger_anchor_ids: [ledgerAnchorId], exchange_sequence: exchangeSequence + 3, issued_at: issuedAt, @@ -1499,6 +1571,9 @@ async function settleAssetPackLedger(pipelineResultState) { journalEntryIds, depositorWalletId, readerWalletId, + assetPackMintReceipt, + readReceipt, + rightsTransferReceipt, btcFee: { network: btcNetwork, requestedNetwork: requestedBtcNetwork, @@ -1576,13 +1651,18 @@ try { { applyAssetPackSettlementUnlockToPreview, buildAssetPackSettlementUnlock }, { reconcileLedgerDatabaseProjection }, { evaluateBtdOrganizationInterfaceAuthority }, + btdReceiptBuilders, ] = await Promise.all([ import('../../packages/pipelines/asset-pack/src/index'), import('../../packages/pipelines-generics/src/index'), import('../../packages/btd/src/settlement'), import('../../packages/btd/src/reconciliation'), import('../../packages/btd/src/authority'), + import('../../packages/btd/src/receipts'), ]); + buildBtdAssetPackMintReceiptFn = btdReceiptBuilders.buildBtdAssetPackMintReceipt; + buildBtdReadReceiptFn = btdReceiptBuilders.buildBtdReadReceipt; + buildBtdRightsTransferReceiptFn = btdReceiptBuilders.buildBtdRightsTransferReceipt; readingPipelineObservabilityInventory = buildReadingPipelineObservabilityInventory(); resolveReadingPipelineTelemetryProjectionFn = resolveReadingPipelineTelemetryProjection; summarizeReadingPipelineObservabilityCoverageFn = summarizeReadingPipelineObservabilityCoverage; @@ -1879,6 +1959,9 @@ try { status: ledgerSettlement.status, settlementAdmissible: ledgerSettlement.settlementAdmissible, assetPackId: ledgerSettlement.assetPackId || null, + assetPackMintReceiptRoot: ledgerSettlement.assetPackMintReceipt?.receiptRoot || null, + readReceiptRoot: ledgerSettlement.readReceipt?.receiptRoot || null, + rightsTransferReceiptRoot: ledgerSettlement.rightsTransferReceipt?.receiptRoot || null, reconciliationState: ledgerDatabaseReconciliation?.state || null, repairActionCount: ledgerDatabaseReconciliation?.repairActions?.length || 0, organizationAuthorityDecision: organizationAuthority[0].decision, diff --git a/scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs b/scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs new file mode 100644 index 000000000..4c93e412d --- /dev/null +++ b/scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs @@ -0,0 +1,238 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 4 typed BTD AssetPack mint, read, rights-transfer receipts, source-safe boundaries, Terminal readback, harness evidence, docs, and workflow readiness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-4-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 4 work must occur on version/v30 or v30/gate-4-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + 'packages/btd/src/receipts.ts', + 'packages/btd/src/api-boundaries.ts', + 'packages/btd/__tests__/api-boundaries.test.ts', + 'packages/pipeline-hosts/src/asset-pack-harness.ts', + 'uapi/app/terminal/terminal-transaction-detail-snapshot.ts', + 'uapi/app/terminal/terminal-transaction-read-model.ts', + 'uapi/tests/terminalTransactionDetailSnapshot.test.ts', + 'uapi/tests/terminalTransactionReadModel.test.ts', + 'packages/btd/README.md', + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + ]) { + assertCheck(failures, fileExists(root, relativePath), `Missing V30 Gate 4 file: ${relativePath}`); + } + + const receipts = read(root, 'packages/btd/src/receipts.ts'); + const apiBoundary = read(root, 'packages/btd/src/api-boundaries.ts'); + const btdTest = read(root, 'packages/btd/__tests__/api-boundaries.test.ts'); + const harness = read(root, 'packages/pipeline-hosts/src/asset-pack-harness.ts'); + const terminalSnapshot = read(root, 'uapi/app/terminal/terminal-transaction-detail-snapshot.ts'); + const terminalReadModel = read(root, 'uapi/app/terminal/terminal-transaction-read-model.ts'); + const terminalSnapshotTest = read(root, 'uapi/tests/terminalTransactionDetailSnapshot.test.ts'); + const terminalReadModelTest = read(root, 'uapi/tests/terminalTransactionReadModel.test.ts'); + const btdReadme = read(root, 'packages/btd/README.md'); + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + for (const symbol of [ + 'BtdAssetPackMintReceipt', + 'BtdReadReceipt', + 'BtdRightsTransferReceipt', + 'buildBtdAssetPackMintReceipt', + 'buildBtdReadReceipt', + 'buildBtdRightsTransferReceipt', + 'assertBtdAssetPackMintReceipt', + 'assertBtdReadReceipt', + 'assertBtdRightsTransferReceipt', + ]) { + assertCheck(failures, receipts.includes(symbol), `BTD receipts module must define/export ${symbol}.`); + } + + for (const requiredField of [ + 'sourceSafePreviewRoot', + 'paidUnlockRoot', + 'deliveryAdmissionRoot', + 'ledgerProjectionRoot', + 'readerWalletId', + 'depositorWalletId', + 'protectedSourceVisible', + ]) { + assertCheck(failures, receipts.includes(requiredField), `BTD receipts must bind ${requiredField}.`); + } + + assertCheck( + failures, + receipts.includes('Protected source cannot be visible before paid unlock.'), + 'BTD read receipts must reject protected source visibility before paid unlock.', + ); + assertCheck( + failures, + receipts.includes("btcFeeFinalityState !== 'confirmed'"), + 'BTD rights-transfer receipts must require confirmed BTC fee finality.', + ); + assertCheck( + failures, + receipts.includes("disclosureState: 'source_safe_preview'") && + receipts.includes('protectedSourceVisible: false'), + 'BTD AssetPack mint receipts must remain source-safe.', + ); + + for (const symbol of [ + 'buildBtdAssetPackMintReceipt', + 'buildBtdReadReceiptBoundarySettlement', + 'buildBtdRightsTransferReceipt', + 'assetPackMintReceipt', + 'btdRightsTransferReceipt', + ]) { + assertCheck(failures, apiBoundary.includes(symbol), `BTD API boundary must expose/use ${symbol}.`); + } + + for (const expectedEvidence of [ + 'source_safe_preview', + 'paidUnlockRoot', + 'deliveryAdmissionRoot', + "btcFeeFinalityState: 'confirmed'", + 'Rights transfer receipt requires confirmed BTC fee finality.', + ]) { + assertCheck(failures, btdTest.includes(expectedEvidence), `BTD tests must cover ${expectedEvidence}.`); + } + + for (const harnessEvidence of [ + 'buildBtdAssetPackMintReceiptFn', + 'buildBtdReadReceiptFn', + 'assetPackMintReceipt', + 'readReceipt', + 'assetPackMintReceiptRoot', + 'readReceiptRoot', + ]) { + assertCheck(failures, harness.includes(harnessEvidence), `Sandbox harness must store or stream ${harnessEvidence}.`); + } + + for (const terminalEvidence of [ + 'assetPackMintReceipt', + 'readReceipt', + 'rightsTransferReceipt', + ]) { + assertCheck(failures, terminalSnapshot.includes(terminalEvidence), `Terminal snapshot must coerce ${terminalEvidence}.`); + assertCheck(failures, terminalReadModel.includes(terminalEvidence), `Terminal read model must count ${terminalEvidence}.`); + } + assertCheck( + failures, + terminalSnapshot.includes('asset_pack_mint_receipt') && terminalSnapshot.includes('btd_rights_transfer_receipt'), + 'Terminal snapshot must accept database-style receipt payload keys.', + ); + assertCheck( + failures, + terminalSnapshotTest.includes('asset-pack-mint-receipt-root-run-1') && + terminalReadModelTest.includes('read-receipt-root-1'), + 'Terminal tests must cover receipt readback and read model counting.', + ); + + assertCheck(failures, btdReadme.includes('typed AssetPack mint/read/rights-transfer receipts'), 'BTD README must document Gate 4 receipt ownership.'); + assertCheck(failures, spec.includes('Gate 4 receipt precision'), 'V30 SPEC must include Gate 4 receipt precision.'); + assertCheck(failures, delta.includes('Gate 4 implementation centers'), 'V30 DELTA must include Gate 4 implementation evidence.'); + assertCheck(failures, notes.includes('Gate 4 BTD AssetPack mint and read receipt notes'), 'V30 NOTES must include Gate 4 implementation notes.'); + assertCheck(failures, parity.includes('## Gate 4 Parity'), 'V30 PARITY must include Gate 4 parity evidence.'); + assertCheck(failures, parity.includes('Gate 4 accepted boundaries'), 'V30 PARITY must include Gate 4 accepted boundaries.'); + assertCheck(failures, packageJson.includes('"check:v30-gate4"'), 'package.json must expose check:v30-gate4.'); + assertCheck( + failures, + gateWorkflow.includes('check-v30-gate4-btd-assetpack-mint-read-receipts.mjs'), + 'Gate workflow must run the V30 Gate 4 checker.', + ); + + if (failures.length) { + process.stderr.write('V30 Gate 4 BTD AssetPack mint/read receipts check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V30 Gate 4 BTD AssetPack mint/read receipts check passed.\n'); +} + +try { + main(); +} catch (error) { + const detail = error instanceof Error ? error.message : String(error); + process.stderr.write(`${detail}\n`); + process.exitCode = 1; +} diff --git a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts index f8ae77057..b55128af6 100644 --- a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts +++ b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts @@ -54,6 +54,9 @@ export type TerminalLedgerSettlementSnapshot = { readerWalletId: string | null; btcFee: TerminalJsonRecord | null; ownershipBoundary: TerminalJsonRecord | null; + assetPackMintReceipt?: TerminalJsonRecord | null; + readReceipt?: TerminalJsonRecord | null; + rightsTransferReceipt?: TerminalJsonRecord | null; readback: Record; journalEntryIds: string[]; ownershipEventId: string | null; @@ -329,15 +332,32 @@ function coerceRecordArray(value: unknown): TerminalJsonRecord[] { return value.filter((entry): entry is TerminalJsonRecord => isRecord(entry)); } +function coerceJsonRecord(value: unknown): TerminalJsonRecord | null { + return isRecord(value) ? value : null; +} + function coerceLedgerSettlement(value: unknown): TerminalLedgerSettlementSnapshot | null { if (!isRecord(value)) return null; const readback = coerceBooleanRecord(value.readback); const journalEntryIds = coerceChips(value.journalEntryIds); + const assetPackMintReceipt = coerceJsonRecord( + value.assetPackMintReceipt || value.asset_pack_mint_receipt, + ); + const readReceipt = coerceJsonRecord(value.readReceipt || value.read_receipt); + const rightsTransferReceipt = coerceJsonRecord( + value.rightsTransferReceipt || + value.btdRightsTransferReceipt || + value.rights_transfer_receipt || + value.btd_rights_transfer_receipt, + ); const hasSettlementShape = coerceString(value.status) || coerceString(value.assetPackId) || coerceString(value.ledgerAnchorId) || coerceString(value.btcFeeReceiptId) || + assetPackMintReceipt || + readReceipt || + rightsTransferReceipt || Object.keys(readback).length > 0 || journalEntryIds.length > 0; @@ -355,6 +375,9 @@ function coerceLedgerSettlement(value: unknown): TerminalLedgerSettlementSnapsho readerWalletId: coerceString(value.readerWalletId), btcFee: isRecord(value.btcFee) ? value.btcFee : null, ownershipBoundary: isRecord(value.ownershipBoundary) ? value.ownershipBoundary : null, + assetPackMintReceipt, + readReceipt, + rightsTransferReceipt, readback, journalEntryIds, ownershipEventId: coerceString(value.ownershipEventId), diff --git a/uapi/app/terminal/terminal-transaction-read-model.ts b/uapi/app/terminal/terminal-transaction-read-model.ts index 209bc00d9..fb9457f19 100644 --- a/uapi/app/terminal/terminal-transaction-read-model.ts +++ b/uapi/app/terminal/terminal-transaction-read-model.ts @@ -175,6 +175,14 @@ function countJournalRows(detail: TerminalRunDetailSnapshot | null) { ); } +function countBtdSettlementReceipts(detail: TerminalRunDetailSnapshot | null) { + return [ + detail?.ledgerSettlement?.assetPackMintReceipt, + detail?.ledgerSettlement?.readReceipt, + detail?.ledgerSettlement?.rightsTransferReceipt, + ].filter(Boolean).length; +} + function createSectionHref( searchParams: URLSearchParams, transactionId: string, @@ -263,16 +271,18 @@ function resolveSectionAvailability({ } if (sectionId === 'closure') { + const receiptCount = countBtdSettlementReceipts(detail); const hasClosure = Boolean(detail?.closureState) || Boolean(detail?.closureFollowThrough) || Boolean(detail?.ledgerSettlement) || + receiptCount > 0 || Boolean(detail?.processingStats.tokenTotal); return { availability: hasClosure ? 'available' : 'empty', blocker: hasClosure ? null : 'Closure, settlement, and processing detail has not been projected for this row yet.', - metricCount: detail?.closureFollowThrough?.settlementMetrics.length || 4, - rowCount: detail?.closureFollowThrough?.branchArtifacts.length || 0, + metricCount: detail?.closureFollowThrough?.settlementMetrics.length || receiptCount || 4, + rowCount: (detail?.closureFollowThrough?.branchArtifacts.length || 0) + receiptCount, payloadAvailable: hasClosure, }; } @@ -303,12 +313,13 @@ function resolveSectionAvailability({ if (sectionId === 'journal') { const journalRows = countJournalRows(detail); - const hasLedger = journalRows > 0 || Boolean(detail?.ledgerSettlement); + const receiptCount = countBtdSettlementReceipts(detail); + const hasLedger = journalRows > 0 || receiptCount > 0 || Boolean(detail?.ledgerSettlement); return { availability: hasLedger ? 'available' : 'empty', blocker: hasLedger ? null : 'No journal readback, ledger observation, or repair receipt is attached yet.', metricCount: 3, - rowCount: journalRows, + rowCount: journalRows + receiptCount, payloadAvailable: hasLedger, }; } diff --git a/uapi/tests/terminalTransactionDetailSnapshot.test.ts b/uapi/tests/terminalTransactionDetailSnapshot.test.ts index aec769cff..b687bd6a2 100644 --- a/uapi/tests/terminalTransactionDetailSnapshot.test.ts +++ b/uapi/tests/terminalTransactionDetailSnapshot.test.ts @@ -310,6 +310,22 @@ describe('terminal-transaction-detail-snapshot helpers', () => { btdRange: { start: 0, endExclusive: 1, tokenCount: 1 }, ledgerAnchorId: 'ledger-anchor-run-1', btcFeeReceiptId: 'btc-fee-run-1', + asset_pack_mint_receipt: { + kind: 'btd.asset_pack_mint_receipt', + receiptRoot: 'asset-pack-mint-receipt-root-run-1', + protectedSourceVisible: false, + }, + read_receipt: { + kind: 'btd.read_receipt', + receiptRoot: 'read-receipt-root-run-1', + disclosureState: 'source_safe_preview', + protectedSourceVisible: false, + }, + btd_rights_transfer_receipt: { + kind: 'btd.rights_transfer_receipt', + receiptRoot: 'rights-transfer-receipt-root-run-1', + protectedSourceVisible: true, + }, readback: { assetPackRange: true, btcFeeTransaction: true, @@ -464,6 +480,15 @@ describe('terminal-transaction-detail-snapshot helpers', () => { terminalJournal: true, }, journalEntryIds: ['journal-mint-run-1'], + assetPackMintReceipt: { + receiptRoot: 'asset-pack-mint-receipt-root-run-1', + }, + readReceipt: { + receiptRoot: 'read-receipt-root-run-1', + }, + rightsTransferReceipt: { + receiptRoot: 'rights-transfer-receipt-root-run-1', + }, }); expect(snapshot.terminalJournal).toMatchObject({ expectedJournalEntryIds: ['journal-mint-run-1'], diff --git a/uapi/tests/terminalTransactionReadModel.test.ts b/uapi/tests/terminalTransactionReadModel.test.ts index f33f58f64..23e967de9 100644 --- a/uapi/tests/terminalTransactionReadModel.test.ts +++ b/uapi/tests/terminalTransactionReadModel.test.ts @@ -87,6 +87,18 @@ const detail: TerminalRunDetailSnapshot = { serverCustody: false, }, ownershipBoundary: null, + assetPackMintReceipt: { + kind: 'btd.asset_pack_mint_receipt', + receiptRoot: 'asset-pack-mint-receipt-root-1', + protectedSourceVisible: false, + }, + readReceipt: { + kind: 'btd.read_receipt', + receiptRoot: 'read-receipt-root-1', + disclosureState: 'source_safe_preview', + protectedSourceVisible: false, + }, + rightsTransferReceipt: null, readback: { assetPackRange: true }, journalEntryIds: ['journal-1'], ownershipEventId: null, @@ -149,6 +161,10 @@ describe('terminal transaction read model', () => { availability: 'available', factFamily: 'wallet', }); + expect(model.sections.find((section) => section.id === 'journal')).toMatchObject({ + availability: 'available', + rowCount: 2, + }); }); it('marks empty and blocked sections explicitly without raw payload dependency', () => { From d0fd62f2622d32b8164f121fe56b7ca9a9ca5623 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 18:31:12 -0300 Subject: [PATCH 05/15] V30 Gate 5: Harden testnet ledger projection Adds package-owned object-storage artifact facts and secret-free Supabase staging-testnet readback receipts to BTD reconciliation reports. Wires the report through the AssetPack Sandbox harness and Terminal journal reconciliation UI so ledger, database, object-storage, and private facts remain distinct with deterministic repair roots. Covers drift, quarantine, retry, protected-source rejection, staging readback blocking, API serialization, harness generation, Terminal rendering, V30 spec parity, and the Gate 5 workflow checker. --- .github/workflows/bitcode-gate-quality.yml | 1 + BITCODE_SPEC_V30.md | 13 +- BITCODE_SPEC_V30_DELTA.md | 33 +++ BITCODE_SPEC_V30_NOTES.md | 30 ++ BITCODE_SPEC_V30_PARITY_MATRIX.md | 19 +- package.json | 1 + .../src/routes/__tests__/btd-crypto.test.ts | 42 +++ packages/btd/README.md | 6 + packages/btd/__tests__/reconciliation.test.ts | 224 ++++++++++++++ packages/btd/src/api-boundaries.ts | 9 + packages/btd/src/reconciliation.ts | 276 +++++++++++++++++- .../src/__tests__/asset-pack-harness.test.ts | 6 + .../pipeline-hosts/src/asset-pack-harness.ts | 107 ++++++- ...e5-testnet-ledger-projection-hardening.mjs | 243 +++++++++++++++ uapi/app/terminal/README.md | 12 +- ...alTransactionJournalReconciliationCard.tsx | 5 + .../terminal-journal-reconciliation.ts | 143 ++++++++- .../terminal-transaction-detail-snapshot.ts | 6 + .../terminalJournalReconciliation.test.ts | 34 ++- .../terminalTransactionDetailSnapshot.test.ts | 17 ++ 20 files changed, 1207 insertions(+), 20 deletions(-) create mode 100644 packages/btd/__tests__/reconciliation.test.ts create mode 100644 scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index dbdda501d..8d8b3aeef 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -83,6 +83,7 @@ jobs: node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs --skip-branch-check node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs --skip-branch-check node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs --skip-branch-check + node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index 219cc4109..6bf137d1c 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -353,7 +353,9 @@ The canonical report is produced from: - ledger observed facts: fee receipts, ledger anchors, journal entries, BTD ranges, ownership events, read licenses, and finality state; - database projected facts: the Supabase readback rows that claim those ledger facts are durable in the application projection; +- object-storage artifact facts: source-safe preview, pipeline evidence, telemetry, delivery manifest, and ledger projection artifact roots that prove artifacts are durable without exposing protected source; - private metaphysical canonical facts: protected source metadata, need/fit context, access policy documents, encrypted storage pointers, disputes, and telemetry context represented only by roots; +- staging-testnet readback facts: secret-free Supabase project reference, REST/DB hosts, out-of-band admin-credential state, table readback counts, and synchronized-or-blocked state; - settlement conservation checks: BTC debit/credit and fee/payment roots that must conserve before unlock; - delivery evidence: post-settlement pull-request visibility and recovery posture. @@ -363,24 +365,33 @@ Drift is classified before repair: - `ledger_root_mismatch`: the database projection points at a different root than the ledger observation; - `ledger_finality_mismatch`: the projected finality differs from the observed finality; - `database_orphan_projection`: the database projects a fact that has no matching ledger observation; +- `missing_object_storage_artifact`: the ledger or projection expects an artifact root that is not durable yet; +- `object_storage_root_mismatch`: the database projection and object-storage artifact root disagree; +- `staging_testnet_readback_blocked`: staging-testnet Supabase readback cannot prove the expected rows without retry; - `settlement_conservation_drift`: BTC debit/credit or fee/payment accounting does not conserve. Repair actions are canonical and auditable: - `retry_database_readback`; +- `retry_object_storage_write`; +- `retry_staging_testnet_readback`; - `project_ledger_fact`; - `update_finality_state`; - `quarantine_database_projection`; +- `quarantine_object_storage_artifact`; - `pause_settlement_unlock`; - `recover_delivery`. The reconciliation state is one of aligned, retryable, repairable, approval required, or blocked. Confirmed ledger facts that are missing from the database require operator-approved projection repair. Reorged or failed finality, database-only orphan projection, or settlement conservation drift blocks unlock and delivery. +Missing durable object-storage artifacts are retryable unlock blockers. +Object-storage root mismatches require quarantine until the artifact and projection agree. Delivery recovery is allowed only when settlement is otherwise aligned and the full AssetPack delivery target is not visible. -Terminal must show drift classes, blockers, repair actions, proof roots, observed facts, projected facts, canonical facts, journal entries, and repair receipts before raw payloads. +Terminal must show drift classes, blockers, repair actions, proof roots, observed facts, projected facts, object-storage facts, canonical facts, journal entries, and repair receipts before raw payloads. The Vercel Sandbox harness must store the reconciliation report as settlement evidence when it claims ledger readback. +Supabase staging-testnet readback receipts must never store service-role JWTs, `sb_secret__` keys, OpenAI keys, database passwords, or any raw secret in tracked code or persisted proof payloads; only host/project identifiers, credential presence state, and proof roots are admissible. The API may persist schema-compatible repair receipts while richer repair actions and proof roots remain report evidence until the registry schema is formally expanded. ## V30 canonical subsystem surfaces diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 589887915..4fe2ea3dd 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -178,6 +178,39 @@ Closure acceptance: - Supabase staging-testnet readback can prove synchronized or blocked state without secrets in tracked files; - reconciliation tests cover drift, quarantine, retry, and unlock blocking. +Gate 5 implementation centers on `packages/btd/src/reconciliation.ts`. +`LedgerDatabaseReconciliationReport` now carries distinct ledger-observed +facts, database-projected facts, object-storage artifact facts, private +metaphysical facts, settlement-conservation checks, and optional +`SupabaseStagingTestnetProjectionReadback` evidence. Object-storage facts name +artifact kind, source visibility, durable root, protected-source/encryption +posture, and manifest root. Supabase readback receipts name only safe project +and host identifiers, table counts, synchronized-or-blocked state, credential +presence, and proof roots; secret-looking values are rejected. + +The deterministic repair surface now includes +`missing_object_storage_artifact`, `object_storage_root_mismatch`, and +`staging_testnet_readback_blocked` drift classes plus +`retry_object_storage_write`, `retry_staging_testnet_readback`, and +`quarantine_object_storage_artifact` repair actions. Missing durable artifacts +block unlock as retryable repairs, object-storage root mismatches require +quarantine/approval, and staging-testnet readback failures remain blocked until +the table readback proves synchronized. + +The Sandbox harness emits object-storage artifact roots and secret-free +staging-testnet readback receipts into settlement reconciliation evidence. +Terminal reconciliation now renders object-storage artifacts as a fourth fact +group beside ledger, database, and metaphysical facts and includes report proof +roots and repair actions in the existing journal repair cockpit. + +Gate 5 evidence is covered by +`packages/btd/__tests__/reconciliation.test.ts`, +`packages/api/src/routes/__tests__/btd-crypto.test.ts`, +`packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts`, +`uapi/tests/terminalJournalReconciliation.test.ts`, +`uapi/tests/terminalTransactionDetailSnapshot.test.ts`, and +`scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs`. + ### Gate 6: Source-To-Shares Proof Cleanup Gate 6 cleans contribution measurement and settlement conservation. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index 5a4f8b653..97dcb7bb6 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -137,6 +137,36 @@ coerce receipt payloads under camelCase or database-style snake_case keys, and the transaction read model counts receipt payloads in closure and journal availability. +## Gate 5 testnet ledger projection notes + +Gate 5 extends the V29 reconciliation cockpit from ledger/database/private-root +separation into a four-fact projection model: + +- ledger observed facts remain fee, anchor, journal, range, ownership, license, + and finality observations; +- database projected facts remain Supabase rows and projected roots/finality; +- object-storage artifact facts now carry source-safe preview, evidence, + telemetry, delivery, and ledger-projection roots separately from database + rows; +- private metaphysical facts remain root-only protected source and policy + context. + +Object storage may prove a durable artifact exists, but it may not leak +protected source before settlement. Unencrypted protected source artifacts are +rejected. Encrypted protected source artifacts are admissible only as roots and +encrypted posture, not visible source. + +Supabase staging-testnet readback is an explicit receipt. It records project +ref, REST host, optional DB host, admin credential presence state, table readback +counts, synchronized-or-blocked state, and proof root. It rejects secret-shaped +values so tracked files, telemetry, and persisted proof payloads cannot carry +service-role JWTs, `sb_secret__` keys, OpenAI keys, or database passwords. + +Gate 5 keeps the existing registry table shape for repair rows. The API +persists schema-compatible repair receipts; richer drift classes, repair +actions, readback receipts, and proof roots remain in the report payload until a +future schema expansion admits more columns. + 4. **Gate 4: BTD AssetPack Mint And Read Receipts** - Make BTD mint, read, and rights-transfer receipts typed, proof-rooted, stored, streamed, and source-safe. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index ad6b2cb5b..8abfc3495 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -58,7 +58,7 @@ No `_legacy/` source is active source truth. | Protocol package API boundaries | Gate 2 | `packages/btd/src/api-boundaries.ts`, `packages/api/src/routes/btd-crypto.ts`, package READMEs/tests | drafted | Shared Protocol/BTD objects have package-owned builders, parsers, validators, JSON-safe serializers, and tests. | | Bitcoin Taproot PSBT fee rigor | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, `packages/btd/src/bitcoin-fees.ts`, BTD/API tests, gate checker | drafted | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, Taproot/PSBT aware, and proof-rooted. | | BTD AssetPack mint/read receipts | Gate 4 | `packages/btd/src/receipts.ts`, `packages/btd/src/api-boundaries.ts`, asset-pack harness evidence, Terminal detail snapshot/read model tests, gate checker | drafted | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | -| Testnet ledger projection hardening | Gate 5 | BTD reconciliation, Supabase readback, object-storage evidence, repair tests | pending | Ledger/database/object-storage projections are synchronized or blocked with deterministic repair posture. | +| Testnet ledger projection hardening | Gate 5 | `packages/btd/src/reconciliation.ts`, API route tests, asset-pack harness evidence, Terminal journal reconciliation UI/tests, gate checker | drafted | Ledger/database/object-storage/private facts are distinct; staging-testnet readback is secret-free; drift, quarantine, retry, and unlock blocking are tested. | | Source-to-shares proof cleanup | Gate 6 | BTD/source-to-shares proof primitives, settlement conservation tests | pending | Measurement contribution, fee allocation, zero-cell/refit tail, and conservation invariants are testable. | | Bridge-readiness research boundaries | Gate 7 | Protocol/BTD research notes, policy posture tests, docs | pending | Bridge paths are documented as research until admitted by explicit future proof and policy. | | Protocol telemetry/proof hooks | Gate 8 | telemetry schema, proof hooks, generated-artifact inventory, tests | pending | Receipts, fee states, projections, and source-to-shares facts emit source-safe telemetry and proof hooks. | @@ -150,6 +150,15 @@ No `_legacy/` source is active source truth. | Tests cover package and Terminal receipt posture | `packages/btd/__tests__/api-boundaries.test.ts`, `uapi/tests/terminalTransactionDetailSnapshot.test.ts`, and `uapi/tests/terminalTransactionReadModel.test.ts` | drafted | | Gate checker protects the receipt surface | `scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs`, `pnpm run check:v30-gate4`, gate-quality workflow | drafted | +## Gate 5 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| Ledger projection report separates four fact classes | `packages/btd/src/reconciliation.ts`, `uapi/app/terminal/terminal-journal-reconciliation.ts`, `uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx` | drafted | +| Object-storage and staging-testnet repair classes are deterministic | `packages/btd/__tests__/reconciliation.test.ts`, `packages/api/src/routes/__tests__/btd-crypto.test.ts` | drafted | +| Harness and Terminal consume the same report evidence | `packages/pipeline-hosts/src/asset-pack-harness.ts`, `packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts`, `uapi/tests/terminalJournalReconciliation.test.ts`, `uapi/tests/terminalTransactionDetailSnapshot.test.ts` | drafted | +| Gate checker protects projection hardening | `scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs`, `pnpm run check:v30-gate5`, gate-quality workflow | drafted | + ## Gate 4 accepted boundaries - Gate 4 does not require production-mainnet BTC settlement. @@ -158,6 +167,14 @@ No `_legacy/` source is active source truth. - Gate 4 does not harden all ledger/database/object-storage projection repair; Gate 5 owns that. - Gate 4 does not finish source-to-shares contribution cleanup; Gate 6 owns that. +## Gate 5 accepted boundaries + +- Gate 5 does not expand the physical reconciliation repair registry schema. +- Gate 5 does not store or print Supabase service-role JWTs, `sb_secret__` keys, OpenAI keys, database passwords, or Vercel tokens. +- Gate 5 does not make protected AssetPack source visible before paid unlock and delivery admission. +- Gate 5 does not implement source-to-shares contribution accounting; Gate 6 owns that. +- Gate 5 does not promote V30 or change the active canon pointer. + ## completion condition Gate 1 is complete when the V30 draft family validates, `check:v30-gate1` passes, workflow posture is V30-aware, README and roadmap reflect V30 initiation, V31-V37 scopes are current enough to guide future gates, diff hygiene passes, and the gate branch is committed and pushed for review into `version/v30`. diff --git a/package.json b/package.json index 7bdfbaa29..ddb94026e 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "check:v30-gate2": "node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs", "check:v30-gate3": "node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs", "check:v30-gate4": "node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs", + "check:v30-gate5": "node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/api/src/routes/__tests__/btd-crypto.test.ts b/packages/api/src/routes/__tests__/btd-crypto.test.ts index 487502b9b..986c291cf 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -1338,6 +1338,24 @@ describe('BTD crypto API builders', () => { projectedLedgerRoot: 'confirmed-root', projectedFinalityState: 'broadcast', }, + { + factId: 'artifact-api-1', + projectedLedgerRoot: 'artifact-ledger-root', + projectedFinalityState: 'prepared', + projectedObjectStorageRoot: 'artifact-database-root', + }, + ], + objectStorageArtifacts: [ + { + factId: 'artifact-api-1', + artifactId: 'artifact-api-1', + artifactKind: 'pipeline_evidence', + storageRoot: 'artifact-storage-root', + sourceVisibility: 'proof_public', + durable: true, + containsProtectedSource: false, + encrypted: false, + }, ], metaphysicalFacts: [ { @@ -1348,6 +1366,27 @@ describe('BTD crypto API builders', () => { private: true, }, ], + stagingTestnetReadback: { + kind: 'btd.supabase_projection_readback', + readbackId: 'staging-readback-api-1', + lane: 'staging-testnet', + supabaseProjectRef: 'tkpyosihuouusyaxtbau', + restHost: 'tkpyosihuouusyaxtbau.supabase.co', + adminCredentialState: 'provided_out_of_band', + secretValuesStored: false, + tableReadbacks: [ + { + table: 'btd_asset_pack_ranges', + expectedCount: 1, + observedCount: 1, + synchronized: true, + }, + ], + state: 'synchronized', + blockingReasons: [], + proofRoot: 'btd-proof-root:supabase-projection-readback:api', + issuedAt, + }, settlementConservationChecks: [ { checkId: 'settlement-conservation-api-1', @@ -1369,6 +1408,9 @@ describe('BTD crypto API builders', () => { expect(body.report.blocking).toBe(true); expect(body.report.state).toBe('blocked'); expect(body.report.driftKindCounts.settlement_conservation_drift).toBe(1); + expect(body.report.driftKindCounts.object_storage_root_mismatch).toBe(1); + expect(body.report.objectStorageArtifacts[0].storageRoot).toBe('artifact-storage-root'); + expect(body.report.stagingTestnetReadback.secretValuesStored).toBe(false); expect(body.report.metaphysicalFacts[0].canonicalRoot).toBe('private-source-root'); expect(body.committed).toBe(true); expect(insertReconciliationRepair).toHaveBeenCalledWith( diff --git a/packages/btd/README.md b/packages/btd/README.md index 3cea896d8..0d46393ec 100644 --- a/packages/btd/README.md +++ b/packages/btd/README.md @@ -15,6 +15,10 @@ This package owns: Reader and Depositor identities, source-safe preview roots, paid unlock, delivery admission, and ledger projection roots without leaking protected source before settlement +- ledger/database/object-storage projection reconciliation, including + deterministic repair classes, source-safe object artifact roots, + secret-free Supabase staging-testnet readback receipts, quarantine/retry + actions, and settlement-unlock blocking posture - BTC fee operation posture, including quote lifecycle, signer recovery, no-server-custody PSBT handoff, Taproot/script posture, broadcast/finality observation, replacement/reorg repair, and testnet/mainnet network policy @@ -44,6 +48,8 @@ import { buildBtdReadReceiptBoundarySettlement, buildBtdRightsTransferReceipt, buildBtdRegistrySnapshot, + buildSupabaseStagingTestnetProjectionReadback, + reconcileLedgerDatabaseProjection, toBtdJsonSafe, calculateLlmBtcFeeEstimate, buildLicensedReadRevenueRoute, diff --git a/packages/btd/__tests__/reconciliation.test.ts b/packages/btd/__tests__/reconciliation.test.ts new file mode 100644 index 000000000..654a68cd8 --- /dev/null +++ b/packages/btd/__tests__/reconciliation.test.ts @@ -0,0 +1,224 @@ +import { + buildSupabaseStagingTestnetProjectionReadback, + reconcileLedgerDatabaseProjection, +} from '../src'; + +const issuedAt = '2026-05-21T00:00:00.000Z'; + +describe('BTD ledger projection reconciliation', () => { + it('keeps ledger, database, object-storage, and private facts distinct when aligned', () => { + const readback = buildSupabaseStagingTestnetProjectionReadback({ + readbackId: 'readback-aligned-1', + lane: 'staging-testnet', + supabaseProjectRef: 'tkpyosihuouusyaxtbau', + restHost: 'tkpyosihuouusyaxtbau.supabase.co', + databaseHost: 'db.tkpyosihuouusyaxtbau.supabase.co', + adminCredentialState: 'provided_out_of_band', + tableReadbacks: [ + { + table: 'btd_asset_pack_ranges', + expectedCount: 1, + observedCount: 1, + synchronized: true, + }, + ], + issuedAt, + }); + const report = reconcileLedgerDatabaseProjection({ + reconciliationId: 'reconciliation-aligned-1', + ledgerFacts: [ + { + factId: 'asset-pack-aligned-1', + ledgerRoot: 'sha256:ledger-root', + finalityState: 'confirmed', + }, + ], + databaseFacts: [ + { + factId: 'asset-pack-aligned-1', + projectedLedgerRoot: 'sha256:ledger-root', + projectedFinalityState: 'confirmed', + projectedObjectStorageRoot: 'sha256:storage-root', + }, + ], + objectStorageArtifacts: [ + { + factId: 'asset-pack-aligned-1', + artifactId: 'artifact-aligned-1', + artifactKind: 'asset_pack_source_safe_preview', + storageRoot: 'sha256:storage-root', + manifestRoot: 'sha256:manifest-root', + sourceVisibility: 'source_safe', + durable: true, + containsProtectedSource: false, + encrypted: false, + }, + ], + metaphysicalFacts: [ + { + factId: 'private-source-aligned-1', + factKind: 'private_source_metadata', + canonicalRoot: 'sha256:private-root', + private: true, + }, + ], + stagingTestnetReadback: readback, + issuedAt, + }); + + expect(report.state).toBe('aligned'); + expect(report.objectStorageArtifacts).toHaveLength(1); + expect(report.metaphysicalFacts[0].private).toBe(true); + expect(report.stagingTestnetReadback).toMatchObject({ + state: 'synchronized', + secretValuesStored: false, + supabaseProjectRef: 'tkpyosihuouusyaxtbau', + }); + expect(report.proofRoots.objectStorageRoot).toMatch(/^btd-proof-root:object-storage-artifacts:/); + expect(report.proofRoots.stagingTestnetReadbackRoot).toBe(readback.proofRoot); + }); + + it('classifies missing object-storage artifacts as retryable repair actions that block unlock', () => { + const report = reconcileLedgerDatabaseProjection({ + reconciliationId: 'reconciliation-storage-missing-1', + ledgerFacts: [], + databaseFacts: [], + objectStorageArtifacts: [ + { + factId: 'artifact-missing-1', + artifactId: 'artifact-missing-1', + artifactKind: 'pipeline_evidence', + storageRoot: 'sha256:artifact-root', + sourceVisibility: 'proof_public', + durable: false, + containsProtectedSource: false, + encrypted: false, + }, + ], + issuedAt, + }); + + expect(report.state).toBe('repairable'); + expect(report.blocking).toBe(true); + expect(report.repairs[0]).toMatchObject({ + repairKind: 'object_storage_artifact', + driftKind: 'missing_object_storage_artifact', + repairActionKind: 'retry_object_storage_write', + blocking: true, + requiresOperatorApproval: false, + }); + expect(report.repairActions[0].summary).toContain('Retry object-storage artifact write'); + }); + + it('quarantines database projections whose object-storage artifact root disagrees', () => { + const report = reconcileLedgerDatabaseProjection({ + reconciliationId: 'reconciliation-storage-root-mismatch-1', + ledgerFacts: [], + databaseFacts: [ + { + factId: 'artifact-root-mismatch-1', + projectedLedgerRoot: 'sha256:ledger-root', + projectedFinalityState: 'prepared', + projectedObjectStorageRoot: 'sha256:database-storage-root', + }, + ], + objectStorageArtifacts: [ + { + factId: 'artifact-root-mismatch-1', + artifactId: 'artifact-root-mismatch-1', + artifactKind: 'delivery_manifest', + storageRoot: 'sha256:artifact-storage-root', + sourceVisibility: 'proof_public', + durable: true, + containsProtectedSource: false, + encrypted: false, + }, + ], + issuedAt, + }); + + expect(report.state).toBe('approval_required'); + expect(report.repairs[0]).toMatchObject({ + driftKind: 'object_storage_root_mismatch', + repairActionKind: 'quarantine_object_storage_artifact', + requiresOperatorApproval: true, + }); + }); + + it('blocks staging-testnet readback without storing Supabase secrets', () => { + const readback = buildSupabaseStagingTestnetProjectionReadback({ + readbackId: 'readback-blocked-1', + lane: 'staging-testnet', + supabaseProjectRef: 'tkpyosihuouusyaxtbau', + restHost: 'tkpyosihuouusyaxtbau.supabase.co', + adminCredentialState: 'missing', + tableReadbacks: [ + { + table: 'btd_terminal_journal_entries', + expectedCount: 4, + observedCount: 3, + synchronized: false, + }, + ], + issuedAt, + }); + const report = reconcileLedgerDatabaseProjection({ + reconciliationId: 'reconciliation-readback-blocked-1', + ledgerFacts: [], + databaseFacts: [], + stagingTestnetReadback: readback, + issuedAt, + }); + + expect(readback.state).toBe('blocked'); + expect(readback.secretValuesStored).toBe(false); + expect(readback.blockingReasons).toEqual( + expect.arrayContaining([ + 'btd_terminal_journal_entries expected 4 row(s) and observed 3.', + 'Supabase admin credential is missing from the untracked environment.', + ]), + ); + expect(report.repairs[0]).toMatchObject({ + repairKind: 'staging_testnet_readback', + driftKind: 'staging_testnet_readback_blocked', + repairActionKind: 'retry_staging_testnet_readback', + }); + }); + + it('rejects protected source object-storage artifacts unless encrypted', () => { + expect(() => + reconcileLedgerDatabaseProjection({ + reconciliationId: 'reconciliation-protected-source-1', + ledgerFacts: [], + databaseFacts: [], + objectStorageArtifacts: [ + { + factId: 'protected-source-artifact-1', + artifactId: 'protected-source-artifact-1', + artifactKind: 'asset_pack_protected_source_encrypted', + storageRoot: 'sha256:protected-source-root', + sourceVisibility: 'source_safe', + durable: true, + containsProtectedSource: true, + encrypted: false, + }, + ], + issuedAt, + }), + ).toThrow('Object storage artifacts containing protected source must be encrypted.'); + }); + + it('rejects accidental Supabase or OpenAI secret values in readback receipts', () => { + expect(() => + buildSupabaseStagingTestnetProjectionReadback({ + readbackId: 'readback-secret-1', + lane: 'staging-testnet', + supabaseProjectRef: 'tkpyosihuouusyaxtbau', + restHost: 'sb_secret__should-not-be-here', + adminCredentialState: 'provided_out_of_band', + tableReadbacks: [], + issuedAt, + }), + ).toThrow('restHost must not contain a secret value.'); + }); +}); diff --git a/packages/btd/src/api-boundaries.ts b/packages/btd/src/api-boundaries.ts index 5fab4b18a..893789cb6 100644 --- a/packages/btd/src/api-boundaries.ts +++ b/packages/btd/src/api-boundaries.ts @@ -89,7 +89,9 @@ import type { DatabaseProjectedFact, LedgerObservedFact, MetaphysicalCanonicalFact, + ObjectStorageArtifactFact, ProjectionRepairReceipt, + SupabaseStagingTestnetProjectionReadback, } from './reconciliation'; import { reconcileLedgerDatabaseProjection } from './reconciliation'; import type { @@ -417,7 +419,9 @@ export interface BtdLedgerDatabaseReconciliationInput { reconciliationId: string; ledgerFacts: LedgerObservedFact[]; databaseFacts: DatabaseProjectedFact[]; + objectStorageArtifacts?: ObjectStorageArtifactFact[]; metaphysicalFacts?: MetaphysicalCanonicalFact[]; + stagingTestnetReadback?: SupabaseStagingTestnetProjectionReadback | null; settlementConservationChecks?: Parameters[0]['settlementConservationChecks']; commitToRegistry?: boolean; actorId?: string; @@ -1177,7 +1181,9 @@ export function buildBtdLedgerDatabaseReconciliationSettlement( reconciliationId: input.reconciliationId, ledgerFacts: input.ledgerFacts, databaseFacts: input.databaseFacts, + objectStorageArtifacts: input.objectStorageArtifacts, metaphysicalFacts: input.metaphysicalFacts, + stagingTestnetReadback: input.stagingTestnetReadback, settlementConservationChecks: input.settlementConservationChecks, issuedAt: input.issuedAt, }); @@ -1202,9 +1208,12 @@ export function buildBtdLedgerDatabaseReconciliationSettlement( receiptRoots: [ report.reconciliationId, ...report.repairs.map((repair) => repair.repairId), + ...report.objectStorageArtifacts.map((artifact) => artifact.storageRoot), ...report.metaphysicalFacts.map((fact) => fact.receiptRoot ?? fact.canonicalRoot), report.proofRoots.ledgerObservedRoot, report.proofRoots.databaseProjectionRoot, + report.proofRoots.objectStorageRoot, + report.proofRoots.stagingTestnetReadbackRoot, report.proofRoots.repairPlanRoot, report.proofRoots.settlementConservationRoot, ], diff --git a/packages/btd/src/reconciliation.ts b/packages/btd/src/reconciliation.ts index ff5ed6d4a..065f79558 100644 --- a/packages/btd/src/reconciliation.ts +++ b/packages/btd/src/reconciliation.ts @@ -3,6 +3,8 @@ import { assertNonEmptyString } from './constants'; export type ProjectionRepairKind = | 'ledger_finality_state' | 'ledger_anchor_root' + | 'object_storage_artifact' + | 'staging_testnet_readback' | 'terminal_post_state' | 'receipt_root' | 'settlement_conservation' @@ -13,13 +15,19 @@ export type ProjectionDriftKind = | 'ledger_root_mismatch' | 'ledger_finality_mismatch' | 'database_orphan_projection' + | 'missing_object_storage_artifact' + | 'object_storage_root_mismatch' + | 'staging_testnet_readback_blocked' | 'settlement_conservation_drift'; export type ProjectionRepairActionKind = | 'retry_database_readback' + | 'retry_object_storage_write' + | 'retry_staging_testnet_readback' | 'project_ledger_fact' | 'update_finality_state' | 'quarantine_database_projection' + | 'quarantine_object_storage_artifact' | 'pause_settlement_unlock' | 'recover_delivery'; @@ -53,6 +61,59 @@ export interface DatabaseProjectedFact { factId: string; projectedLedgerRoot: string; projectedFinalityState: 'prepared' | 'broadcast' | 'confirmed' | 'reorged' | 'failed'; + projectedObjectStorageRoot?: string; +} + +export type ObjectStorageArtifactKind = + | 'pipeline_evidence' + | 'pipeline_telemetry' + | 'asset_pack_source_safe_preview' + | 'asset_pack_protected_source_encrypted' + | 'delivery_manifest' + | 'ledger_projection_artifact'; + +export type ObjectStorageSourceVisibility = + | 'proof_public' + | 'source_safe' + | 'encrypted_protected_source'; + +export interface ObjectStorageArtifactFact { + factId: string; + artifactId: string; + artifactKind: ObjectStorageArtifactKind; + storageRoot: string; + manifestRoot?: string; + sourceVisibility: ObjectStorageSourceVisibility; + durable: boolean; + containsProtectedSource: boolean; + encrypted: boolean; +} + +export type SupabaseProjectionLane = 'local' | 'staging-testnet' | 'production-mainnet'; +export type SupabaseProjectionCredentialState = 'provided_out_of_band' | 'missing'; + +export interface SupabaseProjectionTableReadback { + table: string; + expectedCount: number; + observedCount: number; + synchronized: boolean; + proofRoot?: string; +} + +export interface SupabaseStagingTestnetProjectionReadback { + kind: 'btd.supabase_projection_readback'; + readbackId: string; + lane: SupabaseProjectionLane; + supabaseProjectRef: string; + restHost: string; + databaseHost?: string; + adminCredentialState: SupabaseProjectionCredentialState; + secretValuesStored: false; + tableReadbacks: SupabaseProjectionTableReadback[]; + state: 'synchronized' | 'blocked'; + blockingReasons: string[]; + proofRoot: string; + issuedAt: string; } export type MetaphysicalCanonicalFactKind = @@ -105,7 +166,9 @@ export interface SettlementConservationProjection { export interface LedgerDatabaseReconciliationProofRoots { ledgerObservedRoot: string; databaseProjectionRoot: string; + objectStorageRoot: string; metaphysicalCanonicalRoot: string; + stagingTestnetReadbackRoot: string; repairPlanRoot: string; settlementConservationRoot: string; } @@ -119,22 +182,91 @@ export interface LedgerDatabaseReconciliationReport { driftKindCounts: Record; proofRoots: LedgerDatabaseReconciliationProofRoots; settlementConservation: SettlementConservationProjection; + objectStorageArtifacts: ObjectStorageArtifactFact[]; metaphysicalFacts: MetaphysicalCanonicalFact[]; + stagingTestnetReadback: SupabaseStagingTestnetProjectionReadback | null; blocking: boolean; } +export function buildSupabaseStagingTestnetProjectionReadback(input: { + readbackId: string; + lane: SupabaseProjectionLane; + supabaseProjectRef: string; + restHost: string; + databaseHost?: string; + adminCredentialState: SupabaseProjectionCredentialState; + tableReadbacks: SupabaseProjectionTableReadback[]; + issuedAt?: string; +}): SupabaseStagingTestnetProjectionReadback { + const readbackId = assertNonEmptyString(input.readbackId, 'readbackId'); + const tableReadbacks = input.tableReadbacks.map(assertSupabaseProjectionTableReadback); + const blockingReasons = tableReadbacks + .filter((entry) => !entry.synchronized) + .map( + (entry) => + `${entry.table} expected ${entry.expectedCount} row(s) and observed ${entry.observedCount}.`, + ); + + if (input.adminCredentialState === 'missing') { + blockingReasons.push('Supabase admin credential is missing from the untracked environment.'); + } + + const restHost = assertSecretFreeIdentifier(input.restHost, 'restHost'); + const databaseHost = input.databaseHost + ? assertSecretFreeIdentifier(input.databaseHost, 'databaseHost') + : undefined; + const supabaseProjectRef = assertSecretFreeIdentifier( + input.supabaseProjectRef, + 'supabaseProjectRef', + ); + + return { + kind: 'btd.supabase_projection_readback', + readbackId, + lane: input.lane, + supabaseProjectRef, + restHost, + databaseHost, + adminCredentialState: input.adminCredentialState, + secretValuesStored: false, + tableReadbacks, + state: blockingReasons.length ? 'blocked' : 'synchronized', + blockingReasons, + proofRoot: stableProofRoot('supabase-projection-readback', [ + readbackId, + input.lane, + supabaseProjectRef, + restHost, + databaseHost ?? null, + input.adminCredentialState, + tableReadbacks, + blockingReasons, + ]), + issuedAt: input.issuedAt ?? new Date().toISOString(), + }; +} + export function reconcileLedgerDatabaseProjection(input: { reconciliationId: string; ledgerFacts: LedgerObservedFact[]; databaseFacts: DatabaseProjectedFact[]; + objectStorageArtifacts?: ObjectStorageArtifactFact[]; metaphysicalFacts?: MetaphysicalCanonicalFact[]; + stagingTestnetReadback?: SupabaseStagingTestnetProjectionReadback | null; settlementConservationChecks?: SettlementConservationCheck[]; issuedAt?: string; }): LedgerDatabaseReconciliationReport { const reconciliationId = assertNonEmptyString(input.reconciliationId, 'reconciliationId'); const databaseByFactId = new Map(input.databaseFacts.map((fact) => [fact.factId, fact])); const ledgerFactIds = new Set(input.ledgerFacts.map((fact) => fact.factId)); + const objectStorageArtifacts = (input.objectStorageArtifacts ?? []).map( + assertObjectStorageArtifactFact, + ); + const objectStorageFactIds = new Set(objectStorageArtifacts.map((fact) => fact.factId)); const metaphysicalFacts = (input.metaphysicalFacts ?? []).map(assertMetaphysicalFact); + const stagingTestnetReadback = input.stagingTestnetReadback + ? assertSupabaseStagingTestnetProjectionReadback(input.stagingTestnetReadback) + : null; const settlementConservationChecks = (input.settlementConservationChecks ?? []).map( assertSettlementConservationCheck, ); @@ -204,7 +336,9 @@ export function reconcileLedgerDatabaseProjection(input: { for (const databaseFact of input.databaseFacts) { assertDatabaseFact(databaseFact); - if (ledgerFactIds.has(databaseFact.factId)) continue; + if (ledgerFactIds.has(databaseFact.factId) || objectStorageFactIds.has(databaseFact.factId)) { + continue; + } repairs.push(buildRepairReceipt({ reconciliationId, factId: databaseFact.factId, @@ -220,6 +354,61 @@ export function reconcileLedgerDatabaseProjection(input: { })); } + for (const artifact of objectStorageArtifacts) { + const projected = databaseByFactId.get(artifact.factId); + + if (!artifact.durable) { + repairs.push(buildRepairReceipt({ + reconciliationId, + factId: artifact.factId, + suffix: 'object_storage_missing', + repairKind: 'object_storage_artifact', + driftKind: 'missing_object_storage_artifact', + repairActionKind: 'retry_object_storage_write', + before: 'missing', + after: artifact.storageRoot, + blocking: true, + requiresOperatorApproval: false, + issuedAt, + })); + } + + if ( + projected?.projectedObjectStorageRoot && + projected.projectedObjectStorageRoot !== artifact.storageRoot + ) { + repairs.push(buildRepairReceipt({ + reconciliationId, + factId: artifact.factId, + suffix: 'object_storage_root', + repairKind: 'object_storage_artifact', + driftKind: 'object_storage_root_mismatch', + repairActionKind: 'quarantine_object_storage_artifact', + before: projected.projectedObjectStorageRoot, + after: artifact.storageRoot, + blocking: true, + requiresOperatorApproval: true, + issuedAt, + })); + } + } + + if (stagingTestnetReadback?.state === 'blocked') { + repairs.push(buildRepairReceipt({ + reconciliationId, + factId: stagingTestnetReadback.readbackId, + suffix: 'staging_testnet_readback', + repairKind: 'staging_testnet_readback', + driftKind: 'staging_testnet_readback_blocked', + repairActionKind: 'retry_staging_testnet_readback', + before: stagingTestnetReadback.blockingReasons.join('; ') || 'blocked', + after: 'synchronized', + blocking: true, + requiresOperatorApproval: false, + issuedAt, + })); + } + for (const check of settlementConservationChecks) { if (isConservationBalanced(check)) continue; repairs.push(buildRepairReceipt({ @@ -246,7 +435,11 @@ export function reconcileLedgerDatabaseProjection(input: { const proofRoots = { ledgerObservedRoot: stableProofRoot('ledger-observed', input.ledgerFacts), databaseProjectionRoot: stableProofRoot('database-projected', input.databaseFacts), + objectStorageRoot: stableProofRoot('object-storage-artifacts', objectStorageArtifacts), metaphysicalCanonicalRoot: stableProofRoot('metaphysical-canonical', metaphysicalFacts), + stagingTestnetReadbackRoot: + stagingTestnetReadback?.proofRoot ?? + stableProofRoot('supabase-projection-readback', ['not-provided', reconciliationId]), repairPlanRoot: stableProofRoot('repair-plan', repairs), settlementConservationRoot: settlementConservation.proofRoot, }; @@ -261,7 +454,9 @@ export function reconcileLedgerDatabaseProjection(input: { driftKindCounts, proofRoots, settlementConservation, + objectStorageArtifacts, metaphysicalFacts, + stagingTestnetReadback, blocking, }; } @@ -274,6 +469,36 @@ function assertLedgerFact(fact: LedgerObservedFact): void { function assertDatabaseFact(fact: DatabaseProjectedFact): void { assertNonEmptyString(fact.factId, 'factId'); assertNonEmptyString(fact.projectedLedgerRoot, 'projectedLedgerRoot'); + if (fact.projectedObjectStorageRoot !== undefined) { + assertNonEmptyString(fact.projectedObjectStorageRoot, 'projectedObjectStorageRoot'); + } +} + +function assertObjectStorageArtifactFact( + fact: ObjectStorageArtifactFact, +): ObjectStorageArtifactFact { + assertNonEmptyString(fact.factId, 'factId'); + assertNonEmptyString(fact.artifactId, 'artifactId'); + assertNonEmptyString(fact.artifactKind, 'artifactKind'); + assertNonEmptyString(fact.storageRoot, 'storageRoot'); + if (fact.manifestRoot !== undefined) { + assertNonEmptyString(fact.manifestRoot, 'manifestRoot'); + } + assertNonEmptyString(fact.sourceVisibility, 'sourceVisibility'); + + if (fact.containsProtectedSource && !fact.encrypted) { + throw new Error('Object storage artifacts containing protected source must be encrypted.'); + } + if (fact.containsProtectedSource && fact.sourceVisibility !== 'encrypted_protected_source') { + throw new Error( + 'Object storage protected source artifacts must be marked encrypted_protected_source.', + ); + } + if (!fact.containsProtectedSource && fact.sourceVisibility === 'encrypted_protected_source') { + throw new Error('Encrypted protected source visibility requires protected source content.'); + } + + return fact; } function assertMetaphysicalFact(fact: MetaphysicalCanonicalFact): MetaphysicalCanonicalFact { @@ -305,6 +530,46 @@ function assertSettlementConservationCheck( return check; } +function assertSupabaseProjectionTableReadback( + check: SupabaseProjectionTableReadback, +): SupabaseProjectionTableReadback { + assertSecretFreeIdentifier(check.table, 'table'); + assertNonNegativeSats(check.expectedCount, 'expectedCount'); + assertNonNegativeSats(check.observedCount, 'observedCount'); + if (check.proofRoot !== undefined) assertNonEmptyString(check.proofRoot, 'proofRoot'); + return check; +} + +function assertSupabaseStagingTestnetProjectionReadback( + readback: SupabaseStagingTestnetProjectionReadback, +): SupabaseStagingTestnetProjectionReadback { + assertNonEmptyString(readback.readbackId, 'readbackId'); + assertSecretFreeIdentifier(readback.supabaseProjectRef, 'supabaseProjectRef'); + assertSecretFreeIdentifier(readback.restHost, 'restHost'); + if (readback.databaseHost !== undefined) { + assertSecretFreeIdentifier(readback.databaseHost, 'databaseHost'); + } + if (readback.secretValuesStored !== false) { + throw new Error('Supabase projection readback receipts must not store secret values.'); + } + readback.tableReadbacks.forEach(assertSupabaseProjectionTableReadback); + assertNonEmptyString(readback.proofRoot, 'proofRoot'); + return readback; +} + +function assertSecretFreeIdentifier(value: string, label: string): string { + const identifier = assertNonEmptyString(value, label); + if ( + /sb_secret__/u.test(identifier) || + /service_role/u.test(identifier) || + /sk-(?:proj|live|test)-/u.test(identifier) || + /^eyJ[\w-]+\.[\w-]+\.[\w-]+$/u.test(identifier) + ) { + throw new Error(`${label} must not contain a secret value.`); + } + return identifier; +} + function assertNonNegativeSats(value: number, field: string): void { if (!Number.isInteger(value) || value < 0) { throw new Error(`${field} must be a non-negative integer sat amount.`); @@ -372,8 +637,14 @@ function describeRepairAction(repair: ProjectionRepairReceipt): string { return `Project ledger fact ${repair.factId} into the database from ${repair.before} to ${repair.after}.`; case 'update_finality_state': return `Update database finality for ${repair.factId} from ${repair.before} to ${repair.after}.`; + case 'retry_object_storage_write': + return `Retry object-storage artifact write for ${repair.factId} before unlock or delivery.`; + case 'retry_staging_testnet_readback': + return `Retry staging-testnet projection readback for ${repair.factId}.`; case 'quarantine_database_projection': return `Quarantine database projection ${repair.factId} until a matching ledger observation exists.`; + case 'quarantine_object_storage_artifact': + return `Quarantine object-storage projection ${repair.factId} until the artifact root agrees.`; case 'pause_settlement_unlock': return `Pause settlement unlock for ${repair.factId} until the drift is reconciled.`; case 'recover_delivery': @@ -389,6 +660,9 @@ function countDriftKinds(repairs: ProjectionRepairReceipt[]): Record { expect(source).toContain("execution.store('asset-pack/settlement', 'unlock'"); expect(source).toContain("execution.store('asset-pack/preview', 'feeQuote'"); expect(source).toContain('reconcileLedgerDatabaseProjection'); + expect(source).toContain('buildSupabaseStagingTestnetProjectionReadback'); + expect(source).toContain('objectStorageArtifacts'); + expect(source).toContain('buildProjectionTableReadbacks'); + expect(source).toContain('pipeline_evidence'); + expect(source).toContain('asset_pack_source_safe_preview'); + expect(source).toContain('staging-testnet-readback-'); expect(source).toContain("execution.store('asset-pack/settlement', 'ledgerDatabaseReconciliation'"); expect(source).toContain("execution.store('asset-pack/settlement', 'organizationAuthority'"); expect(source).toContain('organizationAuthorityDecision'); diff --git a/packages/pipeline-hosts/src/asset-pack-harness.ts b/packages/pipeline-hosts/src/asset-pack-harness.ts index c65dae3ee..d1d943ef9 100644 --- a/packages/pipeline-hosts/src/asset-pack-harness.ts +++ b/packages/pipeline-hosts/src/asset-pack-harness.ts @@ -913,6 +913,45 @@ function normalizeBtcLedgerNetwork(value) { return 'testnet'; } +function hostFromUrl(value) { + if (!value) return null; + try { + return new URL(value).hostname; + } catch { + return null; + } +} + +const READBACK_TABLE_NAMES = { + semanticMeasurement: 'btd_semantic_volume_measurements', + measureMintReceipt: 'btd_measure_mint_receipts', + assetPackRange: 'btd_asset_pack_ranges', + btdCell: 'btd_cells', + ownershipEvent: 'btd_ownership_events', + readLicense: 'btd_read_licenses', + mintReceipt: 'btd_mint_receipts', + btcFeeTransaction: 'btc_fee_transactions', + ledgerAnchor: 'btd_asset_pack_ledger_anchors', + terminalJournal: 'btd_terminal_journal_entries', + cryptoTelemetry: 'btd_crypto_telemetry_events', +}; + +function buildProjectionTableReadbacks(readback) { + return Object.entries(readback || {}).map(([key, present]) => ({ + table: READBACK_TABLE_NAMES[key] || key, + expectedCount: 1, + observedCount: present ? 1 : 0, + synchronized: Boolean(present), + proofRoot: rootOf({ table: READBACK_TABLE_NAMES[key] || key, present: Boolean(present) }), + })); +} + +function supabaseProjectRefFromHost(host) { + if (!host) return 'staging-testnet-unresolved'; + const [projectRef] = String(host).split('.'); + return projectRef || 'staging-testnet-unresolved'; +} + function ledgerWallet(kind, explicit, fallback) { const value = String(explicit || '').trim(); if (value) return value; @@ -1649,7 +1688,7 @@ try { }, { enablePipelineStreaming, factoryPipelineExecution }, { applyAssetPackSettlementUnlockToPreview, buildAssetPackSettlementUnlock }, - { reconcileLedgerDatabaseProjection }, + { buildSupabaseStagingTestnetProjectionReadback, reconcileLedgerDatabaseProjection }, { evaluateBtdOrganizationInterfaceAuthority }, btdReceiptBuilders, ] = await Promise.all([ @@ -1817,6 +1856,25 @@ try { }); const ledgerSettlement = await settleAssetPackLedger(settlementResultState); + const supabaseRestHost = hostFromUrl( + process.env.NEXT_PUBLIC_SUPABASE_URL || + process.env.SUPABASE_URL || + process.env.BITCODE_SUPABASE_URL + ); + const supabaseDatabaseHost = hostFromUrl(process.env.SUPABASE_DB_URL || process.env.DATABASE_URL); + const stagingTestnetReadback = ledgerSettlement?.readback + ? buildSupabaseStagingTestnetProjectionReadback({ + readbackId: 'staging-testnet-readback-' + runId, + lane: 'staging-testnet', + supabaseProjectRef: + process.env.BITCODE_SUPABASE_PROJECT_REF || + supabaseProjectRefFromHost(supabaseRestHost), + restHost: supabaseRestHost || 'staging-testnet-unresolved.supabase.co', + databaseHost: supabaseDatabaseHost || undefined, + adminCredentialState: supabase ? 'provided_out_of_band' : 'missing', + tableReadbacks: buildProjectionTableReadbacks(ledgerSettlement.readback), + }) + : null; const ledgerDatabaseReconciliation = ledgerSettlement?.assetPackId ? reconcileLedgerDatabaseProjection({ reconciliationId: 'harness-reconciliation-' + runId, @@ -1851,6 +1909,11 @@ try { factId: ledgerSettlement.assetPackId, projectedLedgerRoot: ledgerSettlement.proofRoots?.proofRoot || rootOf({ assetPackId: ledgerSettlement.assetPackId }), projectedFinalityState: ledgerSettlement.status === 'settled' ? 'confirmed' : 'failed', + projectedObjectStorageRoot: rootOf({ + artifactPath: '${EVIDENCE_PATH}', + assetPackId: ledgerSettlement.assetPackId, + manifestRoot, + }), }] : []), ...(ledgerSettlement.readback?.btcFeeTransaction && ledgerSettlement.btcFeeReceiptId @@ -1872,6 +1935,48 @@ try { }] : []), ], + objectStorageArtifacts: [ + { + factId: ledgerSettlement.assetPackId, + artifactId: 'pipeline-evidence-' + runId, + artifactKind: 'pipeline_evidence', + storageRoot: rootOf({ + artifactPath: '${EVIDENCE_PATH}', + assetPackId: ledgerSettlement.assetPackId, + manifestRoot, + }), + manifestRoot: manifestRoot ? 'sha256:' + manifestRoot : undefined, + sourceVisibility: 'proof_public', + durable: true, + containsProtectedSource: false, + encrypted: false, + }, + { + factId: 'pipeline-telemetry-' + runId, + artifactId: 'pipeline-telemetry-' + runId, + artifactKind: 'pipeline_telemetry', + storageRoot: rootOf({ artifactPath: '${TELEMETRY_PATH}', runId }), + manifestRoot: manifestRoot ? 'sha256:' + manifestRoot : undefined, + sourceVisibility: 'proof_public', + durable: true, + containsProtectedSource: false, + encrypted: false, + }, + { + factId: 'source-safe-preview-' + runId, + artifactId: 'source-safe-preview-' + runId, + artifactKind: 'asset_pack_source_safe_preview', + storageRoot: + ledgerSettlement.assetPackMintReceipt?.sourceSafePreviewRoot || + rootOf({ sourceSafePreview, protectedSourceVisible: false }), + manifestRoot: ledgerSettlement.proofRoots?.sourceManifestRoot, + sourceVisibility: 'source_safe', + durable: true, + containsProtectedSource: false, + encrypted: false, + }, + ], + stagingTestnetReadback, settlementConservationChecks: ledgerSettlement.btcFee ? [{ checkId: 'btc-fee-conservation-' + runId, diff --git a/scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs b/scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs new file mode 100644 index 000000000..fbecc5d7d --- /dev/null +++ b/scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs @@ -0,0 +1,243 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 5 testnet ledger projection hardening, object-storage facts, secret-free Supabase readback, Terminal rendering, tests, docs, and workflow readiness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-5-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 5 work must occur on version/v30 or v30/gate-5-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + 'packages/btd/src/reconciliation.ts', + 'packages/btd/src/api-boundaries.ts', + 'packages/btd/__tests__/reconciliation.test.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'packages/pipeline-hosts/src/asset-pack-harness.ts', + 'packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts', + 'uapi/app/terminal/terminal-journal-reconciliation.ts', + 'uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx', + 'uapi/app/terminal/terminal-transaction-detail-snapshot.ts', + 'uapi/tests/terminalJournalReconciliation.test.ts', + 'uapi/tests/terminalTransactionDetailSnapshot.test.ts', + 'packages/btd/README.md', + 'uapi/app/terminal/README.md', + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + ]) { + assertCheck(failures, fileExists(root, relativePath), `Missing V30 Gate 5 file: ${relativePath}`); + } + + const reconciliation = read(root, 'packages/btd/src/reconciliation.ts'); + const apiBoundary = read(root, 'packages/btd/src/api-boundaries.ts'); + const btdTest = read(root, 'packages/btd/__tests__/reconciliation.test.ts'); + const apiTest = read(root, 'packages/api/src/routes/__tests__/btd-crypto.test.ts'); + const harness = read(root, 'packages/pipeline-hosts/src/asset-pack-harness.ts'); + const harnessTest = read(root, 'packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts'); + const terminalProjection = read(root, 'uapi/app/terminal/terminal-journal-reconciliation.ts'); + const terminalCard = read(root, 'uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx'); + const terminalSnapshot = read(root, 'uapi/app/terminal/terminal-transaction-detail-snapshot.ts'); + const terminalTest = read(root, 'uapi/tests/terminalJournalReconciliation.test.ts'); + const btdReadme = read(root, 'packages/btd/README.md'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + for (const symbol of [ + 'ObjectStorageArtifactFact', + 'SupabaseStagingTestnetProjectionReadback', + 'buildSupabaseStagingTestnetProjectionReadback', + 'objectStorageArtifacts', + 'stagingTestnetReadback', + 'objectStorageRoot', + 'stagingTestnetReadbackRoot', + ]) { + assertCheck(failures, reconciliation.includes(symbol), `BTD reconciliation primitive is missing ${symbol}.`); + } + + for (const driftOrAction of [ + 'missing_object_storage_artifact', + 'object_storage_root_mismatch', + 'staging_testnet_readback_blocked', + 'retry_object_storage_write', + 'retry_staging_testnet_readback', + 'quarantine_object_storage_artifact', + ]) { + assertCheck(failures, reconciliation.includes(driftOrAction), `BTD reconciliation must define ${driftOrAction}.`); + assertCheck(failures, btdTest.includes(driftOrAction), `BTD reconciliation tests must cover ${driftOrAction}.`); + } + + for (const secretGuard of [ + 'secretValuesStored: false', + 'sb_secret__', + 'service_role', + 'sk-(?:proj|live|test)-', + 'must not contain a secret value', + ]) { + assertCheck(failures, reconciliation.includes(secretGuard), `Supabase readback receipt must guard ${secretGuard}.`); + } + + for (const apiEvidence of [ + 'objectStorageArtifacts', + 'stagingTestnetReadback', + ]) { + assertCheck(failures, apiBoundary.includes(apiEvidence), `BTD API boundary must accept ${apiEvidence}.`); + } + for (const apiEvidence of [ + 'objectStorageArtifacts', + 'stagingTestnetReadback', + 'projectedObjectStorageRoot', + 'secretValuesStored', + ]) { + assertCheck(failures, apiTest.includes(apiEvidence), `API tests must cover ${apiEvidence}.`); + } + + for (const harnessEvidence of [ + 'buildSupabaseStagingTestnetProjectionReadback', + 'buildProjectionTableReadbacks', + 'objectStorageArtifacts', + 'pipeline_evidence', + 'asset_pack_source_safe_preview', + 'staging-testnet-readback-', + ]) { + assertCheck(failures, harness.includes(harnessEvidence), `Sandbox harness must emit ${harnessEvidence}.`); + assertCheck(failures, harnessTest.includes(harnessEvidence), `Harness tests must assert ${harnessEvidence}.`); + } + + for (const terminalEvidence of [ + 'objectStorageFacts', + 'object_storage_artifact', + 'ledgerDatabaseReconciliation', + 'Object storage artifacts', + 'blocks unlock or delivery', + ]) { + assertCheck( + failures, + terminalProjection.includes(terminalEvidence) || + terminalCard.includes(terminalEvidence) || + terminalSnapshot.includes(terminalEvidence) || + terminalTest.includes(terminalEvidence), + `Terminal reconciliation surface must include ${terminalEvidence}.`, + ); + } + + assertCheck( + failures, + btdReadme.includes('ledger/database/object-storage projection reconciliation'), + 'BTD README must document Gate 5 projection ownership.', + ); + assertCheck( + failures, + terminalReadme.includes('object-storage artifact facts'), + 'Terminal README must document object-storage reconciliation facts.', + ); + assertCheck( + failures, + spec.includes('object-storage artifact facts') && + spec.includes('Supabase staging-testnet readback receipts must never store'), + 'V30 SPEC must define Gate 5 projection and secret-free readback canon.', + ); + assertCheck(failures, delta.includes('Gate 5 implementation centers'), 'V30 DELTA must include Gate 5 implementation evidence.'); + assertCheck(failures, notes.includes('Gate 5 testnet ledger projection notes'), 'V30 NOTES must include Gate 5 implementation notes.'); + assertCheck(failures, parity.includes('## Gate 5 Parity'), 'V30 PARITY must include Gate 5 parity evidence.'); + assertCheck(failures, parity.includes('Gate 5 accepted boundaries'), 'V30 PARITY must include Gate 5 accepted boundaries.'); + assertCheck(failures, packageJson.includes('"check:v30-gate5"'), 'package.json must expose check:v30-gate5.'); + assertCheck( + failures, + gateWorkflow.includes('check-v30-gate5-testnet-ledger-projection-hardening.mjs'), + 'Gate workflow must run the V30 Gate 5 checker.', + ); + + if (failures.length) { + process.stderr.write('V30 Gate 5 testnet ledger projection hardening check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V30 Gate 5 testnet ledger projection hardening check passed.\n'); +} + +try { + main(); +} catch (error) { + const detail = error instanceof Error ? error.message : String(error); + process.stderr.write(`${detail}\n`); + process.exitCode = 1; +} diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 59fe795af..bdc0c6b3d 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -133,11 +133,13 @@ place for prompt templates, interpolated prompts, raw model responses, parsed typed outputs, tool inputs/outputs, and harness evidence coverage. The Journal section is also the settlement reconciliation repair cockpit. -It must distinguish ledger-observed facts, database-projected facts, and -metaphysical canonical root facts; classify drift; show blocking reasons; -surface repair actions; list proof roots; and keep repair receipts readable. -BTC fee conservation drift blocks unlock, confirmed ledger facts missing from -database projection require approval, and settled transactions with missing +It must distinguish ledger-observed facts, database-projected facts, +object-storage artifact facts, and metaphysical canonical root facts; classify +drift; show blocking reasons; surface repair actions; list proof roots; and +keep repair receipts readable. BTC fee conservation drift blocks unlock, +confirmed ledger facts missing from database projection require approval, +object-storage root mismatches require quarantine, missing durable artifacts +are retryable unlock blockers, and settled transactions with missing pull-request delivery surface delivery recovery without exposing protected AssetPack source before payment. diff --git a/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx b/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx index 518cdb13f..6baacad3b 100644 --- a/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx +++ b/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx @@ -91,6 +91,11 @@ export default function TerminalTransactionJournalReconciliationCard({ summary="Readback projection booleans reported by the pipeline settlement path." facts={reconciliation.projectedFacts} /> + ; observedFacts: TerminalJournalReconciliationFact[]; projectedFacts: TerminalJournalReconciliationFact[]; + objectStorageFacts: TerminalJournalReconciliationFact[]; canonicalFacts: TerminalJournalReconciliationFact[]; journalEntries: Array<{ id: string; title: string; summary: string; supportingText?: string }>; repairReceipts: Array<{ id: string; title: string; summary: string; supportingText?: string }>; @@ -48,6 +53,10 @@ function asString(value: unknown) { return typeof value === 'string' && value.trim() ? value : null; } +function isRecord(value: unknown): value is TerminalJsonRecord { + return typeof value === 'object' && value !== null; +} + function asNumber(value: unknown) { return typeof value === 'number' && Number.isFinite(value) ? value : null; } @@ -177,6 +186,44 @@ function buildProjectedFacts(settlement: TerminalLedgerSettlementSnapshot | null ); } +function buildObjectStorageFacts( + settlement: TerminalLedgerSettlementSnapshot | null, +): TerminalJournalReconciliationFact[] { + const report = settlement?.ledgerDatabaseReconciliation; + const artifacts = Array.isArray(report?.objectStorageArtifacts) + ? report.objectStorageArtifacts.filter((entry): entry is TerminalJsonRecord => Boolean(entry) && typeof entry === 'object') + : []; + + if (!artifacts.length) { + return [ + fact({ + id: 'object-storage-artifacts', + label: 'Object storage artifacts', + value: 'not projected', + state: 'missing', + source: 'object_storage_artifact', + blocksContradictoryProjection: false, + }), + ]; + } + + return artifacts.map((artifact) => { + const durable = artifact.durable === true; + const containsProtectedSource = artifact.containsProtectedSource === true; + const encrypted = artifact.encrypted === true; + const visibility = asString(artifact.sourceVisibility) || 'unknown'; + return fact({ + id: asString(artifact.factId) || asString(artifact.artifactId) || 'object-storage-artifact', + label: asString(artifact.artifactKind) || 'object storage artifact', + value: asString(artifact.storageRoot) || 'n/a', + state: durable ? visibility : 'missing', + source: 'object_storage_artifact', + blocksContradictoryProjection: + !durable || (containsProtectedSource && (!encrypted || visibility !== 'encrypted_protected_source')), + }); + }); +} + function buildCanonicalFacts( settlement: TerminalLedgerSettlementSnapshot | null, journal: TerminalJournalReadbackSnapshot | null, @@ -244,6 +291,46 @@ function buildRepairItems(repairs: TerminalReconciliationRepairSnapshot[]) { })); } +function buildReportRepairSnapshots( + settlement: TerminalLedgerSettlementSnapshot | null, +): TerminalReconciliationRepairSnapshot[] { + const report = settlement?.ledgerDatabaseReconciliation; + const repairs = Array.isArray(report?.repairs) + ? report.repairs.filter((entry): entry is TerminalJsonRecord => Boolean(entry) && typeof entry === 'object') + : []; + + return repairs.map((repair) => ({ + repairId: asString(repair.repairId) || asString(repair.repair_id) || 'n/a', + reconciliationId: + asString(repair.reconciliationId) || + asString(repair.reconciliation_id) || + asString(report?.reconciliationId) || + 'n/a', + factId: asString(repair.factId) || asString(repair.fact_id) || 'n/a', + repairKind: asString(repair.repairKind) || asString(repair.repair_kind) || 'n/a', + driftKind: asString(repair.driftKind) || asString(repair.drift_kind), + repairActionKind: asString(repair.repairActionKind) || asString(repair.repair_action_kind), + beforeValue: asString(repair.beforeValue) || asString(repair.before_value) || asString(repair.before) || 'n/a', + afterValue: asString(repair.afterValue) || asString(repair.after_value) || asString(repair.after) || 'n/a', + blocking: repair.blocking === true, + requiresOperatorApproval: repair.requiresOperatorApproval === true || repair.requires_operator_approval === true, + proofRoot: asString(repair.proofRoot) || asString(repair.proof_root), + issuedAt: asString(repair.issuedAt) || asString(repair.issued_at), + raw: repair, + })); +} + +function mergeRepairSnapshots( + journalRepairs: TerminalReconciliationRepairSnapshot[], + reportRepairs: TerminalReconciliationRepairSnapshot[], +) { + const byId = new Map(); + for (const repair of [...journalRepairs, ...reportRepairs]) { + byId.set(repair.repairId, repair); + } + return Array.from(byId.values()); +} + function deriveDriftKind(repair: TerminalReconciliationRepairSnapshot) { if (repair.driftKind) return repair.driftKind; if (repair.beforeValue === 'missing') return 'missing_database_projection'; @@ -289,8 +376,9 @@ function buildRepairActions( detail: TerminalRunDetailSnapshot | null, observedFacts: TerminalJournalReconciliationFact[], missingJournalEntryIds: string[], + repairs: TerminalReconciliationRepairSnapshot[], ) { - const actions = (journal?.repairs || []).map((repair) => ({ + const actions = repairs.map((repair) => ({ id: `${repair.repairId}:${deriveRepairActionKind(repair)}`, title: deriveRepairActionKind(repair), summary: summarizeRepairAction(repair), @@ -411,8 +499,10 @@ function uniqueProofRootItems(entries: Array<{ title: string; root: string; supp function buildProofRoots( journal: TerminalJournalReadbackSnapshot | null, + settlement: TerminalLedgerSettlementSnapshot | null, canonicalFacts: TerminalJournalReconciliationFact[], ) { + const report = settlement?.ledgerDatabaseReconciliation; const repairRoots = journal?.repairs.flatMap((repair) => repair.proofRoot @@ -440,8 +530,19 @@ function buildProofRoots( root: entry.value, supportingText: entry.source, })); - - return uniqueProofRootItems([...repairRoots, ...journalRoots, ...canonicalRoots]); + const reportProofRoots = isRecord(report?.proofRoots) + ? Object.entries(report.proofRoots).flatMap(([title, root]) => + typeof root === 'string' + ? [{ + title, + root, + supportingText: 'ledger database reconciliation report', + }] + : [], + ) + : []; + + return uniqueProofRootItems([...repairRoots, ...journalRoots, ...canonicalRoots, ...reportProofRoots]); } function findMissingExpectedJournalEntries(journal: TerminalJournalReadbackSnapshot | null) { @@ -454,6 +555,8 @@ function buildBlockingReasons( settlement: TerminalLedgerSettlementSnapshot | null, journal: TerminalJournalReadbackSnapshot | null, observedFacts: TerminalJournalReconciliationFact[], + repairs: TerminalReconciliationRepairSnapshot[], + objectStorageFacts: TerminalJournalReconciliationFact[], ) { const reasons: string[] = []; const readback = settlement?.readback || {}; @@ -479,7 +582,12 @@ function buildBlockingReasons( if (settlementConservationReason) { reasons.push(settlementConservationReason); } - for (const repair of journal?.repairs || []) { + for (const fact of objectStorageFacts) { + if (fact.blocksContradictoryProjection) { + reasons.push(`Object storage artifact ${fact.id} blocks unlock or delivery until repaired.`); + } + } + for (const repair of repairs) { if (repair.blocking) { reasons.push(`Repair ${repair.repairId} blocks ${repair.factId}.`); } @@ -563,9 +671,20 @@ export function buildTerminalJournalReconciliation( const journal = detail?.terminalJournal || null; const observedFacts = buildObservedFacts(settlement, journal); const projectedFacts = buildProjectedFacts(settlement); + const objectStorageFacts = buildObjectStorageFacts(settlement); const canonicalFacts = buildCanonicalFacts(settlement, journal); + const repairSnapshots = mergeRepairSnapshots( + journal?.repairs || [], + buildReportRepairSnapshots(settlement), + ); const missingJournalEntryIds = findMissingExpectedJournalEntries(journal); - const blockingReasons = buildBlockingReasons(settlement, journal, observedFacts); + const blockingReasons = buildBlockingReasons( + settlement, + journal, + observedFacts, + repairSnapshots, + objectStorageFacts, + ); if (missingJournalEntryIds.length) { blockingReasons.push(`Missing Terminal journal entries: ${missingJournalEntryIds.join(', ')}`); } @@ -576,9 +695,10 @@ export function buildTerminalJournalReconciliation( detail, observedFacts, missingJournalEntryIds, + repairSnapshots, ); - const proofRoots = buildProofRoots(journal, canonicalFacts); - const driftKindCounts = buildDriftKindCounts(journal?.repairs || [], missingJournalEntryIds); + const proofRoots = buildProofRoots(journal, settlement, canonicalFacts); + const driftKindCounts = buildDriftKindCounts(repairSnapshots, missingJournalEntryIds); return { state, @@ -591,15 +711,17 @@ export function buildTerminalJournalReconciliation( { label: 'State', value: stateLabel(state) }, { label: 'Journal entries', value: formatCount(journal?.entries.length || 0) }, { label: 'Projected facts', value: formatCount(projectedFacts.length) }, - { label: 'Repair receipts', value: formatCount(journal?.repairs.length || 0) }, + { label: 'Storage artifacts', value: formatCount(objectStorageFacts.length) }, + { label: 'Repair receipts', value: formatCount(repairSnapshots.length) }, { label: 'Repair actions', value: formatCount(repairActions.length) }, { label: 'Proof roots', value: formatCount(proofRoots.length) }, ], observedFacts, projectedFacts, + objectStorageFacts, canonicalFacts, journalEntries: buildJournalItems(journal?.entries || []), - repairReceipts: buildRepairItems(journal?.repairs || []), + repairReceipts: buildRepairItems(repairSnapshots), repairActions, proofRoots, driftKindCounts, @@ -609,6 +731,7 @@ export function buildTerminalJournalReconciliation( terminalJournal: journal, observedFacts, projectedFacts, + objectStorageFacts, canonicalFacts, missingJournalEntryIds, repairActions, diff --git a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts index b55128af6..899c8748d 100644 --- a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts +++ b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts @@ -57,6 +57,7 @@ export type TerminalLedgerSettlementSnapshot = { assetPackMintReceipt?: TerminalJsonRecord | null; readReceipt?: TerminalJsonRecord | null; rightsTransferReceipt?: TerminalJsonRecord | null; + ledgerDatabaseReconciliation?: TerminalJsonRecord | null; readback: Record; journalEntryIds: string[]; ownershipEventId: string | null; @@ -350,6 +351,9 @@ function coerceLedgerSettlement(value: unknown): TerminalLedgerSettlementSnapsho value.rights_transfer_receipt || value.btd_rights_transfer_receipt, ); + const ledgerDatabaseReconciliation = coerceJsonRecord( + value.ledgerDatabaseReconciliation || value.ledger_database_reconciliation, + ); const hasSettlementShape = coerceString(value.status) || coerceString(value.assetPackId) || @@ -358,6 +362,7 @@ function coerceLedgerSettlement(value: unknown): TerminalLedgerSettlementSnapsho assetPackMintReceipt || readReceipt || rightsTransferReceipt || + ledgerDatabaseReconciliation || Object.keys(readback).length > 0 || journalEntryIds.length > 0; @@ -378,6 +383,7 @@ function coerceLedgerSettlement(value: unknown): TerminalLedgerSettlementSnapsho assetPackMintReceipt, readReceipt, rightsTransferReceipt, + ledgerDatabaseReconciliation, readback, journalEntryIds, ownershipEventId: coerceString(value.ownershipEventId), diff --git a/uapi/tests/terminalJournalReconciliation.test.ts b/uapi/tests/terminalJournalReconciliation.test.ts index dc227ecdf..50b51c176 100644 --- a/uapi/tests/terminalJournalReconciliation.test.ts +++ b/uapi/tests/terminalJournalReconciliation.test.ts @@ -43,6 +43,25 @@ describe('terminal journal reconciliation', () => { readerWalletId: 'reader-wallet', btcFee: { finalityState: 'prepared' }, ownershipBoundary: null, + ledgerDatabaseReconciliation: { + objectStorageArtifacts: [ + { + factId: 'asset-pack-run-1', + artifactId: 'preview-artifact-run-1', + artifactKind: 'asset_pack_source_safe_preview', + storageRoot: 'sha256:preview-storage-root', + sourceVisibility: 'source_safe', + durable: true, + containsProtectedSource: false, + encrypted: false, + }, + ], + proofRoots: { + objectStorageRoot: 'btd-proof-root:object-storage-artifacts:terminal', + stagingTestnetReadbackRoot: 'btd-proof-root:supabase-projection-readback:terminal', + }, + repairs: [], + }, readback: { assetPackRange: true, btcFeeTransaction: true, @@ -85,11 +104,24 @@ describe('terminal journal reconciliation', () => { expect(result.state).toBe('aligned'); expect(result.observedFacts.every((fact) => fact.source === 'ledger_observed')).toBe(true); expect(result.projectedFacts.every((fact) => fact.source === 'database_projected')).toBe(true); + expect(result.objectStorageFacts.every((fact) => fact.source === 'object_storage_artifact')).toBe(true); expect(result.canonicalFacts.every((fact) => fact.source === 'metaphysical_canonical')).toBe(true); + expect(result.objectStorageFacts[0]).toMatchObject({ + id: 'asset-pack-run-1', + state: 'source_safe', + blocksContradictoryProjection: false, + }); expect(result.blockingReasons).toEqual([]); expect(result.repairActions).toEqual([]); expect(result.proofRoots.map((root) => root.title)).toEqual( - expect.arrayContaining(['pre-state root', 'post-state root', 'receipt root', 'Settlement journal root']), + expect.arrayContaining([ + 'pre-state root', + 'post-state root', + 'receipt root', + 'Settlement journal root', + 'objectStorageRoot', + 'stagingTestnetReadbackRoot', + ]), ); }); diff --git a/uapi/tests/terminalTransactionDetailSnapshot.test.ts b/uapi/tests/terminalTransactionDetailSnapshot.test.ts index b687bd6a2..7b538f3bf 100644 --- a/uapi/tests/terminalTransactionDetailSnapshot.test.ts +++ b/uapi/tests/terminalTransactionDetailSnapshot.test.ts @@ -326,6 +326,15 @@ describe('terminal-transaction-detail-snapshot helpers', () => { receiptRoot: 'rights-transfer-receipt-root-run-1', protectedSourceVisible: true, }, + ledger_database_reconciliation: { + kind: 'btd.ledger_database_reconciliation', + objectStorageArtifacts: [ + { + artifactId: 'preview-artifact-run-1', + storageRoot: 'sha256:preview-storage-root', + }, + ], + }, readback: { assetPackRange: true, btcFeeTransaction: true, @@ -489,6 +498,14 @@ describe('terminal-transaction-detail-snapshot helpers', () => { rightsTransferReceipt: { receiptRoot: 'rights-transfer-receipt-root-run-1', }, + ledgerDatabaseReconciliation: { + objectStorageArtifacts: [ + { + artifactId: 'preview-artifact-run-1', + storageRoot: 'sha256:preview-storage-root', + }, + ], + }, }); expect(snapshot.terminalJournal).toMatchObject({ expectedJournalEntryIds: ['journal-mint-run-1'], From 790daeb2843075b0bfea07ca9377d6eb791ceb53 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 18:37:09 -0300 Subject: [PATCH 06/15] V30 Gate 5: Stabilize journal reconciliation cards Allow Terminal reconciliation cards to render historical or partial journal snapshots that predate object-storage fact projection while preserving the new object-storage section for current reports. Proof: pnpm --dir uapi exec jest --runTestsByPath tests/api/readReviewRoute.test.ts tests/api/pipelineHarnessRoute.test.ts tests/terminalPipelineHarnessClient.test.ts tests/terminalDepositReadWorkbench.test.ts tests/terminalTransactionQuery.test.ts tests/terminalTransactionReadModel.test.ts tests/terminalWalletBtcOperation.test.ts tests/terminalJournalReconciliation.test.ts tests/terminalOrganizationAuthority.test.ts tests/protocolCommercialBoundary.test.ts tests/terminalTransactionDetailCards.test.tsx tests/terminalTransactionDetailSnapshot.test.ts tests/terminalUxBrowserProof.test.tsx tests/pipelineExecutionLogHeader.test.tsx --runInBand; pnpm -C uapi exec jest --coverage; pnpm --dir uapi exec tsc --noEmit --pretty false --- .../terminal/TerminalTransactionJournalReconciliationCard.tsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx b/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx index 6baacad3b..8c16ddf4c 100644 --- a/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx +++ b/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx @@ -16,7 +16,7 @@ interface TerminalTransactionJournalReconciliationCardProps { reconciliation: TerminalJournalReconciliationSnapshot; } -function factRows(facts: TerminalJournalReconciliationFact[]) { +function factRows(facts: readonly TerminalJournalReconciliationFact[] = []) { return facts.map((fact) => ({ label: fact.label, value: `${fact.value} · ${fact.state}${fact.blocksContradictoryProjection ? ' · blocks contradictory projection' : ''}`, @@ -30,7 +30,7 @@ function FactSection({ }: { title: string; summary: string; - facts: TerminalJournalReconciliationFact[]; + facts?: readonly TerminalJournalReconciliationFact[]; }) { return (
From 6987c6ba297c847d43baf5a4157f7115280a1a72 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 19:03:32 -0300 Subject: [PATCH 07/15] V30 Gate 6: Clean source-to-shares proof accounting Add package-owned SourceToSharesProof primitives for contribution weights, BTD range slices, BTC fee allocation, settlement conservation, zero-cell/refit tail posture, ancestry evidence, and no-overpayment/no-underpayment theorem verdicts. Expose the proof through the BTD API boundary and Next route, add focused BTD/API tests, document the Gate 6 protocol contract, and wire check:v30-gate6 into gate quality. Proof: pnpm --filter @bitcode/btd typecheck; pnpm --filter @bitcode/api build; pnpm --filter @bitcode/btd test; pnpm --filter @bitcode/api exec jest --config jest.config.cjs --runTestsByPath src/routes/__tests__/btd-crypto.test.ts --runInBand; pnpm --dir uapi exec tsc --noEmit --pretty false; pnpm run check:v30-gate6; git diff --check. --- .github/workflows/bitcode-gate-quality.yml | 1 + BITCODE_SPEC_V30.md | 27 +- BITCODE_SPEC_V30_DELTA.md | 23 + BITCODE_SPEC_V30_NOTES.md | 24 + BITCODE_SPEC_V30_PARITY_MATRIX.md | 19 +- package.json | 1 + .../src/routes/__tests__/btd-crypto.test.ts | 110 ++ packages/api/src/routes/btd-crypto.ts | 38 + packages/btd/README.md | 6 + .../btd/__tests__/source-to-shares.test.ts | 226 +++++ packages/btd/src/api-boundaries.ts | 64 ++ packages/btd/src/index.ts | 1 + packages/btd/src/source-to-shares.ts | 944 ++++++++++++++++++ ...0-gate6-source-to-shares-proof-cleanup.mjs | 228 +++++ .../api/btd/source-to-shares-proof/route.ts | 3 + uapi/app/terminal/README.md | 8 + 16 files changed, 1719 insertions(+), 4 deletions(-) create mode 100644 packages/btd/__tests__/source-to-shares.test.ts create mode 100644 packages/btd/src/source-to-shares.ts create mode 100644 scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs create mode 100644 uapi/app/api/btd/source-to-shares-proof/route.ts diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 8d8b3aeef..2f0052e12 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -84,6 +84,7 @@ jobs: node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs --skip-branch-check node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs --skip-branch-check node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs --skip-branch-check + node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index 6bf137d1c..a71d90388 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -218,6 +218,27 @@ Gate 4 receipt precision: root, read right, and ledger projection root. - Rights-transfer receipts require confirmed BTC fee finality before the BTD right/license transfer can admit protected source visibility to the Reader. + +Gate 6 source-to-shares precision: + +- `SourceToSharesProof` is package-owned in `@bitcode/btd` and is the reusable + accounting boundary for later Exchange work. +- Proof inputs bind accepted Need root, Finding Fits result root, admitted fit + deposits, per-deposit measurement roots, normalized measurement units, + fit/provenance quality basis points, BTD range projection, accepted BTC fee + quote, payment observation, and optional ancestry review. +- Contribution weights are deterministic largest-remainder basis points over + measured fit-deposit weights. The trace records total clipped weight, + remainder order, tie-break policy, and provisional/final shares. +- BTD range slices and BTC fee allocations are both derived from the same + contribution weights. Range slices may be zero-cell/refit-tail slices when the + measuremint tail or small range leaves a contributor with no cell. +- Settlement conservation carries distinct no-overpayment and no-underpayment + theorem verdicts, exact allocation conservation, blocker reasons, a + conservation root, and a reconciliation-compatible check. +- A source-to-shares proof may represent balanced, overpayment, underpayment, or + drifted state, but only balanced state is settlement-admissible for protected + source unlock and delivery. Prepared, signed, broadcast, replaced, reorged, and failed fee receipts do not unlock protected source. @@ -688,9 +709,9 @@ Terminal renders those roots with blockers and decision rows so operators can un - current member verdict shape: prepared, signed, broadcast, confirmed, blocked, reconciled. - current theorem-by-theorem closure reading: no paid source unlock without fee and right-transfer readback. - current theorem-to-replay grouping: quote root, payment path, ledger observation, BTD state, reconciliation. -- minimum artifact/replay binding set: fee quote root, txid or blocked receipt, range id, license id, journal id. -- current proof-object fields: quote, payment, range, license, reconciliation, blocker. -- generated-artifact and test bindings: BTD tests, settlement route tests, staging readback. +- minimum artifact/replay binding set: fee quote root, payment receipt root, txid or blocked receipt, BTD range slice roots, contribution weights, conservation root, license id, journal id. +- current proof-object fields: quote, payment observation, fit deposits, contribution weights, range slices, settlement allocations, no-overpayment, no-underpayment, zero-cell/refit tail, ancestry evidence, reconciliation check, blocker. +- generated-artifact and test bindings: BTD source-to-shares tests, settlement route tests, staging readback. - fail-closed conditions: settlement conservation drift, stale quote, or chain reorg. ### Disclosure-boundary diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 4fe2ea3dd..9e07c0ed8 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -221,6 +221,29 @@ Closure acceptance: - no-overpayment and no-underpayment invariants are testable; - later Exchange work can reuse the proof without reinterpreting V30 accounting. +Gate 6 implementation centers on `packages/btd/src/source-to-shares.ts`. +`SourceToSharesProof` is package-owned and binds accepted Need roots, Finding +Fits result roots, admitted fit deposits, per-deposit measurement roots, +normalized measurement units, fit/provenance basis points, deterministic +largest-remainder contribution weights, BTD range slices, accepted BTC fee +quote, payment observation, exact source credit allocation, settlement +conservation, zero-cell/refit tail posture, and ancestry review evidence when +available. + +The proof separates conservation from settlement admission. It can represent a +balanced, overpayment, underpayment, or drifted settlement without losing the +proof roots needed for repair. `noOverpayment` and `noUnderpayment` are separate +theorem verdicts, while `allocationConserved` proves that source credit +allocation sums to the accepted BTC fee quote. Only a balanced proof is +settlement-admissible. The proof exposes a reconciliation-compatible +`SettlementConservationCheck` so ledger/database repair can consume the same +accounting without route-local reinterpretation. + +Gate 6 evidence is covered by `packages/btd/__tests__/source-to-shares.test.ts`, +`packages/api/src/routes/__tests__/btd-crypto.test.ts`, +`uapi/app/api/btd/source-to-shares-proof/route.ts`, and +`scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs`. + ### Gate 7: Bridge Readiness Research Boundaries Gate 7 records bridge-readiness without false chain-of-record claims. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index 97dcb7bb6..c39eedce1 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -167,6 +167,30 @@ persists schema-compatible repair receipts; richer drift classes, repair actions, readback receipts, and proof roots remain in the report payload until a future schema expansion admits more columns. +## Gate 6 source-to-shares cleanup notes + +Gate 6 moves settlement-source-to-shares accounting into the BTD package instead +of relying on older protocol-local artifact builders. The package primitive +normalizes accepted fit deposits into contribution weights through a deterministic +largest-remainder method, allocates BTD range slices with zero-cell/refit-tail +posture when a fit receives no cell, allocates BTC fee credits exactly by the +same contribution weights, and emits one proof root that binds the fee quote, +payment observation, measurements, fit deposits, range slices, allocation roots, +settlement conservation, and ancestry evidence. + +The proof intentionally keeps no-overpayment and no-underpayment as distinct +theorem verdicts. This lets a repair cockpit distinguish a Reader overpayment +from an inadmissible underpayment instead of collapsing both into generic +conservation drift. The same proof emits a reconciliation-compatible settlement +conservation check so Gate 5 ledger/database repair can pause unlock or delivery +from the source-to-shares proof directly. + +The source-to-shares API route does not write a new registry table in Gate 6. +It returns a JSON-safe proof settlement and a Terminal journal entry. Later +Exchange work may persist richer proof rows after schema admission, but it must +reuse the package proof rather than recomputing contribution weights, range +slices, or BTC fee allocations. + 4. **Gate 4: BTD AssetPack Mint And Read Receipts** - Make BTD mint, read, and rights-transfer receipts typed, proof-rooted, stored, streamed, and source-safe. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index 8abfc3495..317767e61 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -59,7 +59,7 @@ No `_legacy/` source is active source truth. | Bitcoin Taproot PSBT fee rigor | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, `packages/btd/src/bitcoin-fees.ts`, BTD/API tests, gate checker | drafted | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, Taproot/PSBT aware, and proof-rooted. | | BTD AssetPack mint/read receipts | Gate 4 | `packages/btd/src/receipts.ts`, `packages/btd/src/api-boundaries.ts`, asset-pack harness evidence, Terminal detail snapshot/read model tests, gate checker | drafted | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | | Testnet ledger projection hardening | Gate 5 | `packages/btd/src/reconciliation.ts`, API route tests, asset-pack harness evidence, Terminal journal reconciliation UI/tests, gate checker | drafted | Ledger/database/object-storage/private facts are distinct; staging-testnet readback is secret-free; drift, quarantine, retry, and unlock blocking are tested. | -| Source-to-shares proof cleanup | Gate 6 | BTD/source-to-shares proof primitives, settlement conservation tests | pending | Measurement contribution, fee allocation, zero-cell/refit tail, and conservation invariants are testable. | +| Source-to-shares proof cleanup | Gate 6 | `packages/btd/src/source-to-shares.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Measurement contribution, fee allocation, zero-cell/refit tail, ancestry evidence, and conservation invariants are testable. | | Bridge-readiness research boundaries | Gate 7 | Protocol/BTD research notes, policy posture tests, docs | pending | Bridge paths are documented as research until admitted by explicit future proof and policy. | | Protocol telemetry/proof hooks | Gate 8 | telemetry schema, proof hooks, generated-artifact inventory, tests | pending | Receipts, fee states, projections, and source-to-shares facts emit source-safe telemetry and proof hooks. | | Interface integration regression | Gate 9 | Terminal/API/MCP/ChatGPT App adapters and tests | pending | Existing interfaces consume package-owned objects without regressing V29 behavior. | @@ -175,6 +175,23 @@ No `_legacy/` source is active source truth. - Gate 5 does not implement source-to-shares contribution accounting; Gate 6 owns that. - Gate 5 does not promote V30 or change the active canon pointer. +## Gate 6 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| Source-to-shares proof is package-owned | `packages/btd/src/source-to-shares.ts`, `packages/btd/src/api-boundaries.ts` | drafted | +| Contribution weights, range slices, BTC fee allocation, and conservation are deterministic | `packages/btd/__tests__/source-to-shares.test.ts` | drafted | +| API and Next route consume the package proof without route-local accounting | `packages/api/src/routes/btd-crypto.ts`, `uapi/app/api/btd/source-to-shares-proof/route.ts`, `packages/api/src/routes/__tests__/btd-crypto.test.ts` | drafted | +| Gate checker protects source-to-shares cleanup | `scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs`, `pnpm run check:v30-gate6`, gate-quality workflow | drafted | + +## Gate 6 accepted boundaries + +- Gate 6 does not create a new physical source-to-shares registry table; the API route returns proof payloads and Terminal journal entries until schema admission. +- Gate 6 does not expose protected source before paid unlock and delivery admission. +- Gate 6 does not alter `$BTD` supply law or measureminting curve. +- Gate 6 does not admit bridge chain-of-record semantics; Gate 7 owns bridge-readiness boundaries. +- Gate 6 does not promote V30 or change the active canon pointer. + ## completion condition Gate 1 is complete when the V30 draft family validates, `check:v30-gate1` passes, workflow posture is V30-aware, README and roadmap reflect V30 initiation, V31-V37 scopes are current enough to guide future gates, diff hygiene passes, and the gate branch is committed and pushed for review into `version/v30`. diff --git a/package.json b/package.json index ddb94026e..2a3e25ace 100644 --- a/package.json +++ b/package.json @@ -59,6 +59,7 @@ "check:v30-gate3": "node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs", "check:v30-gate4": "node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs", "check:v30-gate5": "node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs", + "check:v30-gate6": "node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/api/src/routes/__tests__/btd-crypto.test.ts b/packages/api/src/routes/__tests__/btd-crypto.test.ts index 986c291cf..c0abac55f 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -25,6 +25,7 @@ import { buildBtdMintDraft, buildBtdOrganizationInterfaceAuthorityDecision, buildBtdReadAccessDecision, + buildBtdSourceToSharesProofSettlement, buildBtdTerminalJournalSettlement, buildBtcFeeQuote, createBtdMeasureMintState, @@ -41,6 +42,7 @@ import { buildPostBtdMintDraftRoute, buildPostBtdOrganizationInterfaceAuthorityRoute, buildPostBtdReadAccessRoute, + buildPostBtdSourceToSharesProofRoute, buildPostBtdTerminalJournalRoute, } from '../btd-crypto'; @@ -147,6 +149,63 @@ function mintDraftRequestBody(overrides: Record = {}) { }; } +function sourceToSharesProofBody(overrides: Record = {}) { + return { + readId: 'read-api-source-to-shares-1', + assetPackId: 'asset-pack-api-source-to-shares-1', + acceptedNeedRoot: 'accepted-need-api-root', + findingFitsResultRoot: 'finding-fits-api-root', + fitDeposits: [ + { + depositId: 'deposit-api-a', + assetPackId: 'fit-asset-api-a', + depositorWalletId: 'wallet-depositor-api-a', + sourceManifestRoot: 'source-api-root-a', + findingFitsResultRoot: 'finding-fits-api-root-a', + measurementRoot: 'measurement-api-root-a', + normalizedMeasurementUnits: '20000', + fitQualityBps: 10000, + provenanceBps: 10000, + accepted: true, + }, + { + depositId: 'deposit-api-b', + assetPackId: 'fit-asset-api-b', + depositorWalletId: 'wallet-depositor-api-b', + sourceManifestRoot: 'source-api-root-b', + findingFitsResultRoot: 'finding-fits-api-root-b', + measurementRoot: 'measurement-api-root-b', + normalizedMeasurementUnits: '10000', + fitQualityBps: 10000, + provenanceBps: 10000, + accepted: true, + }, + ], + btdRange: { + assetPackId: 'asset-pack-api-source-to-shares-1', + rangeStart: 40, + rangeEndExclusive: 43, + tokenCount: 3, + measureMintReceiptRoot: 'measuremint-api-root', + }, + feeQuote: { + quoteId: 'quote-api-source-to-shares-1', + quoteRoot: 'quote-api-source-root', + grossSats: '9000', + }, + paymentObservation: { + paymentReceiptRoot: 'payment-api-source-root', + observedDebitSats: '9000', + observedCreditSats: '9000', + finalityState: 'confirmed', + txid: 'txid-api-source-to-shares', + }, + exchangeSequence: '18', + issuedAt, + ...overrides, + }; +} + describe('BTD crypto API builders', () => { it('builds a deterministic mint draft from accepted Read-Fit semantic units', () => { const draft = buildBtdMintDraft(mintDraftInput()); @@ -879,6 +938,35 @@ describe('BTD crypto API builders', () => { ); }); + it('builds source-to-shares proof settlements with exact conservation roots', () => { + const settlement = buildBtdSourceToSharesProofSettlement({ + actorId: 'user-1', + ...sourceToSharesProofBody(), + exchangeSequence: 18n, + } as any); + + expect(settlement.kind).toBe('btd_source_to_shares_proof_settlement'); + expect(settlement.proof.contributionWeights.map((entry) => entry.shareBps)).toEqual([ + 6667, + 3333, + ]); + expect(settlement.proof.settlementConservation).toMatchObject({ + state: 'balanced', + settlementAdmissible: true, + allocationConserved: true, + }); + expect( + settlement.proof.settlementAllocations.reduce( + (sum, route) => sum + route.allocatedSats, + 0n, + ), + ).toBe(9000n); + expect(settlement.terminalJournalEntry.transactionKind).toBe('settlement_finalization'); + expect(settlement.terminalJournalEntry.receiptRoots).toContain( + settlement.proof.settlementConservation.conservationRoot, + ); + }); + it('builds deployment readiness, telemetry, and upgrade settlements', () => { const readiness = buildBtdDeploymentReadinessSettlement({ actorId: 'user-1', @@ -1425,6 +1513,28 @@ describe('BTD crypto API builders', () => { ); }); + it('returns JSON-safe source-to-shares proofs from the route boundary', async () => { + const route = buildPostBtdSourceToSharesProofRoute({ + resolveAuthenticatedUser: async () => ({ userId: 'user-1' }), + }); + const response = await route( + new Request('https://bitcode.test/api/btd/source-to-shares-proof', { + method: 'POST', + body: JSON.stringify(sourceToSharesProofBody()), + }), + ); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body.kind).toBe('btd_source_to_shares_proof_settlement'); + expect(body.committed).toBe(false); + expect(body.proof.feeQuote.priceAsset).toBe('BTC'); + expect(body.proof.feeQuote.grossSats).toBe('9000'); + expect(body.proof.settlementConservation.noOverpayment.passed).toBe(true); + expect(body.proof.settlementConservation.noUnderpayment.passed).toBe(true); + expect(body.terminalJournalEntry.exchangeSequence).toBe('18'); + }); + it('returns JSON-safe deployment readiness settlements and persists telemetry or upgrades', async () => { const insertCryptoTelemetryEvent = jest.fn(async (row) => ({ event: row.event, diff --git a/packages/api/src/routes/btd-crypto.ts b/packages/api/src/routes/btd-crypto.ts index 512f6ae99..dd5be39f9 100644 --- a/packages/api/src/routes/btd-crypto.ts +++ b/packages/api/src/routes/btd-crypto.ts @@ -28,6 +28,8 @@ import { type BtdReadAccessDecision, type BtdReadLicense, type BtdOwnershipClaim, + type BtdSourceToSharesProofInput, + type BtdSourceToSharesProofSettlement, type BtdTerminalJournalInput, type BtdTerminalJournalSettlement, type TerminalJournalEntry, @@ -46,6 +48,7 @@ import { buildBtdOrganizationInterfaceAuthorityDecision, buildBtdReadAccessDecision, buildBtdRegistrySnapshot, + buildBtdSourceToSharesProofSettlement, buildBtdStableId as stableId, buildBtdTerminalJournalSettlement, buildLicensedReadRevenueRoute, @@ -67,6 +70,7 @@ export { buildBtdOrganizationInterfaceAuthorityDecision, buildBtdReadAccessDecision, buildBtdRegistrySnapshot, + buildBtdSourceToSharesProofSettlement, buildBtdTerminalJournalSettlement, }; @@ -564,6 +568,39 @@ export function buildPostBtdLedgerDatabaseReconciliationRoute(options: BtdRouteO }); } +export function buildPostBtdSourceToSharesProofRoute(options: BtdRouteOptions = {}) { + return traceRoute('/btd/source-to-shares-proof', async (request: Request) => { + const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( + request, + ); + if (!user) { + return createJsonResponse({ error: 'Unauthorized' }, 401); + } + + let body: Omit & { + exchangeSequence: string | number; + }; + try { + body = await request.json(); + } catch { + return createJsonResponse({ error: 'Invalid JSON body' }, 400); + } + + let settlement: BtdSourceToSharesProofSettlement; + try { + settlement = buildBtdSourceToSharesProofSettlement({ + ...body, + actorId: user.userId, + exchangeSequence: parseBtdRequiredBigInt(body.exchangeSequence, 'exchangeSequence'), + }); + } catch (error) { + return createJsonResponse({ error: toBadRequestMessage(error) }, 400); + } + + return createJsonResponse(toJsonSafe(settlement)); + }); +} + export function buildPostBtdDeploymentReadinessRoute(options: BtdRouteOptions = {}) { return traceRoute('/btd/deployment-readiness', async (request: Request) => { const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( @@ -623,6 +660,7 @@ export const postBtdAssetPackExchange = buildPostBtdAssetPackExchangeRoute(); export const postBtdTerminalJournal = buildPostBtdTerminalJournalRoute(); export const postBtdLedgerDatabaseReconciliation = buildPostBtdLedgerDatabaseReconciliationRoute(); +export const postBtdSourceToSharesProof = buildPostBtdSourceToSharesProofRoute(); export const postBtdDeploymentReadiness = buildPostBtdDeploymentReadinessRoute(); function toBadRequestMessage(error: unknown): string { diff --git a/packages/btd/README.md b/packages/btd/README.md index 0d46393ec..169192136 100644 --- a/packages/btd/README.md +++ b/packages/btd/README.md @@ -15,6 +15,10 @@ This package owns: Reader and Depositor identities, source-safe preview roots, paid unlock, delivery admission, and ledger projection roots without leaking protected source before settlement +- source-to-shares proof cleanup: contribution measurement, deterministic + largest-remainder share weights, BTD range slices, exact BTC fee allocation, + settlement conservation, zero-cell/refit tail posture, ancestry evidence, and + no-overpayment/no-underpayment theorem verdicts - ledger/database/object-storage projection reconciliation, including deterministic repair classes, source-safe object artifact roots, secret-free Supabase staging-testnet readback receipts, quarantine/retry @@ -49,7 +53,9 @@ import { buildBtdRightsTransferReceipt, buildBtdRegistrySnapshot, buildSupabaseStagingTestnetProjectionReadback, + buildSourceToSharesProof, reconcileLedgerDatabaseProjection, + sourceToSharesProofToSettlementConservationCheck, toBtdJsonSafe, calculateLlmBtcFeeEstimate, buildLicensedReadRevenueRoute, diff --git a/packages/btd/__tests__/source-to-shares.test.ts b/packages/btd/__tests__/source-to-shares.test.ts new file mode 100644 index 000000000..9e06ff4e3 --- /dev/null +++ b/packages/btd/__tests__/source-to-shares.test.ts @@ -0,0 +1,226 @@ +import { + assertSourceToSharesSettlementAdmissible, + buildSourceToSharesProof, + reviewBtdAncestorEdges, + sourceToSharesProofToSettlementConservationCheck, +} from '../src'; + +const issuedAt = '2026-05-06T00:00:00.000Z'; + +function baseProofInput(overrides: Record = {}) { + return { + readId: 'read-source-to-shares-1', + assetPackId: 'asset-pack-source-to-shares-1', + acceptedNeedRoot: 'accepted-need-root-1', + findingFitsResultRoot: 'finding-fits-root-1', + fitDeposits: [ + { + depositId: 'deposit-a', + assetPackId: 'fit-asset-a', + depositorWalletId: 'wallet-depositor-a', + sourceManifestRoot: 'source-root-a', + findingFitsResultRoot: 'finding-fits-root-a', + measurementRoot: 'measurement-root-a', + normalizedMeasurementUnits: 30_000n, + fitQualityBps: 10_000, + provenanceBps: 10_000, + accepted: true as const, + }, + { + depositId: 'deposit-b', + assetPackId: 'fit-asset-b', + depositorWalletId: 'wallet-depositor-b', + sourceManifestRoot: 'source-root-b', + findingFitsResultRoot: 'finding-fits-root-b', + measurementRoot: 'measurement-root-b', + normalizedMeasurementUnits: 10_000n, + fitQualityBps: 10_000, + provenanceBps: 10_000, + accepted: true as const, + }, + ], + btdRange: { + assetPackId: 'asset-pack-source-to-shares-1', + rangeStart: 100, + rangeEndExclusive: 103, + tokenCount: 3, + rangeRoot: 'range-root-1', + measureMintReceiptRoot: 'measuremint-root-1', + }, + feeQuote: { + quoteId: 'quote-source-to-shares-1', + quoteRoot: 'quote-root-1', + grossSats: 10_001n, + }, + paymentObservation: { + paymentReceiptRoot: 'payment-root-1', + observedDebitSats: 10_001n, + observedCreditSats: 10_001n, + finalityState: 'confirmed' as const, + txid: 'txid-source-to-shares-1', + }, + issuedAt, + ...overrides, + }; +} + +describe('source-to-shares proof cleanup', () => { + it('binds measurements, fit deposits, BTD range slices, fee quote, and exact BTC allocation', () => { + const proof = buildSourceToSharesProof(baseProofInput()); + + expect(proof.kind).toBe('btd.source_to_shares_proof'); + expect(proof.contributionWeights.map((entry) => [entry.depositId, entry.shareBps])).toEqual([ + ['deposit-a', 7500], + ['deposit-b', 2500], + ]); + expect(proof.rangeSlices.map((entry) => [entry.depositId, entry.tokenCount])).toEqual([ + ['deposit-a', 2], + ['deposit-b', 1], + ]); + expect(proof.settlementAllocations.map((entry) => [entry.depositId, entry.allocatedSats])).toEqual([ + ['deposit-a', 7501n], + ['deposit-b', 2500n], + ]); + expect(proof.settlementConservation).toMatchObject({ + state: 'balanced', + settlementAdmissible: true, + allocationConserved: true, + blockerReasons: [], + }); + expect(proof.settlementConservation.noOverpayment.passed).toBe(true); + expect(proof.settlementConservation.noUnderpayment.passed).toBe(true); + expect(proof.zeroCellRefitTail).toMatchObject({ + state: 'no_zero_cell_tail', + refitRequired: false, + rangeTokenCount: 3, + }); + expect(proof.proofRoot).toMatch(/^btd-proof-root:source-to-shares:/); + + const check = sourceToSharesProofToSettlementConservationCheck(proof); + expect(check).toMatchObject({ + checkId: proof.proofId, + expectedDebitSats: 10001, + observedDebitSats: 10001, + expectedCreditSats: 10001, + observedCreditSats: 10001, + feeQuoteRoot: 'quote-root-1', + paymentReceiptRoot: 'payment-root-1', + }); + }); + + it('keeps no-underpayment and no-overpayment invariants independently testable', () => { + const underpaid = buildSourceToSharesProof( + baseProofInput({ + paymentObservation: { + paymentReceiptRoot: 'payment-root-underpaid', + observedDebitSats: 9_999n, + observedCreditSats: 9_999n, + finalityState: 'confirmed', + }, + }), + ); + const overpaid = buildSourceToSharesProof( + baseProofInput({ + paymentObservation: { + paymentReceiptRoot: 'payment-root-overpaid', + observedDebitSats: 10_002n, + observedCreditSats: 10_002n, + finalityState: 'confirmed', + }, + }), + ); + + expect(underpaid.settlementConservation.state).toBe('underpayment'); + expect(underpaid.settlementConservation.noOverpayment.passed).toBe(true); + expect(underpaid.settlementConservation.noUnderpayment.passed).toBe(false); + expect(() => assertSourceToSharesSettlementAdmissible(underpaid)).toThrow( + /not admissible/, + ); + + expect(overpaid.settlementConservation.state).toBe('overpayment'); + expect(overpaid.settlementConservation.noOverpayment.passed).toBe(false); + expect(overpaid.settlementConservation.noUnderpayment.passed).toBe(true); + expect(() => assertSourceToSharesSettlementAdmissible(overpaid)).toThrow( + /not admissible/, + ); + }); + + it('records zero-cell refit tail posture and ancestry evidence without changing settlement supply', () => { + const ancestryReview = reviewBtdAncestorEdges({ + reviewId: 'ancestry-review-source-to-shares-1', + childAssetPackId: 'asset-pack-source-to-shares-1', + edges: [ + { + parentAssetPackId: 'asset-pack-parent-1', + childAssetPackId: 'asset-pack-source-to-shares-1', + edgeKind: 'proof_dependency', + evidenceRoot: 'ancestry-evidence-root-1', + confidenceBps: 9_000, + timelessnessBps: 8_000, + depth: 1, + createdAfterChildFit: true, + conflictDisclosure: [], + }, + ], + issuedAt, + }); + const proof = buildSourceToSharesProof( + baseProofInput({ + btdRange: { + assetPackId: 'asset-pack-source-to-shares-1', + tokenCount: 0, + measureMintReceiptRoot: 'measuremint-zero-cell-root-1', + zeroCellReason: 'tail_exhausted', + }, + ancestryReview, + }), + ); + + expect(proof.zeroCellRefitTail).toMatchObject({ + state: 'zero_cell_refit_tail', + tailPolicy: 'zero_cell_receipt_then_refit_only', + zeroCellReason: 'tail_exhausted', + refitRequired: true, + zeroCellDepositIds: ['deposit-a', 'deposit-b'], + }); + expect(proof.rangeSlices.every((slice) => slice.tokenCount === 0)).toBe(true); + expect(proof.ancestryEvidence).toMatchObject({ + state: 'reviewed', + reviewId: 'ancestry-review-source-to-shares-1', + payableEdgeCount: 1, + recordedUnpaidEdgeCount: 0, + rejectedEdgeCount: 0, + }); + expect(proof.ancestryEvidence.payableRouteWeight).toBe('18000000'); + expect(proof.settlementConservation.settlementAdmissible).toBe(true); + }); + + it('fails closed on duplicate or unaccepted fit deposits', () => { + expect(() => + buildSourceToSharesProof( + baseProofInput({ + fitDeposits: [ + baseProofInput().fitDeposits[0], + { + ...baseProofInput().fitDeposits[0], + assetPackId: 'duplicate-fit-asset', + }, + ], + }), + ), + ).toThrow(/Duplicate source-to-shares fit deposit/); + + expect(() => + buildSourceToSharesProof( + baseProofInput({ + fitDeposits: [ + { + ...baseProofInput().fitDeposits[0], + accepted: false, + }, + ], + }), + ), + ).toThrow(/only accepts admitted fit deposits/); + }); +}); diff --git a/packages/btd/src/api-boundaries.ts b/packages/btd/src/api-boundaries.ts index 893789cb6..940a120a7 100644 --- a/packages/btd/src/api-boundaries.ts +++ b/packages/btd/src/api-boundaries.ts @@ -104,6 +104,8 @@ import { } from './revenue'; import type { SemanticVolumeUnitInput } from './semantic-volume'; import { measureProofAddressableSemanticVolume } from './semantic-volume'; +import type { SourceToSharesProofInput } from './source-to-shares'; +import { buildSourceToSharesProof } from './source-to-shares'; import { createBtdSupplyState } from './supply'; import type { V27CryptoTelemetryEvent, @@ -428,6 +430,12 @@ export interface BtdLedgerDatabaseReconciliationInput { issuedAt?: string; } +export interface BtdSourceToSharesProofInput extends SourceToSharesProofInput { + exchangeSequence: bigint; + actorId?: string; + commitToRegistry?: boolean; +} + export type BtdDeploymentReadinessAction = | 'deployment_lane' | 'telemetry_event' @@ -533,6 +541,14 @@ export interface BtdLedgerDatabaseReconciliationSettlement { committed: boolean; } +export interface BtdSourceToSharesProofSettlement { + kind: 'btd_source_to_shares_proof_settlement'; + actorId: string; + proof: ReturnType; + terminalJournalEntry: ReturnType; + committed: false; +} + export interface BtdDeploymentReadinessSettlement { kind: 'btd_deployment_readiness_settlement'; actorId: string; @@ -1230,6 +1246,54 @@ export function buildBtdLedgerDatabaseReconciliationSettlement( }; } +export function buildBtdSourceToSharesProofSettlement( + input: BtdSourceToSharesProofInput & { actorId: string }, +): BtdSourceToSharesProofSettlement { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { + throw new Error('Source-to-shares proof settlement requires a positive Exchange sequence.'); + } + + const proof = buildSourceToSharesProof(input); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-source-to-shares-proof', [ + proof.proofId, + input.exchangeSequence.toString(), + ]), + transactionKind: 'settlement_finalization', + actorId, + preStateRoot: buildBtdStableId('source-to-shares-pre-state', [ + proof.readId, + proof.acceptedNeedRoot, + ]), + postStateRoot: buildBtdStableId('source-to-shares-post-state', [ + proof.proofRoot, + proof.settlementConservation.state, + String(proof.settlementConservation.settlementAdmissible), + ]), + receiptRoots: [ + proof.proofRoot, + proof.feeQuote.quoteRoot, + proof.paymentObservation.paymentReceiptRoot, + proof.settlementConservation.conservationRoot, + proof.zeroCellRefitTail.tailRoot, + proof.ancestryEvidence.reviewRoot, + ...proof.settlementAllocations.map((allocation) => allocation.allocationRoot), + ], + ledgerAnchorIds: proof.paymentObservation.txid ? [proof.paymentObservation.txid] : [], + exchangeSequence: input.exchangeSequence, + issuedAt: proof.issuedAt, + }); + + return { + kind: 'btd_source_to_shares_proof_settlement', + actorId, + proof, + terminalJournalEntry, + committed: false, + }; +} + export function buildBtdDeploymentReadinessSettlement( input: BtdDeploymentReadinessInput & { actorId: string }, ): Omit { diff --git a/packages/btd/src/index.ts b/packages/btd/src/index.ts index dcdeeacc7..4c68707ec 100644 --- a/packages/btd/src/index.ts +++ b/packages/btd/src/index.ts @@ -175,6 +175,7 @@ export * from './replay'; export * from './revenue'; export * from './semantic-volume'; export * from './settlement'; +export * from './source-to-shares'; export * from './supply'; export * from './telemetry'; export * from './terminal-journal'; diff --git a/packages/btd/src/source-to-shares.ts b/packages/btd/src/source-to-shares.ts new file mode 100644 index 000000000..124dc92f0 --- /dev/null +++ b/packages/btd/src/source-to-shares.ts @@ -0,0 +1,944 @@ +import { createHash } from 'crypto'; +import type { BtdAncestryReviewReceipt } from './ancestry'; +import { + BITCODE_FEE_ASSET, + type BtdTokenId, + assertNonEmptyString, + assertNonNegativeSafeInteger, + toBigIntAmount, +} from './constants'; +import type { BtdZeroCellReason } from './measuremint'; +import type { SettlementConservationCheck } from './reconciliation'; + +const MAX_BPS = 10_000; +const MAX_BPS_BIGINT = 10_000n; + +export type SourceToSharesContributionDisposition = + | 'positive_marginal_contribution' + | 'clipped_zero_contribution'; + +export type SourceToSharesSettlementConservationState = + | 'balanced' + | 'overpayment' + | 'underpayment' + | 'drifted'; + +export type SourceToSharesRangeSliceState = 'allocated' | 'zero_cell_refit_tail'; + +export interface SourceToSharesFitDepositInput { + depositId: string; + assetPackId: string; + depositorWalletId: string; + sourceManifestRoot: string; + findingFitsResultRoot: string; + measurementRoot: string; + normalizedMeasurementUnits: bigint | number | string; + fitQualityBps: number; + provenanceBps?: number; + accepted: true; +} + +export interface SourceToSharesBtdRangeInput { + assetPackId: string; + rangeStart?: BtdTokenId; + rangeEndExclusive?: BtdTokenId; + tokenCount?: number; + rangeRoot?: string; + measureMintReceiptRoot?: string; + zeroCellReason?: BtdZeroCellReason; +} + +export interface SourceToSharesFeeQuoteInput { + quoteId: string; + quoteRoot: string; + grossSats: bigint | number | string; + priceAsset?: typeof BITCODE_FEE_ASSET; +} + +export interface SourceToSharesPaymentObservationInput { + paymentReceiptRoot: string; + observedDebitSats: bigint | number | string; + observedCreditSats?: bigint | number | string; + finalityState?: 'prepared' | 'signed' | 'broadcast' | 'confirmed' | 'replaced' | 'reorged' | 'failed'; + txid?: string; +} + +export interface SourceToSharesProofInput { + proofId?: string; + readId: string; + assetPackId: string; + acceptedNeedRoot: string; + findingFitsResultRoot: string; + fitDeposits: SourceToSharesFitDepositInput[]; + btdRange: SourceToSharesBtdRangeInput; + feeQuote: SourceToSharesFeeQuoteInput; + paymentObservation: SourceToSharesPaymentObservationInput; + ancestryReview?: BtdAncestryReviewReceipt | null; + issuedAt?: string; +} + +export interface SourceToSharesBoundFitDeposit { + depositId: string; + assetPackId: string; + depositorWalletId: string; + sourceManifestRoot: string; + findingFitsResultRoot: string; + measurementRoot: string; + normalizedMeasurementUnits: bigint; + fitQualityBps: number; + provenanceBps: number; + accepted: true; +} + +export interface SourceToSharesContributionWeight { + depositId: string; + assetPackId: string; + depositorWalletId: string; + measurementRoot: string; + sourceManifestRoot: string; + findingFitsResultRoot: string; + rawWeight: string; + clippedWeight: string; + shareBps: number; + normalizationRemainderUnits: string; + disposition: SourceToSharesContributionDisposition; + reasons: string[]; +} + +export interface SourceToSharesNormalizationTrace { + method: 'largest_remainder'; + totalClippedWeight: string; + normalizedTotalBps: number; + tieBreakPolicy: 'remainder_desc_weight_desc_deposit_id_asc'; + remainderDistributionOrder: string[]; + provisionalShares: Array<{ + depositId: string; + floorShareBps: number; + remainderUnits: string; + remainderAwardedBps: number; + finalShareBps: number; + tieBreakRank: number; + }>; +} + +export interface SourceToSharesRangeSlice { + depositId: string; + assetPackId: string; + depositorWalletId: string; + shareBps: number; + tokenCount: number; + rangeStart?: BtdTokenId; + rangeEndExclusive?: BtdTokenId; + sliceState: SourceToSharesRangeSliceState; + sliceRoot: string; +} + +export interface SourceToSharesSettlementAllocation { + depositId: string; + assetPackId: string; + depositorWalletId: string; + shareBps: number; + allocatedSats: bigint; + allocationRemainderUnits: string; + allocationRoot: string; +} + +export interface SourceToSharesInvariantVerdict { + theoremId: string; + passed: boolean; + expectedSats: bigint; + observedSats: bigint; + summary: string; +} + +export interface SourceToSharesSettlementConservation { + state: SourceToSharesSettlementConservationState; + expectedDebitSats: bigint; + observedDebitSats: bigint; + expectedCreditSats: bigint; + observedCreditSats: bigint; + allocatedCreditSats: bigint; + noOverpayment: SourceToSharesInvariantVerdict; + noUnderpayment: SourceToSharesInvariantVerdict; + allocationConserved: boolean; + settlementAdmissible: boolean; + blockerReasons: string[]; + conservationRoot: string; + reconciliationCheck: SettlementConservationCheck; +} + +export interface SourceToSharesZeroCellRefitTail { + tailPolicy: 'zero_cell_receipt_then_refit_only'; + state: 'no_zero_cell_tail' | 'zero_cell_refit_tail'; + rangeTokenCount: number; + zeroCellReason?: BtdZeroCellReason; + measureMintReceiptRoot?: string; + zeroCellDepositIds: string[]; + refitRequired: boolean; + tailRoot: string; +} + +export interface SourceToSharesAncestryEvidence { + state: 'not_provided' | 'reviewed'; + reviewId?: string; + reviewRoot: string; + payableEdgeCount: number; + recordedUnpaidEdgeCount: number; + rejectedEdgeCount: number; + payableRouteWeight: string; +} + +export interface SourceToSharesProof { + kind: 'btd.source_to_shares_proof'; + proofId: string; + readId: string; + assetPackId: string; + acceptedNeedRoot: string; + findingFitsResultRoot: string; + proofArtifactPath: '.bitcode/v30-settlement-source-to-shares-proof.json'; + sourceToSharesArtifactPath: '.bitcode/source-to-shares.json'; + feeQuote: { + quoteId: string; + quoteRoot: string; + priceAsset: typeof BITCODE_FEE_ASSET; + grossSats: bigint; + }; + paymentObservation: { + paymentReceiptRoot: string; + observedDebitSats: bigint; + observedCreditSats: bigint; + finalityState?: SourceToSharesPaymentObservationInput['finalityState']; + txid?: string; + }; + fitDeposits: SourceToSharesBoundFitDeposit[]; + contributionWeights: SourceToSharesContributionWeight[]; + normalizationTrace: SourceToSharesNormalizationTrace; + rangeSlices: SourceToSharesRangeSlice[]; + settlementAllocations: SourceToSharesSettlementAllocation[]; + settlementConservation: SourceToSharesSettlementConservation; + zeroCellRefitTail: SourceToSharesZeroCellRefitTail; + ancestryEvidence: SourceToSharesAncestryEvidence; + proofRoot: string; + issuedAt: string; +} + +export function buildSourceToSharesProof(input: SourceToSharesProofInput): SourceToSharesProof { + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const readId = assertNonEmptyString(input.readId, 'readId'); + const assetPackId = assertNonEmptyString(input.assetPackId, 'assetPackId'); + const fitDeposits = normalizeFitDeposits(input.fitDeposits); + const btdRange = normalizeBtdRange(input.btdRange, assetPackId); + const feeQuote = normalizeFeeQuote(input.feeQuote); + const paymentObservation = normalizePaymentObservation(input.paymentObservation); + const proofId = + input.proofId ?? + stableId('btd-source-to-shares-proof', [ + readId, + assetPackId, + input.findingFitsResultRoot, + feeQuote.quoteRoot, + paymentObservation.paymentReceiptRoot, + ]); + + if (!fitDeposits.length) { + throw new Error('Source-to-shares proof requires at least one fit deposit.'); + } + + const { contributionWeights, normalizationTrace } = buildContributionWeights(fitDeposits); + const rangeSlices = allocateRangeSlices({ + assetPackId, + fitDeposits, + contributionWeights, + rangeStart: btdRange.rangeStart, + tokenCount: btdRange.tokenCount, + }); + const settlementAllocations = allocateSettlementSats({ + fitDeposits, + contributionWeights, + grossSats: feeQuote.grossSats, + }); + const settlementConservation = buildSettlementConservation({ + proofId, + feeQuote, + paymentObservation, + settlementAllocations, + }); + const zeroCellRefitTail = buildZeroCellRefitTail({ + btdRange, + rangeSlices, + fitDeposits, + }); + const ancestryEvidence = buildAncestryEvidence(input.ancestryReview); + const proofRoot = stableProofRoot('source-to-shares', [ + proofId, + readId, + assetPackId, + input.acceptedNeedRoot, + input.findingFitsResultRoot, + feeQuote, + paymentObservation, + contributionWeights, + normalizationTrace, + rangeSlices, + settlementAllocations, + settlementConservation.conservationRoot, + zeroCellRefitTail.tailRoot, + ancestryEvidence.reviewRoot, + ]); + + return assertSourceToSharesProof({ + kind: 'btd.source_to_shares_proof', + proofId, + readId, + assetPackId, + acceptedNeedRoot: assertNonEmptyString(input.acceptedNeedRoot, 'acceptedNeedRoot'), + findingFitsResultRoot: assertNonEmptyString( + input.findingFitsResultRoot, + 'findingFitsResultRoot', + ), + proofArtifactPath: '.bitcode/v30-settlement-source-to-shares-proof.json', + sourceToSharesArtifactPath: '.bitcode/source-to-shares.json', + feeQuote, + paymentObservation, + fitDeposits, + contributionWeights, + normalizationTrace, + rangeSlices, + settlementAllocations, + settlementConservation, + zeroCellRefitTail, + ancestryEvidence, + proofRoot, + issuedAt, + }); +} + +export function assertSourceToSharesProof(proof: SourceToSharesProof): SourceToSharesProof { + if (proof.kind !== 'btd.source_to_shares_proof') { + throw new Error('Invalid source-to-shares proof kind.'); + } + + assertNonEmptyString(proof.proofId, 'proofId'); + assertNonEmptyString(proof.readId, 'readId'); + assertNonEmptyString(proof.assetPackId, 'assetPackId'); + assertNonEmptyString(proof.acceptedNeedRoot, 'acceptedNeedRoot'); + assertNonEmptyString(proof.findingFitsResultRoot, 'findingFitsResultRoot'); + assertNonEmptyString(proof.proofRoot, 'proofRoot'); + assertNonEmptyString(proof.issuedAt, 'issuedAt'); + normalizeFitDeposits(proof.fitDeposits); + + const shareTotal = proof.contributionWeights.reduce((sum, entry) => sum + entry.shareBps, 0); + if (shareTotal !== MAX_BPS || proof.normalizationTrace.normalizedTotalBps !== MAX_BPS) { + throw new Error('Source-to-shares contribution weights must sum to 10000 basis points.'); + } + + const allocatedRange = proof.rangeSlices.reduce((sum, slice) => sum + slice.tokenCount, 0); + if (allocatedRange !== proof.zeroCellRefitTail.rangeTokenCount) { + throw new Error('Source-to-shares range slices do not conserve the BTD range token count.'); + } + + const allocatedSats = proof.settlementAllocations.reduce( + (sum, allocation) => sum + allocation.allocatedSats, + 0n, + ); + if (allocatedSats !== proof.feeQuote.grossSats) { + throw new Error('Source-to-shares settlement allocations do not conserve gross sats.'); + } + + if (proof.settlementConservation.allocatedCreditSats !== allocatedSats) { + throw new Error('Source-to-shares conservation allocated credit does not match allocations.'); + } + + return proof; +} + +export function assertSourceToSharesSettlementAdmissible( + proof: SourceToSharesProof, +): SourceToSharesProof { + assertSourceToSharesProof(proof); + if (!proof.settlementConservation.settlementAdmissible) { + throw new Error( + `Source-to-shares settlement is not admissible: ${proof.settlementConservation.blockerReasons.join('; ')}`, + ); + } + return proof; +} + +export function sourceToSharesProofToSettlementConservationCheck( + proof: SourceToSharesProof, +): SettlementConservationCheck { + assertSourceToSharesProof(proof); + return proof.settlementConservation.reconciliationCheck; +} + +function normalizeFitDeposits( + deposits: readonly SourceToSharesFitDepositInput[], +): SourceToSharesBoundFitDeposit[] { + const seen = new Set(); + return deposits.map((deposit) => { + const depositId = assertNonEmptyString(deposit.depositId, 'depositId'); + if (seen.has(depositId)) { + throw new Error(`Duplicate source-to-shares fit deposit: ${depositId}.`); + } + seen.add(depositId); + + if (deposit.accepted !== true) { + throw new Error('Source-to-shares proof only accepts admitted fit deposits.'); + } + + const normalizedMeasurementUnits = toBigIntAmount( + deposit.normalizedMeasurementUnits, + 'normalizedMeasurementUnits', + ); + if (normalizedMeasurementUnits <= 0n) { + throw new Error('Source-to-shares fit deposit measurement units must be positive.'); + } + + return { + depositId, + assetPackId: assertNonEmptyString(deposit.assetPackId, 'deposit.assetPackId'), + depositorWalletId: assertNonEmptyString( + deposit.depositorWalletId, + 'depositorWalletId', + ), + sourceManifestRoot: assertNonEmptyString( + deposit.sourceManifestRoot, + 'sourceManifestRoot', + ), + findingFitsResultRoot: assertNonEmptyString( + deposit.findingFitsResultRoot, + 'deposit.findingFitsResultRoot', + ), + measurementRoot: assertNonEmptyString(deposit.measurementRoot, 'measurementRoot'), + normalizedMeasurementUnits, + fitQualityBps: assertBasisPoints(deposit.fitQualityBps, 'fitQualityBps'), + provenanceBps: assertBasisPoints(deposit.provenanceBps ?? MAX_BPS, 'provenanceBps'), + accepted: true, + }; + }); +} + +function normalizeBtdRange(input: SourceToSharesBtdRangeInput, assetPackId: string): { + assetPackId: string; + rangeStart?: BtdTokenId; + rangeEndExclusive?: BtdTokenId; + tokenCount: number; + rangeRoot?: string; + measureMintReceiptRoot?: string; + zeroCellReason?: BtdZeroCellReason; +} { + const rangeAssetPackId = assertNonEmptyString(input.assetPackId, 'btdRange.assetPackId'); + if (rangeAssetPackId !== assetPackId) { + throw new Error('Source-to-shares BTD range assetPackId must match the proof assetPackId.'); + } + + const hasRangeBounds = + input.rangeStart !== undefined || input.rangeEndExclusive !== undefined; + const rangeStart = hasRangeBounds + ? assertNonNegativeSafeInteger(input.rangeStart, 'rangeStart') + : undefined; + const rangeEndExclusive = hasRangeBounds + ? assertNonNegativeSafeInteger(input.rangeEndExclusive, 'rangeEndExclusive') + : undefined; + if (hasRangeBounds && rangeEndExclusive! < rangeStart!) { + throw new Error('Source-to-shares BTD range cannot be negative.'); + } + + const derivedTokenCount = hasRangeBounds ? rangeEndExclusive! - rangeStart! : 0; + const tokenCount = + input.tokenCount === undefined + ? derivedTokenCount + : assertNonNegativeSafeInteger(input.tokenCount, 'tokenCount'); + + if (hasRangeBounds && tokenCount !== derivedTokenCount) { + throw new Error('Source-to-shares BTD tokenCount does not match range bounds.'); + } + if (!hasRangeBounds && tokenCount > 0) { + throw new Error('Source-to-shares positive tokenCount requires range bounds.'); + } + + return { + assetPackId: rangeAssetPackId, + rangeStart, + rangeEndExclusive, + tokenCount, + rangeRoot: input.rangeRoot ? assertNonEmptyString(input.rangeRoot, 'rangeRoot') : undefined, + measureMintReceiptRoot: input.measureMintReceiptRoot + ? assertNonEmptyString(input.measureMintReceiptRoot, 'measureMintReceiptRoot') + : undefined, + zeroCellReason: input.zeroCellReason, + }; +} + +function normalizeFeeQuote(input: SourceToSharesFeeQuoteInput): SourceToSharesProof['feeQuote'] { + if ((input.priceAsset ?? BITCODE_FEE_ASSET) !== BITCODE_FEE_ASSET) { + throw new Error('Source-to-shares fee quote must be priced in BTC.'); + } + const grossSats = toBigIntAmount(input.grossSats, 'grossSats'); + if (grossSats <= 0n) { + throw new Error('Source-to-shares fee quote grossSats must be positive.'); + } + + return { + quoteId: assertNonEmptyString(input.quoteId, 'quoteId'), + quoteRoot: assertNonEmptyString(input.quoteRoot, 'quoteRoot'), + priceAsset: BITCODE_FEE_ASSET, + grossSats, + }; +} + +function normalizePaymentObservation( + input: SourceToSharesPaymentObservationInput, +): SourceToSharesProof['paymentObservation'] { + const observedDebitSats = toBigIntAmount(input.observedDebitSats, 'observedDebitSats'); + if (observedDebitSats < 0n) { + throw new Error('Source-to-shares observedDebitSats must be non-negative.'); + } + const observedCreditSats = + input.observedCreditSats === undefined + ? observedDebitSats + : toBigIntAmount(input.observedCreditSats, 'observedCreditSats'); + if (observedCreditSats < 0n) { + throw new Error('Source-to-shares observedCreditSats must be non-negative.'); + } + + return { + paymentReceiptRoot: assertNonEmptyString(input.paymentReceiptRoot, 'paymentReceiptRoot'), + observedDebitSats, + observedCreditSats, + finalityState: input.finalityState, + txid: input.txid ? assertNonEmptyString(input.txid, 'txid') : undefined, + }; +} + +function buildContributionWeights( + fitDeposits: readonly SourceToSharesBoundFitDeposit[], +): { + contributionWeights: SourceToSharesContributionWeight[]; + normalizationTrace: SourceToSharesNormalizationTrace; +} { + const rawEntries = fitDeposits + .map((deposit) => { + const rawWeight = + deposit.normalizedMeasurementUnits * + BigInt(deposit.fitQualityBps) * + BigInt(deposit.provenanceBps); + const clippedWeight = rawWeight > 0n ? rawWeight : 0n; + return { + deposit, + rawWeight, + clippedWeight, + disposition: + clippedWeight > 0n + ? 'positive_marginal_contribution' + : 'clipped_zero_contribution', + } as const; + }) + .sort((left, right) => left.deposit.depositId.localeCompare(right.deposit.depositId)); + + const totalClippedWeight = rawEntries.reduce((sum, entry) => sum + entry.clippedWeight, 0n); + if (totalClippedWeight <= 0n) { + throw new Error('Source-to-shares proof requires at least one positive contribution weight.'); + } + + const provisional = rawEntries.map((entry) => { + const numerator = entry.clippedWeight * MAX_BPS_BIGINT; + return { + ...entry, + floorShareBps: Number(numerator / totalClippedWeight), + remainderUnits: numerator % totalClippedWeight, + remainderAwardedBps: 0, + tieBreakRank: 0, + }; + }); + let remainingBps = + MAX_BPS - provisional.reduce((sum, entry) => sum + entry.floorShareBps, 0); + const remainderOrder = [...provisional].sort(compareShareRemainders); + remainderOrder.forEach((entry, index) => { + entry.tieBreakRank = index + 1; + }); + for (const entry of remainderOrder) { + if (remainingBps <= 0) break; + entry.floorShareBps += 1; + entry.remainderAwardedBps += 1; + remainingBps -= 1; + } + + const contributionWeights = provisional + .sort((left, right) => right.floorShareBps - left.floorShareBps || left.deposit.depositId.localeCompare(right.deposit.depositId)) + .map((entry): SourceToSharesContributionWeight => ({ + depositId: entry.deposit.depositId, + assetPackId: entry.deposit.assetPackId, + depositorWalletId: entry.deposit.depositorWalletId, + measurementRoot: entry.deposit.measurementRoot, + sourceManifestRoot: entry.deposit.sourceManifestRoot, + findingFitsResultRoot: entry.deposit.findingFitsResultRoot, + rawWeight: entry.rawWeight.toString(), + clippedWeight: entry.clippedWeight.toString(), + shareBps: entry.floorShareBps, + normalizationRemainderUnits: entry.remainderUnits.toString(), + disposition: entry.disposition, + reasons: [ + `measurementUnits=${entry.deposit.normalizedMeasurementUnits.toString()}`, + `fitQualityBps=${entry.deposit.fitQualityBps}`, + `provenanceBps=${entry.deposit.provenanceBps}`, + ], + })); + + return { + contributionWeights, + normalizationTrace: { + method: 'largest_remainder', + totalClippedWeight: totalClippedWeight.toString(), + normalizedTotalBps: contributionWeights.reduce((sum, entry) => sum + entry.shareBps, 0), + tieBreakPolicy: 'remainder_desc_weight_desc_deposit_id_asc', + remainderDistributionOrder: remainderOrder.map((entry) => entry.deposit.depositId), + provisionalShares: provisional.map((entry) => ({ + depositId: entry.deposit.depositId, + floorShareBps: entry.floorShareBps - entry.remainderAwardedBps, + remainderUnits: entry.remainderUnits.toString(), + remainderAwardedBps: entry.remainderAwardedBps, + finalShareBps: entry.floorShareBps, + tieBreakRank: entry.tieBreakRank, + })), + }, + }; +} + +function allocateRangeSlices(input: { + assetPackId: string; + fitDeposits: readonly SourceToSharesBoundFitDeposit[]; + contributionWeights: readonly SourceToSharesContributionWeight[]; + rangeStart?: BtdTokenId; + tokenCount: number; +}): SourceToSharesRangeSlice[] { + if (input.tokenCount === 0) { + return input.contributionWeights.map((weight) => ({ + depositId: weight.depositId, + assetPackId: weight.assetPackId, + depositorWalletId: weight.depositorWalletId, + shareBps: weight.shareBps, + tokenCount: 0, + sliceState: 'zero_cell_refit_tail', + sliceRoot: stableProofRoot('source-to-shares-range-slice', [ + input.assetPackId, + weight.depositId, + 0, + 'zero_cell_refit_tail', + ]), + })); + } + + const provisional = input.contributionWeights.map((weight) => { + const numerator = BigInt(input.tokenCount) * BigInt(weight.shareBps); + return { + weight, + tokenCount: Number(numerator / MAX_BPS_BIGINT), + remainderUnits: numerator % MAX_BPS_BIGINT, + extraTokensAwarded: 0, + }; + }); + let remaining = + input.tokenCount - provisional.reduce((sum, entry) => sum + entry.tokenCount, 0); + for (const entry of [...provisional].sort(compareAllocationRemainders)) { + if (remaining <= 0) break; + entry.tokenCount += 1; + entry.extraTokensAwarded += 1; + remaining -= 1; + } + + let cursor = assertNonNegativeSafeInteger(input.rangeStart, 'rangeStart'); + return provisional + .sort((left, right) => left.weight.depositId.localeCompare(right.weight.depositId)) + .map((entry): SourceToSharesRangeSlice => { + const rangeStart = entry.tokenCount > 0 ? cursor : undefined; + const rangeEndExclusive = entry.tokenCount > 0 ? cursor + entry.tokenCount : undefined; + cursor += entry.tokenCount; + return { + depositId: entry.weight.depositId, + assetPackId: entry.weight.assetPackId, + depositorWalletId: entry.weight.depositorWalletId, + shareBps: entry.weight.shareBps, + tokenCount: entry.tokenCount, + rangeStart, + rangeEndExclusive, + sliceState: entry.tokenCount > 0 ? 'allocated' : 'zero_cell_refit_tail', + sliceRoot: stableProofRoot('source-to-shares-range-slice', [ + input.assetPackId, + entry.weight.depositId, + rangeStart ?? 'zero', + rangeEndExclusive ?? 'zero', + entry.tokenCount, + ]), + }; + }); +} + +function allocateSettlementSats(input: { + fitDeposits: readonly SourceToSharesBoundFitDeposit[]; + contributionWeights: readonly SourceToSharesContributionWeight[]; + grossSats: bigint; +}): SourceToSharesSettlementAllocation[] { + const provisional = input.contributionWeights.map((weight) => { + const numerator = input.grossSats * BigInt(weight.shareBps); + return { + weight, + allocatedSats: numerator / MAX_BPS_BIGINT, + remainderUnits: numerator % MAX_BPS_BIGINT, + extraSatsAwarded: 0n, + }; + }); + let remaining = + input.grossSats - provisional.reduce((sum, entry) => sum + entry.allocatedSats, 0n); + for (const entry of [...provisional].sort(compareAllocationRemainders)) { + if (remaining <= 0n) break; + entry.allocatedSats += 1n; + entry.extraSatsAwarded += 1n; + remaining -= 1n; + } + + return provisional + .sort((left, right) => left.weight.depositId.localeCompare(right.weight.depositId)) + .map((entry): SourceToSharesSettlementAllocation => ({ + depositId: entry.weight.depositId, + assetPackId: entry.weight.assetPackId, + depositorWalletId: entry.weight.depositorWalletId, + shareBps: entry.weight.shareBps, + allocatedSats: entry.allocatedSats, + allocationRemainderUnits: entry.remainderUnits.toString(), + allocationRoot: stableProofRoot('source-to-shares-settlement-allocation', [ + entry.weight.depositId, + entry.weight.shareBps, + entry.allocatedSats.toString(), + ]), + })); +} + +function buildSettlementConservation(input: { + proofId: string; + feeQuote: SourceToSharesProof['feeQuote']; + paymentObservation: SourceToSharesProof['paymentObservation']; + settlementAllocations: readonly SourceToSharesSettlementAllocation[]; +}): SourceToSharesSettlementConservation { + const expectedDebitSats = input.feeQuote.grossSats; + const expectedCreditSats = input.feeQuote.grossSats; + const observedDebitSats = input.paymentObservation.observedDebitSats; + const observedCreditSats = input.paymentObservation.observedCreditSats; + const allocatedCreditSats = input.settlementAllocations.reduce( + (sum, allocation) => sum + allocation.allocatedSats, + 0n, + ); + const noOverpaymentPassed = + observedDebitSats <= expectedDebitSats && observedCreditSats <= expectedCreditSats; + const noUnderpaymentPassed = + observedDebitSats >= expectedDebitSats && observedCreditSats >= expectedCreditSats; + const allocationConserved = allocatedCreditSats === expectedCreditSats; + const state = deriveConservationState({ noOverpaymentPassed, noUnderpaymentPassed, allocationConserved }); + const blockerReasons = [ + noOverpaymentPassed ? null : 'observed payment or credit exceeds accepted BTC fee quote', + noUnderpaymentPassed ? null : 'observed payment or credit is below accepted BTC fee quote', + allocationConserved ? null : 'allocated source-to-shares credits do not conserve gross sats', + ].filter((reason): reason is string => Boolean(reason)); + const conservationRoot = stableProofRoot('source-to-shares-settlement-conservation', [ + input.proofId, + input.feeQuote.quoteRoot, + input.paymentObservation.paymentReceiptRoot, + expectedDebitSats.toString(), + observedDebitSats.toString(), + expectedCreditSats.toString(), + observedCreditSats.toString(), + allocatedCreditSats.toString(), + state, + ]); + + return { + state, + expectedDebitSats, + observedDebitSats, + expectedCreditSats, + observedCreditSats, + allocatedCreditSats, + noOverpayment: { + theoremId: 'settlement_source_to_shares.no_overpayment', + passed: noOverpaymentPassed, + expectedSats: expectedDebitSats, + observedSats: observedDebitSats > observedCreditSats ? observedDebitSats : observedCreditSats, + summary: noOverpaymentPassed + ? 'Observed debit and credit do not exceed the accepted BTC fee quote.' + : 'Observed debit or credit exceeds the accepted BTC fee quote.', + }, + noUnderpayment: { + theoremId: 'settlement_source_to_shares.no_underpayment', + passed: noUnderpaymentPassed, + expectedSats: expectedDebitSats, + observedSats: observedDebitSats < observedCreditSats ? observedDebitSats : observedCreditSats, + summary: noUnderpaymentPassed + ? 'Observed debit and credit satisfy the accepted BTC fee quote.' + : 'Observed debit or credit is below the accepted BTC fee quote.', + }, + allocationConserved, + settlementAdmissible: state === 'balanced', + blockerReasons, + conservationRoot, + reconciliationCheck: { + checkId: input.proofId, + expectedDebitSats: toSafeIntegerSats(expectedDebitSats, 'expectedDebitSats'), + observedDebitSats: toSafeIntegerSats(observedDebitSats, 'observedDebitSats'), + expectedCreditSats: toSafeIntegerSats(expectedCreditSats, 'expectedCreditSats'), + observedCreditSats: toSafeIntegerSats(observedCreditSats, 'observedCreditSats'), + feeQuoteRoot: input.feeQuote.quoteRoot, + paymentReceiptRoot: input.paymentObservation.paymentReceiptRoot, + }, + }; +} + +function buildZeroCellRefitTail(input: { + btdRange: ReturnType; + rangeSlices: readonly SourceToSharesRangeSlice[]; + fitDeposits: readonly SourceToSharesBoundFitDeposit[]; +}): SourceToSharesZeroCellRefitTail { + const zeroCellDepositIds = input.rangeSlices + .filter((slice) => slice.sliceState === 'zero_cell_refit_tail') + .map((slice) => slice.depositId); + const state = zeroCellDepositIds.length ? 'zero_cell_refit_tail' : 'no_zero_cell_tail'; + const tailRoot = stableProofRoot('source-to-shares-zero-cell-refit-tail', [ + input.btdRange.assetPackId, + input.btdRange.tokenCount, + input.btdRange.zeroCellReason ?? null, + input.btdRange.measureMintReceiptRoot ?? null, + zeroCellDepositIds, + ]); + + return { + tailPolicy: 'zero_cell_receipt_then_refit_only', + state, + rangeTokenCount: input.btdRange.tokenCount, + zeroCellReason: input.btdRange.zeroCellReason, + measureMintReceiptRoot: input.btdRange.measureMintReceiptRoot, + zeroCellDepositIds, + refitRequired: state === 'zero_cell_refit_tail', + tailRoot, + }; +} + +function buildAncestryEvidence( + receipt?: BtdAncestryReviewReceipt | null, +): SourceToSharesAncestryEvidence { + if (!receipt) { + return { + state: 'not_provided', + reviewRoot: stableProofRoot('source-to-shares-ancestry', ['not-provided']), + payableEdgeCount: 0, + recordedUnpaidEdgeCount: 0, + rejectedEdgeCount: 0, + payableRouteWeight: '0', + }; + } + + const payableRouteWeight = receipt.edges + .filter((edge) => edge.status === 'payable') + .reduce((sum, edge) => sum + toBigIntAmount(edge.routeWeight, 'routeWeight'), 0n); + return { + state: 'reviewed', + reviewId: assertNonEmptyString(receipt.reviewId, 'ancestryReview.reviewId'), + reviewRoot: stableProofRoot('source-to-shares-ancestry', [ + receipt.reviewId, + receipt.childAssetPackId, + receipt.payableEdgeCount, + receipt.recordedUnpaidEdgeCount, + receipt.rejectedEdgeCount, + payableRouteWeight.toString(), + ]), + payableEdgeCount: receipt.payableEdgeCount, + recordedUnpaidEdgeCount: receipt.recordedUnpaidEdgeCount, + rejectedEdgeCount: receipt.rejectedEdgeCount, + payableRouteWeight: payableRouteWeight.toString(), + }; +} + +function deriveConservationState(input: { + noOverpaymentPassed: boolean; + noUnderpaymentPassed: boolean; + allocationConserved: boolean; +}): SourceToSharesSettlementConservationState { + if (input.noOverpaymentPassed && input.noUnderpaymentPassed && input.allocationConserved) { + return 'balanced'; + } + if (!input.noOverpaymentPassed && input.noUnderpaymentPassed) return 'overpayment'; + if (input.noOverpaymentPassed && !input.noUnderpaymentPassed) return 'underpayment'; + return 'drifted'; +} + +function compareShareRemainders( + left: { + deposit: SourceToSharesBoundFitDeposit; + clippedWeight: bigint; + remainderUnits: bigint; + }, + right: { + deposit: SourceToSharesBoundFitDeposit; + clippedWeight: bigint; + remainderUnits: bigint; + }, +): number { + if (left.remainderUnits !== right.remainderUnits) { + return left.remainderUnits > right.remainderUnits ? -1 : 1; + } + if (left.clippedWeight !== right.clippedWeight) { + return left.clippedWeight > right.clippedWeight ? -1 : 1; + } + return left.deposit.depositId.localeCompare(right.deposit.depositId); +} + +function compareAllocationRemainders( + left: { weight: SourceToSharesContributionWeight; remainderUnits: bigint }, + right: { weight: SourceToSharesContributionWeight; remainderUnits: bigint }, +): number { + if (left.remainderUnits !== right.remainderUnits) { + return left.remainderUnits > right.remainderUnits ? -1 : 1; + } + if (left.weight.shareBps !== right.weight.shareBps) { + return right.weight.shareBps - left.weight.shareBps; + } + return left.weight.depositId.localeCompare(right.weight.depositId); +} + +function assertBasisPoints(value: number, label: string): number { + if (!Number.isSafeInteger(value) || value < 0 || value > MAX_BPS) { + throw new Error(`${label} must be an integer from 0 to 10000.`); + } + + return value; +} + +function toSafeIntegerSats(value: bigint, label: string): number { + if (value < 0n || value > BigInt(Number.MAX_SAFE_INTEGER)) { + throw new Error(`${label} must fit in a non-negative safe integer sat amount.`); + } + return Number(value); +} + +function stableId(prefix: string, parts: Array): string { + const hash = createHash('sha256') + .update(parts.map((part) => String(part)).join('\u001f')) + .digest('hex') + .slice(0, 16); + return `${prefix}_${hash}`; +} + +function stableProofRoot(scope: string, value: unknown): string { + return `btd-proof-root:${scope}:${createHash('sha256').update(stableSerialize(value)).digest('hex')}`; +} + +function stableSerialize(value: unknown): string { + if (value === null || value === undefined) return String(value); + if (typeof value === 'bigint') return `${value.toString()}n`; + if (Array.isArray(value)) return `[${value.map(stableSerialize).join(',')}]`; + if (typeof value === 'object') { + return `{${Object.entries(value as Record) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([key, entry]) => `${JSON.stringify(key)}:${stableSerialize(entry)}`) + .join(',')}}`; + } + return JSON.stringify(value); +} diff --git a/scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs b/scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs new file mode 100644 index 000000000..3a3c52fc8 --- /dev/null +++ b/scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs @@ -0,0 +1,228 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 6 source-to-shares proof cleanup, package proof ownership, API route boundary, tests, docs, and workflow readiness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-6-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 6 work must occur on version/v30 or v30/gate-6-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + 'packages/btd/src/source-to-shares.ts', + 'packages/btd/src/api-boundaries.ts', + 'packages/btd/src/index.ts', + 'packages/btd/__tests__/source-to-shares.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'uapi/app/api/btd/source-to-shares-proof/route.ts', + 'packages/btd/README.md', + 'uapi/app/terminal/README.md', + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + ]) { + assertCheck(failures, fileExists(root, relativePath), `Missing V30 Gate 6 file: ${relativePath}`); + } + + const sourceToShares = read(root, 'packages/btd/src/source-to-shares.ts'); + const btdBoundary = read(root, 'packages/btd/src/api-boundaries.ts'); + const btdIndex = read(root, 'packages/btd/src/index.ts'); + const btdTest = read(root, 'packages/btd/__tests__/source-to-shares.test.ts'); + const apiRoute = read(root, 'packages/api/src/routes/btd-crypto.ts'); + const apiTest = read(root, 'packages/api/src/routes/__tests__/btd-crypto.test.ts'); + const uapiRoute = read(root, 'uapi/app/api/btd/source-to-shares-proof/route.ts'); + const btdReadme = read(root, 'packages/btd/README.md'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + for (const symbol of [ + 'SourceToSharesProof', + 'buildSourceToSharesProof', + 'assertSourceToSharesSettlementAdmissible', + 'sourceToSharesProofToSettlementConservationCheck', + 'noOverpayment', + 'noUnderpayment', + 'zeroCellRefitTail', + 'ancestryEvidence', + 'largest_remainder', + 'settlementAdmissible', + '.bitcode/v30-settlement-source-to-shares-proof.json', + ]) { + assertCheck(failures, sourceToShares.includes(symbol), `BTD source-to-shares primitive is missing ${symbol}.`); + } + + for (const testEvidence of [ + 'binds measurements, fit deposits, BTD range slices, fee quote, and exact BTC allocation', + 'no-underpayment and no-overpayment invariants', + 'zero-cell refit tail posture', + 'ancestry evidence', + 'Duplicate source-to-shares fit deposit', + 'only accepts admitted fit deposits', + ]) { + assertCheck(failures, btdTest.includes(testEvidence), `BTD source-to-shares tests must cover ${testEvidence}.`); + } + + for (const boundaryEvidence of [ + 'BtdSourceToSharesProofInput', + 'BtdSourceToSharesProofSettlement', + 'buildBtdSourceToSharesProofSettlement', + 'terminal-btd-source-to-shares-proof', + 'settlement_finalization', + ]) { + assertCheck(failures, btdBoundary.includes(boundaryEvidence), `BTD API boundary must include ${boundaryEvidence}.`); + } + assertCheck(failures, btdIndex.includes("export * from './source-to-shares'"), 'BTD package index must export source-to-shares primitives.'); + + for (const apiEvidence of [ + 'buildPostBtdSourceToSharesProofRoute', + '/btd/source-to-shares-proof', + ]) { + assertCheck(failures, apiRoute.includes(apiEvidence), `BTD API route must include ${apiEvidence}.`); + assertCheck(failures, apiTest.includes(apiEvidence), `BTD API tests must cover ${apiEvidence}.`); + } + assertCheck( + failures, + apiRoute.includes('postBtdSourceToSharesProof'), + 'BTD API route must export postBtdSourceToSharesProof.', + ); + assertCheck( + failures, + uapiRoute.includes('postBtdSourceToSharesProof'), + 'Next route must expose postBtdSourceToSharesProof.', + ); + + assertCheck( + failures, + btdReadme.includes('source-to-shares proof cleanup') && + btdReadme.includes('no-overpayment/no-underpayment'), + 'BTD README must document source-to-shares proof ownership.', + ); + assertCheck( + failures, + terminalReadme.includes('Source-to-shares settlement evidence') && + terminalReadme.includes('no-overpayment and no-underpayment'), + 'Terminal README must document source-to-shares proof consumption.', + ); + assertCheck( + failures, + spec.includes('Gate 6 source-to-shares precision') && + spec.includes('no-overpayment and no-underpayment'), + 'V30 SPEC must define Gate 6 source-to-shares proof precision.', + ); + assertCheck( + failures, + delta.includes('Gate 6 implementation centers') && + delta.includes('SettlementConservationCheck'), + 'V30 DELTA must include Gate 6 implementation evidence.', + ); + assertCheck( + failures, + notes.includes('Gate 6 source-to-shares cleanup notes'), + 'V30 NOTES must include Gate 6 implementation notes.', + ); + assertCheck( + failures, + parity.includes('## Gate 6 Parity') && parity.includes('Gate 6 accepted boundaries'), + 'V30 PARITY must include Gate 6 parity and accepted boundaries.', + ); + assertCheck(failures, packageJson.includes('"check:v30-gate6"'), 'package.json must expose check:v30-gate6.'); + assertCheck( + failures, + gateWorkflow.includes('check-v30-gate6-source-to-shares-proof-cleanup.mjs'), + 'Gate workflow must run the V30 Gate 6 checker.', + ); + + if (failures.length) { + process.stderr.write('V30 Gate 6 source-to-shares proof cleanup check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V30 Gate 6 source-to-shares proof cleanup check passed.\n'); +} + +try { + main(); +} catch (error) { + const detail = error instanceof Error ? error.message : String(error); + process.stderr.write(`${detail}\n`); + process.exitCode = 1; +} diff --git a/uapi/app/api/btd/source-to-shares-proof/route.ts b/uapi/app/api/btd/source-to-shares-proof/route.ts new file mode 100644 index 000000000..0990845c0 --- /dev/null +++ b/uapi/app/api/btd/source-to-shares-proof/route.ts @@ -0,0 +1,3 @@ +import { postBtdSourceToSharesProof } from '@bitcode/api'; + +export const POST = postBtdSourceToSharesProof; diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index bdc0c6b3d..291be8367 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -143,6 +143,14 @@ are retryable unlock blockers, and settled transactions with missing pull-request delivery surface delivery recovery without exposing protected AssetPack source before payment. +Source-to-shares settlement evidence should enter the Terminal as a package +proof, not as route-local accounting. The BTD source-to-shares proof binds +fit-deposit measurements, contribution weights, BTD range slices, exact BTC fee +allocation, conservation verdicts, zero-cell/refit tail posture, ancestry +evidence, and a reconciliation-compatible conservation check. Operators should +read no-overpayment and no-underpayment separately so overpaid, underpaid, and +drifted settlements are repairable without exposing protected AssetPack source. + The Organization Authority section is the selected-activity permission explainer. It projects registry-derived organization role, explicit grants, wallet binding, owner-read or licensed-read access, settlement state, From 1fd0226bffa228d1cc1a565e8322d97dd6a1fcd6 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 19:25:13 -0300 Subject: [PATCH 08/15] V30 Gate 7: Bound bridge-readiness research Introduce a package-owned BridgeReadinessResearchPosture for Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future distribution path research without admitting any bridge as current BTD chain-of-record truth. Expose the source-safe posture through BTD API and Next route boundaries, add BTD/API coverage, update V30 spec family and README documentation, and wire the Gate 7 checker into gate-quality CI. Proof: pnpm --filter @bitcode/btd typecheck; pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/bridge-readiness.test.ts --runInBand; pnpm --filter @bitcode/btd test; pnpm --filter @bitcode/api build; pnpm --filter @bitcode/api exec jest --config jest.config.cjs --runTestsByPath src/routes/__tests__/btd-crypto.test.ts --runInBand; pnpm --dir uapi exec tsc --noEmit --pretty false; pnpm run check:v30-gate7; node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs --skip-branch-check through gate7; git diff --check; git diff --cached --check. --- .github/workflows/bitcode-gate-quality.yml | 1 + BITCODE_SPEC_V30.md | 20 + BITCODE_SPEC_V30_DELTA.md | 13 + BITCODE_SPEC_V30_NOTES.md | 19 + BITCODE_SPEC_V30_PARITY_MATRIX.md | 20 +- package.json | 1 + .../src/routes/__tests__/btd-crypto.test.ts | 57 ++ packages/api/src/routes/btd-crypto.ts | 38 ++ packages/btd/README.md | 5 + .../btd/__tests__/bridge-readiness.test.ts | 110 ++++ packages/btd/src/api-boundaries.ts | 64 +++ packages/btd/src/bridge-readiness.ts | 511 ++++++++++++++++++ packages/btd/src/index.ts | 1 + ...7-bridge-readiness-research-boundaries.mjs | 223 ++++++++ .../btd/bridge-readiness-research/route.ts | 3 + uapi/app/terminal/README.md | 7 + 16 files changed, 1092 insertions(+), 1 deletion(-) create mode 100644 packages/btd/__tests__/bridge-readiness.test.ts create mode 100644 packages/btd/src/bridge-readiness.ts create mode 100644 scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs create mode 100644 uapi/app/api/btd/bridge-readiness-research/route.ts diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 2f0052e12..f88313a9f 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -85,6 +85,7 @@ jobs: node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs --skip-branch-check node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs --skip-branch-check node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs --skip-branch-check + node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index a71d90388..7d78fe96e 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -242,6 +242,26 @@ Gate 6 source-to-shares precision: Prepared, signed, broadcast, replaced, reorged, and failed fee receipts do not unlock protected source. +Gate 7 bridge-readiness research boundaries: + +- `BridgeReadinessResearchPosture` is package-owned in `@bitcode/btd` and is + the reusable policy boundary for bridge and distribution research. +- The required research paths are Taproot, BitVM, BSC/opBNB, Binance Web3 + Wallet, and future distribution paths. Each path must have a posture record + naming feasibility, risks, current non-admission, rereview triggers, required + proof before admission, and required policy before admission. +- V30 admits no bridge path as current `$BTD` chain-of-record truth. + The posture root must retain `bitcoin_btd_registry` as the active BTD chain + of record and `no_bridge_chain_of_record` as the bridge truth. +- Bridge-readiness records are source-safe research facts. They may not contain + secrets or protected source, and they may not become wrappers, transfers, + settlement rails, ownership claims, or fee rails without a future promoted + version that supplies proof, policy, repair, telemetry, and disclosure + admission. +- Terminal and API surfaces may show bridge-readiness posture as operational + research evidence, but they must fail closed on any payload attempting to + set `chainOfRecordAdmitted` or to mark a bridge as current BTD truth. + ## V30 whole Bitcode operator chain The V30 Terminal operator chain is: diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 9e07c0ed8..4a7f57ef8 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -254,6 +254,19 @@ Closure acceptance: - each record names feasibility, risks, current non-admission, rereview triggers, and required proof before admission; - no bridge path is treated as current `$BTD` chain-of-record truth. +Gate 7 implementation centers `BridgeReadinessResearchPosture` in +`packages/btd/src/bridge-readiness.ts`. +It deliberately models bridge and distribution candidates as research facts, +not as live chain-of-record adapters. +The package builder synthesizes the required Taproot, BitVM, BSC/opBNB, +Binance Web3 Wallet, and future-distribution records, rejects duplicate paths, +rejects secret-looking posture text, and fails closed when a caller attempts +`chainOfRecordAdmitted`. +The BTD API boundary exposes `/btd/bridge-readiness-research` as a source-safe +route for policy/readiness posture only; it returns a Terminal journal +`proof_admission` entry and never writes bridge ownership, settlement, or fee +state. + ### Gate 8: Protocol Telemetry And Proof Hooks Gate 8 adds Protocol/BTD telemetry and proof hooks. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index c39eedce1..7788418bd 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -212,6 +212,25 @@ slices, or BTC fee allocations. 10. **Gate 10: V30 Promotion Readiness** - Close local/staging proof, generated artifacts, V30 promotion workflow, and post-promotion V30 active / V31 draft posture. +## Gate 7 bridge-readiness research notes + +Gate 7 keeps bridge work honest by making bridge candidates typed research +posture instead of latent implementation claims. +Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future distribution paths +are all represented as records with feasibility, risks, rereview triggers, +required proof, and required policy, but every record remains +`research_only`. + +The accepted implementation is package-owned: +`packages/btd/src/bridge-readiness.ts` builds +`BridgeReadinessResearchPosture`; `packages/btd/src/api-boundaries.ts` wraps it +in a Terminal journal `proof_admission` settlement; and +`packages/api/src/routes/btd-crypto.ts` exposes the source-safe +`/btd/bridge-readiness-research` route. +No Gate 7 code may mint, wrap, transfer, settle, or unlock BTD through a bridge. +The only current chain-of-record posture is `bitcoin_btd_registry` plus +`no_bridge_chain_of_record`. + ## Gate 1 working notes Gate 1 is complete only when the V30 family exists, validates in draft mode over active V29, and makes the roadmap truthful enough to drive V31 through V37 without stale V27/V28/V29 posture. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index 317767e61..1f6fe3ae6 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -60,7 +60,7 @@ No `_legacy/` source is active source truth. | BTD AssetPack mint/read receipts | Gate 4 | `packages/btd/src/receipts.ts`, `packages/btd/src/api-boundaries.ts`, asset-pack harness evidence, Terminal detail snapshot/read model tests, gate checker | drafted | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | | Testnet ledger projection hardening | Gate 5 | `packages/btd/src/reconciliation.ts`, API route tests, asset-pack harness evidence, Terminal journal reconciliation UI/tests, gate checker | drafted | Ledger/database/object-storage/private facts are distinct; staging-testnet readback is secret-free; drift, quarantine, retry, and unlock blocking are tested. | | Source-to-shares proof cleanup | Gate 6 | `packages/btd/src/source-to-shares.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Measurement contribution, fee allocation, zero-cell/refit tail, ancestry evidence, and conservation invariants are testable. | -| Bridge-readiness research boundaries | Gate 7 | Protocol/BTD research notes, policy posture tests, docs | pending | Bridge paths are documented as research until admitted by explicit future proof and policy. | +| Bridge-readiness research boundaries | Gate 7 | `packages/btd/src/bridge-readiness.ts`, BTD/API tests, route boundary, docs, gate checker | drafted | Bridge paths are typed research-only records until admitted by explicit future proof and policy. | | Protocol telemetry/proof hooks | Gate 8 | telemetry schema, proof hooks, generated-artifact inventory, tests | pending | Receipts, fee states, projections, and source-to-shares facts emit source-safe telemetry and proof hooks. | | Interface integration regression | Gate 9 | Terminal/API/MCP/ChatGPT App adapters and tests | pending | Existing interfaces consume package-owned objects without regressing V29 behavior. | | Promotion readiness | Gate 10 | V30 promotion workflow, generated `.bitcode/v30-*`, `BITCODE_SPEC_V30_PROVEN.md` | pending | `version/v30` can promote to `main` only after all V30 checks pass and promotion automation can commit generated canon. | @@ -192,6 +192,24 @@ No `_legacy/` source is active source truth. - Gate 6 does not admit bridge chain-of-record semantics; Gate 7 owns bridge-readiness boundaries. - Gate 6 does not promote V30 or change the active canon pointer. +## Gate 7 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| Bridge-readiness posture is package-owned | `packages/btd/src/bridge-readiness.ts`, `packages/btd/src/index.ts` | drafted | +| Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future distribution paths are covered | `BRIDGE_READINESS_RESEARCH_PATHS`, `packages/btd/__tests__/bridge-readiness.test.ts` | drafted | +| Every bridge path remains research-only and not current BTD chain-of-record truth | `assertNoBridgeChainOfRecordAdmission`, `bridgeChainOfRecordTruth: no_bridge_chain_of_record` | drafted | +| API and Terminal boundary expose source-safe research posture only | `buildBtdBridgeReadinessResearchSettlement`, `buildPostBtdBridgeReadinessResearchRoute`, `uapi/app/api/btd/bridge-readiness-research/route.ts` | drafted | +| Gate checker protects bridge research boundaries | `scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs`, `pnpm run check:v30-gate7`, gate-quality workflow | drafted | + +## Gate 7 accepted boundaries + +- Gate 7 does not implement a bridge chain-of-record path. +- Gate 7 does not mint, wrap, transfer, settle, unlock, or deliver `$BTD` through Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, or any future distribution path. +- Gate 7 does not store secrets or protected source in bridge-readiness records. +- Gate 7 may expose source-safe research posture to Terminal/API callers for operator review. +- Gate 7 does not promote V30 or change the active canon pointer. + ## completion condition Gate 1 is complete when the V30 draft family validates, `check:v30-gate1` passes, workflow posture is V30-aware, README and roadmap reflect V30 initiation, V31-V37 scopes are current enough to guide future gates, diff hygiene passes, and the gate branch is committed and pushed for review into `version/v30`. diff --git a/package.json b/package.json index 2a3e25ace..584b08467 100644 --- a/package.json +++ b/package.json @@ -60,6 +60,7 @@ "check:v30-gate4": "node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs", "check:v30-gate5": "node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs", "check:v30-gate6": "node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs", + "check:v30-gate7": "node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/api/src/routes/__tests__/btd-crypto.test.ts b/packages/api/src/routes/__tests__/btd-crypto.test.ts index c0abac55f..5301b09e3 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -19,6 +19,7 @@ import { buildBtdAssetPackLedgerAnchorSettlement, buildBtdAssetPackExchangeSettlement, buildBtdBtcFeeTransactionSettlement, + buildBtdBridgeReadinessResearchSettlement, buildBtdDeploymentReadinessSettlement, buildBtdLedgerDatabaseReconciliationSettlement, buildBtdLicensedReadRevenueSettlement, @@ -36,6 +37,7 @@ import { buildPostBtdAssetPackLedgerAnchorRoute, buildPostBtdAssetPackExchangeRoute, buildPostBtdBtcFeeTransactionRoute, + buildPostBtdBridgeReadinessResearchRoute, buildPostBtdDeploymentReadinessRoute, buildPostBtdLedgerDatabaseReconciliationRoute, buildPostBtdLicensedReadRevenueRoute, @@ -206,6 +208,15 @@ function sourceToSharesProofBody(overrides: Record = {}) { }; } +function bridgeReadinessResearchBody(overrides: Record = {}) { + return { + postureId: 'bridge-readiness-api-1', + exchangeSequence: '19', + issuedAt, + ...overrides, + }; +} + describe('BTD crypto API builders', () => { it('builds a deterministic mint draft from accepted Read-Fit semantic units', () => { const draft = buildBtdMintDraft(mintDraftInput()); @@ -967,6 +978,30 @@ describe('BTD crypto API builders', () => { ); }); + it('builds bridge-readiness research settlements without chain-of-record admission', () => { + const settlement = buildBtdBridgeReadinessResearchSettlement({ + actorId: 'user-1', + ...bridgeReadinessResearchBody(), + exchangeSequence: 19n, + } as any); + + expect(settlement.kind).toBe('btd_bridge_readiness_research_settlement'); + expect(settlement.committed).toBe(false); + expect(settlement.posture.bridgeChainOfRecordTruth).toBe('no_bridge_chain_of_record'); + expect(settlement.posture.records.map((record) => record.path)).toEqual([ + 'bitcoin_taproot_anchor', + 'bitvm_execution_bridge', + 'bsc_opbnb_distribution', + 'binance_web3_wallet_distribution', + 'future_distribution_path', + ]); + expect(settlement.posture.records.every((record) => record.chainOfRecordAdmitted === false)).toBe( + true, + ); + expect(settlement.terminalJournalEntry.transactionKind).toBe('proof_admission'); + expect(settlement.terminalJournalEntry.receiptRoots).toContain(settlement.posture.proofRoot); + }); + it('builds deployment readiness, telemetry, and upgrade settlements', () => { const readiness = buildBtdDeploymentReadinessSettlement({ actorId: 'user-1', @@ -1535,6 +1570,28 @@ describe('BTD crypto API builders', () => { expect(body.terminalJournalEntry.exchangeSequence).toBe('18'); }); + it('returns JSON-safe bridge-readiness research posture from the route boundary', async () => { + const route = buildPostBtdBridgeReadinessResearchRoute({ + resolveAuthenticatedUser: async () => ({ userId: 'user-1' }), + }); + const response = await route( + new Request('https://bitcode.test/api/btd/bridge-readiness-research', { + method: 'POST', + body: JSON.stringify(bridgeReadinessResearchBody()), + }), + ); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body.kind).toBe('btd_bridge_readiness_research_settlement'); + expect(body.committed).toBe(false); + expect(body.posture.activeBtdChainOfRecord).toBe('bitcoin_btd_registry'); + expect(body.posture.bridgeChainOfRecordTruth).toBe('no_bridge_chain_of_record'); + expect(body.posture.allNonAdmitted).toBe(true); + expect(body.posture.records).toHaveLength(5); + expect(body.terminalJournalEntry.exchangeSequence).toBe('19'); + }); + it('returns JSON-safe deployment readiness settlements and persists telemetry or upgrades', async () => { const insertCryptoTelemetryEvent = jest.fn(async (row) => ({ event: row.event, diff --git a/packages/api/src/routes/btd-crypto.ts b/packages/api/src/routes/btd-crypto.ts index dd5be39f9..eca85c4ec 100644 --- a/packages/api/src/routes/btd-crypto.ts +++ b/packages/api/src/routes/btd-crypto.ts @@ -13,6 +13,8 @@ import { type BtdAssetPackExchangeSettlement, type BtdAssetPackLedgerAnchorInput, type BtdAssetPackLedgerAnchorSettlement, + type BtdBridgeReadinessResearchInput, + type BtdBridgeReadinessResearchSettlement, type BtdBtcFeeTransactionInput, type BtdBtcFeeTransactionSettlement, type BtdDeploymentReadinessInput, @@ -40,6 +42,7 @@ import { buildBtdAncestryReviewSettlement, buildBtdAssetPackExchangeSettlement, buildBtdAssetPackLedgerAnchorSettlement, + buildBtdBridgeReadinessResearchSettlement, buildBtdBtcFeeTransactionSettlement, buildBtdDeploymentReadinessSettlement, buildBtdLedgerDatabaseReconciliationSettlement, @@ -62,6 +65,7 @@ export { buildBtdAncestryReviewSettlement, buildBtdAssetPackExchangeSettlement, buildBtdAssetPackLedgerAnchorSettlement, + buildBtdBridgeReadinessResearchSettlement, buildBtdBtcFeeTransactionSettlement, buildBtdDeploymentReadinessSettlement, buildBtdLedgerDatabaseReconciliationSettlement, @@ -601,6 +605,39 @@ export function buildPostBtdSourceToSharesProofRoute(options: BtdRouteOptions = }); } +export function buildPostBtdBridgeReadinessResearchRoute(options: BtdRouteOptions = {}) { + return traceRoute('/btd/bridge-readiness-research', async (request: Request) => { + const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( + request, + ); + if (!user) { + return createJsonResponse({ error: 'Unauthorized' }, 401); + } + + let body: Omit & { + exchangeSequence: string | number; + }; + try { + body = await request.json(); + } catch { + return createJsonResponse({ error: 'Invalid JSON body' }, 400); + } + + let settlement: BtdBridgeReadinessResearchSettlement; + try { + settlement = buildBtdBridgeReadinessResearchSettlement({ + ...body, + actorId: user.userId, + exchangeSequence: parseBtdRequiredBigInt(body.exchangeSequence, 'exchangeSequence'), + }); + } catch (error) { + return createJsonResponse({ error: toBadRequestMessage(error) }, 400); + } + + return createJsonResponse(toJsonSafe(settlement)); + }); +} + export function buildPostBtdDeploymentReadinessRoute(options: BtdRouteOptions = {}) { return traceRoute('/btd/deployment-readiness', async (request: Request) => { const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( @@ -661,6 +698,7 @@ export const postBtdTerminalJournal = buildPostBtdTerminalJournalRoute(); export const postBtdLedgerDatabaseReconciliation = buildPostBtdLedgerDatabaseReconciliationRoute(); export const postBtdSourceToSharesProof = buildPostBtdSourceToSharesProofRoute(); +export const postBtdBridgeReadinessResearch = buildPostBtdBridgeReadinessResearchRoute(); export const postBtdDeploymentReadiness = buildPostBtdDeploymentReadinessRoute(); function toBadRequestMessage(error: unknown): string { diff --git a/packages/btd/README.md b/packages/btd/README.md index 169192136..b493c7a0b 100644 --- a/packages/btd/README.md +++ b/packages/btd/README.md @@ -19,6 +19,10 @@ This package owns: largest-remainder share weights, BTD range slices, exact BTC fee allocation, settlement conservation, zero-cell/refit tail posture, ancestry evidence, and no-overpayment/no-underpayment theorem verdicts +- bridge-readiness research boundaries for Taproot, BitVM, BSC/opBNB, + Binance Web3 Wallet, and future distribution paths; every bridge posture is + research-only and cannot become current `$BTD` chain-of-record truth without + explicit future proof and policy admission - ledger/database/object-storage projection reconciliation, including deterministic repair classes, source-safe object artifact roots, secret-free Supabase staging-testnet readback receipts, quarantine/retry @@ -54,6 +58,7 @@ import { buildBtdRegistrySnapshot, buildSupabaseStagingTestnetProjectionReadback, buildSourceToSharesProof, + buildBridgeReadinessResearchPosture, reconcileLedgerDatabaseProjection, sourceToSharesProofToSettlementConservationCheck, toBtdJsonSafe, diff --git a/packages/btd/__tests__/bridge-readiness.test.ts b/packages/btd/__tests__/bridge-readiness.test.ts new file mode 100644 index 000000000..3bbbc35ee --- /dev/null +++ b/packages/btd/__tests__/bridge-readiness.test.ts @@ -0,0 +1,110 @@ +import { + BRIDGE_READINESS_RESEARCH_PATHS, + assertNoBridgeChainOfRecordAdmission, + bridgeReadinessPostureToPolicySummary, + buildBridgeReadinessResearchPosture, +} from '../src'; + +const issuedAt = '2026-05-21T00:00:00.000Z'; + +describe('bridge readiness research boundaries', () => { + it('records Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future paths as research-only', () => { + const posture = buildBridgeReadinessResearchPosture({ + postureId: 'bridge-readiness-v30-gate7', + issuedAt, + }); + + expect(posture.kind).toBe('btd.bridge_readiness_research_posture'); + expect(posture.records.map((record) => record.path)).toEqual( + BRIDGE_READINESS_RESEARCH_PATHS, + ); + expect(posture.allRequiredPathsCovered).toBe(true); + expect(posture.allNonAdmitted).toBe(true); + expect(posture.activeBtdChainOfRecord).toBe('bitcoin_btd_registry'); + expect(posture.bridgeChainOfRecordTruth).toBe('no_bridge_chain_of_record'); + expect(posture.records.every((record) => record.currentAdmissionState === 'research_only')).toBe( + true, + ); + expect(posture.records.every((record) => record.chainOfRecordAdmitted === false)).toBe( + true, + ); + expect(posture.admissionBlockers.length).toBeGreaterThanOrEqual( + BRIDGE_READINESS_RESEARCH_PATHS.length, + ); + expect(posture.proofRoot).toMatch(/^btd-proof-root:bridge-readiness-posture:/); + }); + + it('keeps policy summaries source-safe and non-authoritative', () => { + const posture = buildBridgeReadinessResearchPosture({ + postureId: 'bridge-readiness-policy-summary', + issuedAt, + }); + const summary = bridgeReadinessPostureToPolicySummary(posture); + + expect(summary).toEqual({ + postureId: 'bridge-readiness-policy-summary', + activeBtdChainOfRecord: 'bitcoin_btd_registry', + bridgeChainOfRecordTruth: 'no_bridge_chain_of_record', + pathCount: 5, + allNonAdmitted: true, + admissionBlockerCount: posture.admissionBlockers.length, + proofRoot: posture.proofRoot, + }); + }); + + it('fails closed if a path attempts chain-of-record admission', () => { + expect(() => + buildBridgeReadinessResearchPosture({ + postureId: 'bridge-readiness-illegal-admission', + records: [ + { + path: 'bsc_opbnb_distribution', + chainOfRecordAdmitted: true, + }, + ], + issuedAt, + }), + ).toThrow(/cannot be current BTD chain-of-record truth/); + }); + + it('fails closed on duplicate paths and secret-looking research text', () => { + expect(() => + buildBridgeReadinessResearchPosture({ + postureId: 'bridge-readiness-duplicate', + records: [ + { path: 'bitvm_execution_bridge' }, + { path: 'bitvm_execution_bridge' }, + ], + issuedAt, + }), + ).toThrow(/Duplicate bridge-readiness research path/); + + expect(() => + buildBridgeReadinessResearchPosture({ + postureId: 'bridge-readiness-secret', + records: [ + { + path: 'binance_web3_wallet_distribution', + summary: 'provider key sb_secret__not-for-proof', + }, + ], + issuedAt, + }), + ).toThrow(/must not contain secret material/); + }); + + it('requires every record to keep non-admission proof posture', () => { + const posture = buildBridgeReadinessResearchPosture({ + postureId: 'bridge-readiness-assertion', + issuedAt, + }); + const mutated = { + ...posture, + allNonAdmitted: false, + }; + + expect(() => assertNoBridgeChainOfRecordAdmission(mutated)).toThrow( + /contains an admitted bridge path/, + ); + }); +}); diff --git a/packages/btd/src/api-boundaries.ts b/packages/btd/src/api-boundaries.ts index 940a120a7..e6dd45571 100644 --- a/packages/btd/src/api-boundaries.ts +++ b/packages/btd/src/api-boundaries.ts @@ -39,6 +39,8 @@ import { assertBtcFeeQuoteActive, buildBtcFeeOperationPosture, } from './btc-fee-operation'; +import type { BridgeReadinessResearchRecordInput } from './bridge-readiness'; +import { buildBridgeReadinessResearchPosture } from './bridge-readiness'; import type { BitcoinNetwork, LedgerNetwork, @@ -436,6 +438,16 @@ export interface BtdSourceToSharesProofInput extends SourceToSharesProofInput { commitToRegistry?: boolean; } +export interface BtdBridgeReadinessResearchInput { + postureId: string; + records?: BridgeReadinessResearchRecordInput[]; + policyRoot?: string; + exchangeSequence: bigint; + actorId?: string; + commitToRegistry?: boolean; + issuedAt?: string; +} + export type BtdDeploymentReadinessAction = | 'deployment_lane' | 'telemetry_event' @@ -549,6 +561,14 @@ export interface BtdSourceToSharesProofSettlement { committed: false; } +export interface BtdBridgeReadinessResearchSettlement { + kind: 'btd_bridge_readiness_research_settlement'; + actorId: string; + posture: ReturnType; + terminalJournalEntry: ReturnType; + committed: false; +} + export interface BtdDeploymentReadinessSettlement { kind: 'btd_deployment_readiness_settlement'; actorId: string; @@ -1294,6 +1314,50 @@ export function buildBtdSourceToSharesProofSettlement( }; } +export function buildBtdBridgeReadinessResearchSettlement( + input: BtdBridgeReadinessResearchInput & { actorId: string }, +): BtdBridgeReadinessResearchSettlement { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { + throw new Error('Bridge-readiness research settlement requires a positive Exchange sequence.'); + } + + const posture = buildBridgeReadinessResearchPosture(input); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-bridge-readiness-research', [ + posture.postureId, + input.exchangeSequence.toString(), + ]), + transactionKind: 'proof_admission', + actorId, + preStateRoot: buildBtdStableId('bridge-readiness-pre-state', [ + posture.activeBtdChainOfRecord, + 'research-only', + ]), + postStateRoot: buildBtdStableId('bridge-readiness-post-state', [ + posture.proofRoot, + posture.bridgeChainOfRecordTruth, + String(posture.allNonAdmitted), + ]), + receiptRoots: [ + posture.proofRoot, + posture.policyRoot, + ...posture.records.map((record) => record.researchRoot), + ], + ledgerAnchorIds: [], + exchangeSequence: input.exchangeSequence, + issuedAt: posture.issuedAt, + }); + + return { + kind: 'btd_bridge_readiness_research_settlement', + actorId, + posture, + terminalJournalEntry, + committed: false, + }; +} + export function buildBtdDeploymentReadinessSettlement( input: BtdDeploymentReadinessInput & { actorId: string }, ): Omit { diff --git a/packages/btd/src/bridge-readiness.ts b/packages/btd/src/bridge-readiness.ts new file mode 100644 index 000000000..3894a7a15 --- /dev/null +++ b/packages/btd/src/bridge-readiness.ts @@ -0,0 +1,511 @@ +import { createHash } from 'crypto'; +import { assertNonEmptyString } from './constants'; + +export const BRIDGE_READINESS_RESEARCH_PATHS = [ + 'bitcoin_taproot_anchor', + 'bitvm_execution_bridge', + 'bsc_opbnb_distribution', + 'binance_web3_wallet_distribution', + 'future_distribution_path', +] as const; + +export type BridgeReadinessResearchPath = (typeof BRIDGE_READINESS_RESEARCH_PATHS)[number]; + +export type BridgeReadinessFeasibility = + | 'research_feasible' + | 'experimental' + | 'unknown' + | 'not_currently_feasible'; + +export type BridgeReadinessRiskKind = + | 'chain_of_record_confusion' + | 'custody_or_wallet_boundary' + | 'contract_security' + | 'settlement_finality' + | 'provider_dependence' + | 'proof_gap' + | 'operational_repair_gap' + | 'liquidity_or_distribution'; + +export interface BridgeReadinessResearchRisk { + riskKind: BridgeReadinessRiskKind; + summary: string; + blockingAdmission: boolean; +} + +export interface BridgeReadinessResearchRecordInput { + path: BridgeReadinessResearchPath; + label?: string; + feasibility?: BridgeReadinessFeasibility; + summary?: string; + risks?: BridgeReadinessResearchRisk[]; + rereviewTriggers?: string[]; + requiredProofBeforeAdmission?: string[]; + requiredPolicyBeforeAdmission?: string[]; + currentNonAdmission?: boolean; + chainOfRecordAdmitted?: boolean; +} + +export interface BridgeReadinessResearchRecord { + kind: 'btd.bridge_readiness_research_record'; + path: BridgeReadinessResearchPath; + label: string; + feasibility: BridgeReadinessFeasibility; + summary: string; + risks: BridgeReadinessResearchRisk[]; + rereviewTriggers: string[]; + requiredProofBeforeAdmission: string[]; + requiredPolicyBeforeAdmission: string[]; + currentNonAdmission: true; + chainOfRecordAdmitted: false; + currentAdmissionState: 'research_only'; + researchRoot: string; +} + +export interface BridgeReadinessResearchPosture { + kind: 'btd.bridge_readiness_research_posture'; + postureId: string; + activeBtdChainOfRecord: 'bitcoin_btd_registry'; + bridgeChainOfRecordTruth: 'no_bridge_chain_of_record'; + records: BridgeReadinessResearchRecord[]; + allRequiredPathsCovered: boolean; + allNonAdmitted: boolean; + admissionBlockers: string[]; + policyRoot: string; + proofRoot: string; + issuedAt: string; +} + +const DEFAULT_BRIDGE_RESEARCH_RECORDS: Record< + BridgeReadinessResearchPath, + Omit< + BridgeReadinessResearchRecordInput, + 'path' | 'currentNonAdmission' | 'chainOfRecordAdmitted' + > +> = { + bitcoin_taproot_anchor: { + label: 'Taproot BTD anchor research', + feasibility: 'research_feasible', + summary: + 'Research path for Bitcoin-native commitments that may later deepen BTD anchoring without changing current chain-of-record truth.', + risks: [ + { + riskKind: 'chain_of_record_confusion', + summary: + 'Operators or readers could mistake an auxiliary Taproot commitment path for current BTD chain-of-record truth.', + blockingAdmission: true, + }, + { + riskKind: 'proof_gap', + summary: + 'Admission requires replayable proof that the anchor binds the same BTD receipt root and does not create a second ownership source.', + blockingAdmission: true, + }, + ], + rereviewTriggers: [ + 'A Taproot anchor proof can be replayed from BTD receipt roots without exposing protected source.', + 'Wallet signer recovery can prepare, sign, broadcast, and observe finality with no server custody.', + ], + requiredProofBeforeAdmission: [ + 'Receipt-root-to-Taproot-commitment replay proof', + 'PSBT/signer/no-custody proof', + 'Reorg and replacement repair proof', + ], + requiredPolicyBeforeAdmission: [ + 'Operator approval policy for value-bearing networks', + 'Reader/depositor disclosure boundary policy', + ], + }, + bitvm_execution_bridge: { + label: 'BitVM execution bridge research', + feasibility: 'experimental', + summary: + 'Research path for future proof-carrying execution commitments; it is not a current BTD ownership, fee, or delivery rail.', + risks: [ + { + riskKind: 'proof_gap', + summary: + 'Execution claims need executable dispute and replay evidence before they can affect BTD settlement.', + blockingAdmission: true, + }, + { + riskKind: 'operational_repair_gap', + summary: + 'Repair, timeout, challenge, and operator-escalation paths are not admitted in the current protocol rail.', + blockingAdmission: true, + }, + ], + rereviewTriggers: [ + 'Executable BitVM proof transcript can be generated from source-safe BTD receipt inputs.', + 'Timeout and challenge states can be represented in ledger/database reconciliation without unlock ambiguity.', + ], + requiredProofBeforeAdmission: [ + 'Execution transcript replay proof', + 'Challenge/timeout repair proof', + 'Source-safe telemetry proof', + ], + requiredPolicyBeforeAdmission: [ + 'Bridge operator responsibility policy', + 'Dispute and repair authority policy', + ], + }, + bsc_opbnb_distribution: { + label: 'BSC/opBNB distribution research', + feasibility: 'unknown', + summary: + 'Research path for future distribution or market reach; it cannot mint, wrap, transfer, or settle current BTD rights.', + risks: [ + { + riskKind: 'contract_security', + summary: + 'Contract, wrapper, and bridge contracts would need audited fail-closed behavior before any rights projection.', + blockingAdmission: true, + }, + { + riskKind: 'chain_of_record_confusion', + summary: + 'A distribution projection could be mistaken for BTD ownership unless the Bitcoin/BTD registry remains authoritative.', + blockingAdmission: true, + }, + { + riskKind: 'liquidity_or_distribution', + summary: + 'Distribution utility cannot outrun deterministic source-to-shares and paid unlock accounting.', + blockingAdmission: true, + }, + ], + rereviewTriggers: [ + 'A wrapped/distribution receipt can prove it is a projection and not BTD chain-of-record ownership.', + 'Ledger reconciliation can quarantine drift between a distribution projection and the BTD registry.', + ], + requiredProofBeforeAdmission: [ + 'Wrapper/projection non-authority proof', + 'Contract audit receipt', + 'Cross-ledger reconciliation and quarantine proof', + ], + requiredPolicyBeforeAdmission: [ + 'Distribution projection disclosure policy', + 'Mainnet operational approval policy', + ], + }, + binance_web3_wallet_distribution: { + label: 'Binance Web3 Wallet distribution research', + feasibility: 'unknown', + summary: + 'Research path for wallet distribution and user experience; it is not current custody, signing, settlement, or ownership authority.', + risks: [ + { + riskKind: 'custody_or_wallet_boundary', + summary: + 'Wallet integration must preserve no-server-custody, signer recovery, and reader/depositor authority boundaries.', + blockingAdmission: true, + }, + { + riskKind: 'provider_dependence', + summary: + 'Provider-specific availability and policy changes cannot become protocol truth without independent fallback evidence.', + blockingAdmission: true, + }, + ], + rereviewTriggers: [ + 'Wallet capability discovery can prove signer, network, address, and session state without secrets.', + 'Provider-specific failures can be represented as blocked-readiness receipts instead of silent unlock failure.', + ], + requiredProofBeforeAdmission: [ + 'Wallet capability and signer recovery proof', + 'Provider outage and fallback proof', + 'No-secret telemetry proof', + ], + requiredPolicyBeforeAdmission: [ + 'Provider boundary disclosure policy', + 'Wallet capability admission policy', + ], + }, + future_distribution_path: { + label: 'Future distribution path research', + feasibility: 'unknown', + summary: + 'Reserved posture for later distribution or bridge candidates; it exists so future research is reviewed before implementation.', + risks: [ + { + riskKind: 'proof_gap', + summary: + 'Unknown future paths have no admitted proof, policy, repair, or disclosure semantics in current Bitcode.', + blockingAdmission: true, + }, + { + riskKind: 'chain_of_record_confusion', + summary: + 'Any future path must start as a projection or research record and cannot become current BTD truth by naming alone.', + blockingAdmission: true, + }, + ], + rereviewTriggers: [ + 'A concrete candidate path has source-safe proof, ledger reconciliation, and operational policy drafts.', + 'A future version explicitly scopes bridge or distribution admission as a promoted protocol change.', + ], + requiredProofBeforeAdmission: [ + 'Candidate-specific proof-family definition', + 'Ledger reconciliation proof', + 'Disclosure and no-secret telemetry proof', + ], + requiredPolicyBeforeAdmission: [ + 'Future bridge admission policy', + 'Operator approval and rollback policy', + ], + }, +}; + +export function buildBridgeReadinessResearchPosture(input: { + postureId: string; + records?: BridgeReadinessResearchRecordInput[]; + policyRoot?: string; + issuedAt?: string; +}): BridgeReadinessResearchPosture { + const postureId = assertNonEmptyString(input.postureId, 'postureId'); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const policyRoot = assertSourceSafeBridgeText( + input.policyRoot ?? stableBridgeReadinessRoot('bridge-readiness-policy', [postureId]), + 'policyRoot', + ); + const overrides = new Map(); + + for (const record of input.records ?? []) { + assertBridgeReadinessPath(record.path); + if (overrides.has(record.path)) { + throw new Error(`Duplicate bridge-readiness research path: ${record.path}.`); + } + overrides.set(record.path, record); + } + + const records = BRIDGE_READINESS_RESEARCH_PATHS.map((path) => + buildBridgeReadinessResearchRecord({ + path, + ...DEFAULT_BRIDGE_RESEARCH_RECORDS[path], + ...(overrides.get(path) ?? {}), + }), + ); + const allRequiredPathsCovered = requiredBridgePathsCovered(records); + const admissionBlockers = records.flatMap((record) => + record.risks + .filter((risk) => risk.blockingAdmission) + .map((risk) => `${record.path}:${risk.riskKind}`), + ); + const allNonAdmitted = records.every( + (record) => record.currentNonAdmission === true && record.chainOfRecordAdmitted === false, + ); + const proofRoot = stableBridgeReadinessRoot('bridge-readiness-posture', [ + postureId, + policyRoot, + issuedAt, + ...records.map((record) => record.researchRoot), + ...admissionBlockers, + ]); + + const posture: BridgeReadinessResearchPosture = { + kind: 'btd.bridge_readiness_research_posture', + postureId, + activeBtdChainOfRecord: 'bitcoin_btd_registry', + bridgeChainOfRecordTruth: 'no_bridge_chain_of_record', + records, + allRequiredPathsCovered, + allNonAdmitted, + admissionBlockers, + policyRoot, + proofRoot, + issuedAt, + }; + + return assertNoBridgeChainOfRecordAdmission(posture); +} + +export function assertNoBridgeChainOfRecordAdmission( + posture: BridgeReadinessResearchPosture, +): BridgeReadinessResearchPosture { + if (posture.kind !== 'btd.bridge_readiness_research_posture') { + throw new Error('Invalid bridge-readiness research posture kind.'); + } + if (posture.activeBtdChainOfRecord !== 'bitcoin_btd_registry') { + throw new Error('Bridge-readiness posture must keep the Bitcoin BTD registry as chain-of-record.'); + } + if (posture.bridgeChainOfRecordTruth !== 'no_bridge_chain_of_record') { + throw new Error('Bridge-readiness posture must not admit a bridge chain of record.'); + } + if (!posture.allRequiredPathsCovered) { + throw new Error('Bridge-readiness posture must cover every required research path.'); + } + if (!posture.allNonAdmitted) { + throw new Error('Bridge-readiness posture contains an admitted bridge path.'); + } + for (const record of posture.records) { + if (record.currentNonAdmission !== true || record.chainOfRecordAdmitted !== false) { + throw new Error(`Bridge-readiness record ${record.path} is not research-only.`); + } + } + + return posture; +} + +export function bridgeReadinessPostureToPolicySummary( + posture: BridgeReadinessResearchPosture, +) { + const checked = assertNoBridgeChainOfRecordAdmission(posture); + + return { + postureId: checked.postureId, + activeBtdChainOfRecord: checked.activeBtdChainOfRecord, + bridgeChainOfRecordTruth: checked.bridgeChainOfRecordTruth, + pathCount: checked.records.length, + allNonAdmitted: checked.allNonAdmitted, + admissionBlockerCount: checked.admissionBlockers.length, + proofRoot: checked.proofRoot, + }; +} + +function buildBridgeReadinessResearchRecord( + input: BridgeReadinessResearchRecordInput, +): BridgeReadinessResearchRecord { + assertBridgeReadinessPath(input.path); + if (input.currentNonAdmission === false) { + throw new Error(`Bridge-readiness path ${input.path} must remain non-admitted in V30.`); + } + if (input.chainOfRecordAdmitted === true) { + throw new Error(`Bridge-readiness path ${input.path} cannot be current BTD chain-of-record truth.`); + } + + const label = assertSourceSafeBridgeText(input.label, `${input.path}.label`); + const summary = assertSourceSafeBridgeText(input.summary, `${input.path}.summary`); + const feasibility = assertBridgeReadinessFeasibility(input.feasibility ?? 'unknown'); + const risks = assertBridgeReadinessRisks(input.path, input.risks ?? []); + const rereviewTriggers = assertSourceSafeList( + input.rereviewTriggers ?? [], + `${input.path}.rereviewTriggers`, + ); + const requiredProofBeforeAdmission = assertSourceSafeList( + input.requiredProofBeforeAdmission ?? [], + `${input.path}.requiredProofBeforeAdmission`, + ); + const requiredPolicyBeforeAdmission = assertSourceSafeList( + input.requiredPolicyBeforeAdmission ?? [], + `${input.path}.requiredPolicyBeforeAdmission`, + ); + if (!risks.some((risk) => risk.blockingAdmission)) { + throw new Error(`Bridge-readiness path ${input.path} requires at least one blocking admission risk.`); + } + if (!rereviewTriggers.length || !requiredProofBeforeAdmission.length) { + throw new Error(`Bridge-readiness path ${input.path} requires rereview triggers and proof requirements.`); + } + + const researchRoot = stableBridgeReadinessRoot('bridge-readiness-record', [ + input.path, + label, + feasibility, + summary, + ...risks.map((risk) => `${risk.riskKind}:${risk.blockingAdmission}:${risk.summary}`), + ...rereviewTriggers, + ...requiredProofBeforeAdmission, + ...requiredPolicyBeforeAdmission, + ]); + + return { + kind: 'btd.bridge_readiness_research_record', + path: input.path, + label, + feasibility, + summary, + risks, + rereviewTriggers, + requiredProofBeforeAdmission, + requiredPolicyBeforeAdmission, + currentNonAdmission: true, + chainOfRecordAdmitted: false, + currentAdmissionState: 'research_only', + researchRoot, + }; +} + +function requiredBridgePathsCovered(records: BridgeReadinessResearchRecord[]): boolean { + const observed = new Set(records.map((record) => record.path)); + + return BRIDGE_READINESS_RESEARCH_PATHS.every((path) => observed.has(path)); +} + +function assertBridgeReadinessPath(path: unknown): BridgeReadinessResearchPath { + if (!BRIDGE_READINESS_RESEARCH_PATHS.includes(path as BridgeReadinessResearchPath)) { + throw new Error(`Unsupported bridge-readiness research path: ${String(path)}.`); + } + + return path as BridgeReadinessResearchPath; +} + +function assertBridgeReadinessFeasibility(value: unknown): BridgeReadinessFeasibility { + if ( + ![ + 'research_feasible', + 'experimental', + 'unknown', + 'not_currently_feasible', + ].includes(value as BridgeReadinessFeasibility) + ) { + throw new Error(`Unsupported bridge-readiness feasibility: ${String(value)}.`); + } + + return value as BridgeReadinessFeasibility; +} + +function assertBridgeReadinessRiskKind(value: unknown): BridgeReadinessRiskKind { + if ( + ![ + 'chain_of_record_confusion', + 'custody_or_wallet_boundary', + 'contract_security', + 'settlement_finality', + 'provider_dependence', + 'proof_gap', + 'operational_repair_gap', + 'liquidity_or_distribution', + ].includes(value as BridgeReadinessRiskKind) + ) { + throw new Error(`Unsupported bridge-readiness risk kind: ${String(value)}.`); + } + + return value as BridgeReadinessRiskKind; +} + +function assertBridgeReadinessRisks( + path: BridgeReadinessResearchPath, + risks: BridgeReadinessResearchRisk[], +): BridgeReadinessResearchRisk[] { + if (!Array.isArray(risks) || risks.length === 0) { + throw new Error(`Bridge-readiness path ${path} requires at least one risk.`); + } + + return risks.map((risk, index) => ({ + riskKind: assertBridgeReadinessRiskKind(risk.riskKind), + summary: assertSourceSafeBridgeText(risk.summary, `${path}.risks.${index}.summary`), + blockingAdmission: Boolean(risk.blockingAdmission), + })); +} + +function assertSourceSafeList(values: string[], label: string): string[] { + if (!Array.isArray(values)) { + throw new Error(`${label} must be an array.`); + } + + return values.map((value, index) => assertSourceSafeBridgeText(value, `${label}.${index}`)); +} + +function assertSourceSafeBridgeText(value: unknown, label: string): string { + const text = assertNonEmptyString(value, label); + if (/(sk-(?:proj-)?[A-Za-z0-9_-]{16,}|sb_secret__|eyJ[a-zA-Z0-9_-]{20,})/u.test(text)) { + throw new Error(`${label} must not contain secret material.`); + } + + return text; +} + +function stableBridgeReadinessRoot(scope: string, parts: string[]): string { + const hash = createHash('sha256').update(parts.join('\u001f')).digest('hex'); + + return `btd-proof-root:${scope}:${hash}`; +} diff --git a/packages/btd/src/index.ts b/packages/btd/src/index.ts index 4c68707ec..c8d4ff5b1 100644 --- a/packages/btd/src/index.ts +++ b/packages/btd/src/index.ts @@ -157,6 +157,7 @@ export function buildGenerationBitcodeAccounting( export * from './bitcoin-fees'; export * from './btc-fee-operation'; export * from './bitcoin-provider'; +export * from './bridge-readiness'; export * from './access'; export * from './allocation'; export * from './ancestry'; diff --git a/scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs b/scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs new file mode 100644 index 000000000..7de34ff70 --- /dev/null +++ b/scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs @@ -0,0 +1,223 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 7 bridge-readiness research boundaries, package posture ownership, non-chain-of-record policy, tests, docs, and workflow readiness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-7-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 7 work must occur on version/v30 or v30/gate-7-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + 'packages/btd/src/bridge-readiness.ts', + 'packages/btd/src/api-boundaries.ts', + 'packages/btd/src/index.ts', + 'packages/btd/__tests__/bridge-readiness.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'uapi/app/api/btd/bridge-readiness-research/route.ts', + 'packages/btd/README.md', + 'uapi/app/terminal/README.md', + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + ]) { + assertCheck(failures, fileExists(root, relativePath), `Missing V30 Gate 7 file: ${relativePath}`); + } + + const bridgeReadiness = read(root, 'packages/btd/src/bridge-readiness.ts'); + const btdBoundary = read(root, 'packages/btd/src/api-boundaries.ts'); + const btdIndex = read(root, 'packages/btd/src/index.ts'); + const btdTest = read(root, 'packages/btd/__tests__/bridge-readiness.test.ts'); + const apiRoute = read(root, 'packages/api/src/routes/btd-crypto.ts'); + const apiTest = read(root, 'packages/api/src/routes/__tests__/btd-crypto.test.ts'); + const uapiRoute = read(root, 'uapi/app/api/btd/bridge-readiness-research/route.ts'); + const btdReadme = read(root, 'packages/btd/README.md'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + for (const symbol of [ + 'BridgeReadinessResearchPosture', + 'BridgeReadinessResearchRecord', + 'BRIDGE_READINESS_RESEARCH_PATHS', + 'buildBridgeReadinessResearchPosture', + 'assertNoBridgeChainOfRecordAdmission', + 'bridgeReadinessPostureToPolicySummary', + 'bitcoin_taproot_anchor', + 'bitvm_execution_bridge', + 'bsc_opbnb_distribution', + 'binance_web3_wallet_distribution', + 'future_distribution_path', + 'no_bridge_chain_of_record', + 'bitcoin_btd_registry', + ]) { + assertCheck(failures, bridgeReadiness.includes(symbol), `Bridge-readiness primitive is missing ${symbol}.`); + } + + for (const testEvidence of [ + 'Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future paths', + 'keeps policy summaries source-safe and non-authoritative', + 'fails closed if a path attempts chain-of-record admission', + 'secret-looking research text', + 'requires every record to keep non-admission proof posture', + ]) { + assertCheck(failures, btdTest.includes(testEvidence), `Bridge-readiness tests must cover ${testEvidence}.`); + } + + for (const boundaryEvidence of [ + 'BtdBridgeReadinessResearchInput', + 'BtdBridgeReadinessResearchSettlement', + 'buildBtdBridgeReadinessResearchSettlement', + 'terminal-btd-bridge-readiness-research', + 'proof_admission', + ]) { + assertCheck(failures, btdBoundary.includes(boundaryEvidence), `BTD API boundary must include ${boundaryEvidence}.`); + } + assertCheck(failures, btdIndex.includes("export * from './bridge-readiness'"), 'BTD package index must export bridge-readiness primitives.'); + + for (const apiEvidence of [ + 'buildPostBtdBridgeReadinessResearchRoute', + '/btd/bridge-readiness-research', + ]) { + assertCheck(failures, apiRoute.includes(apiEvidence), `BTD API route must include ${apiEvidence}.`); + assertCheck(failures, apiTest.includes(apiEvidence), `BTD API tests must cover ${apiEvidence}.`); + } + assertCheck( + failures, + apiRoute.includes('postBtdBridgeReadinessResearch'), + 'BTD API route must export postBtdBridgeReadinessResearch.', + ); + assertCheck( + failures, + uapiRoute.includes('postBtdBridgeReadinessResearch'), + 'Next route must expose postBtdBridgeReadinessResearch.', + ); + + assertCheck( + failures, + btdReadme.includes('bridge-readiness research boundaries') && + btdReadme.includes('research-only'), + 'BTD README must document bridge-readiness research boundaries.', + ); + assertCheck( + failures, + terminalReadme.includes('Bridge-readiness research evidence') && + terminalReadme.includes('no_bridge_chain_of_record'), + 'Terminal README must document bridge-readiness research consumption.', + ); + assertCheck( + failures, + spec.includes('Gate 7 bridge-readiness research boundaries') && + spec.includes('no_bridge_chain_of_record'), + 'V30 SPEC must define Gate 7 bridge-readiness boundaries.', + ); + assertCheck( + failures, + delta.includes('Gate 7 implementation centers') && + delta.includes('/btd/bridge-readiness-research'), + 'V30 DELTA must include Gate 7 implementation evidence.', + ); + assertCheck( + failures, + notes.includes('Gate 7 bridge-readiness research notes'), + 'V30 NOTES must include Gate 7 implementation notes.', + ); + assertCheck( + failures, + parity.includes('## Gate 7 Parity') && parity.includes('Gate 7 accepted boundaries'), + 'V30 PARITY must include Gate 7 parity and accepted boundaries.', + ); + assertCheck(failures, packageJson.includes('"check:v30-gate7"'), 'package.json must expose check:v30-gate7.'); + assertCheck( + failures, + gateWorkflow.includes('check-v30-gate7-bridge-readiness-research-boundaries.mjs'), + 'Gate workflow must run the V30 Gate 7 checker.', + ); + + if (failures.length) { + process.stderr.write('V30 Gate 7 bridge-readiness research boundaries check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V30 Gate 7 bridge-readiness research boundaries check passed.\n'); +} + +main(); diff --git a/uapi/app/api/btd/bridge-readiness-research/route.ts b/uapi/app/api/btd/bridge-readiness-research/route.ts new file mode 100644 index 000000000..f835394e6 --- /dev/null +++ b/uapi/app/api/btd/bridge-readiness-research/route.ts @@ -0,0 +1,3 @@ +import { postBtdBridgeReadinessResearch } from '@bitcode/api'; + +export const POST = postBtdBridgeReadinessResearch; diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 291be8367..4500e4634 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -151,6 +151,13 @@ evidence, and a reconciliation-compatible conservation check. Operators should read no-overpayment and no-underpayment separately so overpaid, underpaid, and drifted settlements are repairable without exposing protected AssetPack source. +Bridge-readiness research evidence should also enter Terminal through the BTD +package boundary. Taproot, BitVM, BSC/opBNB, Binance Web3 Wallet, and future +distribution paths are visible only as research posture: each path names +feasibility, risks, rereview triggers, required proof, and required policy, and +the selected-activity detail must preserve `no_bridge_chain_of_record` as the +current `$BTD` truth until a future promoted spec admits otherwise. + The Organization Authority section is the selected-activity permission explainer. It projects registry-derived organization role, explicit grants, wallet binding, owner-read or licensed-read access, settlement state, From 0791894c1cddd7694678c90c42f6cf177382724f Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 19:45:31 -0300 Subject: [PATCH 09/15] V30 Gate 8: Add protocol telemetry proof hooks Adds package-owned BTD protocol telemetry envelopes, source-safe telemetry records, and proof hooks for receipts, BTC fee states, ledger projections, source-to-shares proofs, and bridge-readiness posture. Exposes the JSON-safe /btd/protocol-telemetry boundary, documents Terminal consumption and V30 spec parity, wires the Gate 8 checker into gate quality, and covers the slice with focused BTD/API tests. Proof run: pnpm --filter @bitcode/btd typecheck; pnpm --filter @bitcode/btd test; pnpm --filter @bitcode/api build; pnpm --filter @bitcode/api exec jest --config jest.config.cjs --runTestsByPath src/routes/__tests__/btd-crypto.test.ts --runInBand; pnpm --dir uapi exec tsc --noEmit --pretty false; node scripts/check-v30-gate1-roadmap-and-gating.mjs --skip-branch-check through node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs; node scripts/check-bitcode-spec-family.mjs --version V30 --mode draft --current-target V29; node scripts/check-bitcode-canonical-inputs.mjs --current-target V29; node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V29 --draft-target V30; git diff --check; git diff --cached --check. --- .github/workflows/bitcode-gate-quality.yml | 1 + BITCODE_SPEC_V30.md | 28 +- BITCODE_SPEC_V30_DELTA.md | 18 + BITCODE_SPEC_V30_NOTES.md | 20 + BITCODE_SPEC_V30_PARITY_MATRIX.md | 21 +- package.json | 1 + .../src/routes/__tests__/btd-crypto.test.ts | 90 ++++ packages/api/src/routes/btd-crypto.ts | 38 ++ packages/btd/README.md | 5 + packages/btd/__tests__/telemetry.test.ts | 190 ++++++++ packages/btd/src/api-boundaries.ts | 76 +++- packages/btd/src/telemetry.ts | 414 ++++++++++++++++++ ...0-gate8-protocol-telemetry-proof-hooks.mjs | 224 ++++++++++ uapi/app/api/btd/protocol-telemetry/route.ts | 3 + uapi/app/terminal/README.md | 9 + 15 files changed, 1135 insertions(+), 3 deletions(-) create mode 100644 packages/btd/__tests__/telemetry.test.ts create mode 100644 scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs create mode 100644 uapi/app/api/btd/protocol-telemetry/route.ts diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index f88313a9f..879087698 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -86,6 +86,7 @@ jobs: node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs --skip-branch-check node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs --skip-branch-check node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs --skip-branch-check + node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index 7d78fe96e..f52edad3f 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -205,7 +205,7 @@ V30 closes through ten gates: 5. **Gate 5: Testnet Ledger Projection Hardening** hardens ledger/database/object-storage projection, repair classes, and staging-testnet readback. 6. **Gate 6: Source-To-Shares Proof Cleanup** cleans contribution measurement, settlement conservation, zero-cell/refit tail, ancestry, and no-overpayment/no-underpayment proof. 7. **Gate 7: Bridge Readiness Research Boundaries** records bridge research without admitting any bridge as chain-of-record truth. -8. **Gate 8: Protocol Telemetry And Proof Hooks** adds source-safe telemetry and proof hooks for receipts, fee states, projection, and source-to-shares facts. +8. **Gate 8: Protocol Telemetry And Proof Hooks** adds source-safe telemetry and proof hooks for receipts, fee states, projection, source-to-shares facts, and bridge-readiness posture. 9. **Gate 9: Interface Integration And Regression Proof** proves current interfaces consume package-owned objects without V29 behavior regression. 10. **Gate 10: V30 Promotion Readiness** validates local/staging proof, generated artifacts, V30 promotion workflow support, and post-promotion V30 active / V31 draft posture. @@ -262,6 +262,31 @@ Gate 7 bridge-readiness research boundaries: research evidence, but they must fail closed on any payload attempting to set `chainOfRecordAdmitted` or to mark a bridge as current BTD truth. +Gate 8 Protocol telemetry proof hooks: + +- `BtdProtocolTelemetryEnvelope` is the package-owned source-safe carrier for + Protocol/BTD observability that V32 provation and V35 documentation can + replay without reading protected source or secrets. +- `BtdProtocolTelemetryRecord` rows cover exactly these V30 subjects: + `btd_receipt`, `btc_fee_state`, `ledger_projection`, + `source_to_shares_proof`, and `bridge_readiness_posture`. +- `BtdProtocolProofHook` binds each record to theorem ids, replay step ids, + witness artifact paths, optional generated artifact paths, the evidence root, + and the telemetry root. +- Telemetry events must match subject kinds; a BTC fee event cannot be emitted + as a receipt, a ledger projection cannot be emitted as a bridge posture, and + every mismatch fails closed. +- Telemetry metadata is scalar and source-safe. Payloads with protected source, + private source text, API keys, service-role keys, JWT-looking secrets, or + private keys fail closed before becoming Terminal, API, or generated proof + evidence. +- The BTD API exposes `/btd/protocol-telemetry` as the source-safe boundary for + these records. It returns a Terminal journal `proof_admission` entry and does + not commit generated proof artifacts or source-bearing material. +- Gate 8 creates the generated-artifact inventory slot + `.bitcode/v30-protocol-telemetry-proof-hooks.json`; promotion may generate + it only from source-safe telemetry/proof-hook facts. + ## V30 whole Bitcode operator chain The V30 Terminal operator chain is: @@ -783,6 +808,7 @@ V30 continues operator-quality proof: Terminal workflow claims must be backed by | `.bitcode/v30-spec-family-report.json` | yes | yes | validates the hand-authored V30 family shape | | `.bitcode/v30-canonical-input-report.json` | yes | yes | records canonical input closure for active V29 plus V30 draft | | `.bitcode/v30-canon-posture-drift-report.json` | gate-dependent | yes | proves runtime/docs active/draft posture | +| `.bitcode/v30-protocol-telemetry-proof-hooks.json` | gate-dependent | yes | records source-safe Protocol telemetry and proof-hook inventory for provation/documentation | | `BITCODE_SPEC_V30_PROVEN.md` | no | yes | generated proof appendix for promoted V30 | ### V30 specifying generated artifacts diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 4a7f57ef8..376b6a1ed 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -277,6 +277,24 @@ Closure acceptance: - telemetry avoids protected source and secrets; - proof hooks are compatible with V32 provation and V35 documentation/observability work. +Gate 8 implementation centers: + +- `packages/btd/src/telemetry.ts` owns `BtdProtocolTelemetryEnvelope`, + `BtdProtocolTelemetryRecord`, `BtdProtocolProofHook`, source-safety checks, + event/subject matching, and V32/V35 proof compatibility markers. +- `packages/btd/src/api-boundaries.ts` owns + `buildBtdProtocolTelemetrySettlement`, binding telemetry envelopes into a + Terminal journal `proof_admission` row without committing source-bearing + artifacts. +- `packages/api/src/routes/btd-crypto.ts` and + `/btd/protocol-telemetry` expose the JSON-safe route boundary. +- `packages/btd/__tests__/telemetry.test.ts` and the BTD crypto route tests + prove typed emission, source/secret rejection, proof-hook replay facts, and + route JSON safety. +- `.bitcode/v30-protocol-telemetry-proof-hooks.json` is reserved as a + generated source-safe inventory artifact for promotion proof; it is not a + protected-source carrier. + ### Gate 9: Interface Integration And Regression Proof Gate 9 proves existing interfaces can consume the hardened Protocol/BTD rails. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index 7788418bd..5e4ad913d 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -231,6 +231,26 @@ No Gate 7 code may mint, wrap, transfer, settle, or unlock BTD through a bridge. The only current chain-of-record posture is `bitcoin_btd_registry` plus `no_bridge_chain_of_record`. +## Gate 8 Protocol telemetry notes + +Gate 8 turns Protocol/BTD observability into package-owned typed telemetry +instead of leaving receipts, fee states, ledger projections, source-to-shares +proofs, and bridge-readiness posture as unrelated payload fragments. + +The accepted implementation is `BtdProtocolTelemetryEnvelope` in +`packages/btd/src/telemetry.ts`. It contains source-safe telemetry records and +`BtdProtocolProofHook` rows that name theorem ids, replay step ids, witness +artifact paths, generated artifact paths, evidence roots, and telemetry roots. +The envelope is compatible with V32 provation and V35 documentation/ +observability because it carries replayable source-safe proof facts without +requiring protected source. + +Gate 8 rejects event/subject mismatches and secret-shaped metadata before a row +can reach Terminal, API, generated proof, or persistence surfaces. The API +boundary exposes `/btd/protocol-telemetry` as a JSON-safe proof-admission route; +it does not commit source-bearing artifacts, and it does not replace existing +crypto telemetry rows used for deployment readiness health. + ## Gate 1 working notes Gate 1 is complete only when the V30 family exists, validates in draft mode over active V29, and makes the roadmap truthful enough to drive V31 through V37 without stale V27/V28/V29 posture. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index 1f6fe3ae6..fdf662962 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -61,7 +61,7 @@ No `_legacy/` source is active source truth. | Testnet ledger projection hardening | Gate 5 | `packages/btd/src/reconciliation.ts`, API route tests, asset-pack harness evidence, Terminal journal reconciliation UI/tests, gate checker | drafted | Ledger/database/object-storage/private facts are distinct; staging-testnet readback is secret-free; drift, quarantine, retry, and unlock blocking are tested. | | Source-to-shares proof cleanup | Gate 6 | `packages/btd/src/source-to-shares.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Measurement contribution, fee allocation, zero-cell/refit tail, ancestry evidence, and conservation invariants are testable. | | Bridge-readiness research boundaries | Gate 7 | `packages/btd/src/bridge-readiness.ts`, BTD/API tests, route boundary, docs, gate checker | drafted | Bridge paths are typed research-only records until admitted by explicit future proof and policy. | -| Protocol telemetry/proof hooks | Gate 8 | telemetry schema, proof hooks, generated-artifact inventory, tests | pending | Receipts, fee states, projections, and source-to-shares facts emit source-safe telemetry and proof hooks. | +| Protocol telemetry/proof hooks | Gate 8 | `packages/btd/src/telemetry.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Receipts, fee states, projections, source-to-shares proofs, and bridge-readiness posture emit source-safe telemetry and proof hooks. | | Interface integration regression | Gate 9 | Terminal/API/MCP/ChatGPT App adapters and tests | pending | Existing interfaces consume package-owned objects without regressing V29 behavior. | | Promotion readiness | Gate 10 | V30 promotion workflow, generated `.bitcode/v30-*`, `BITCODE_SPEC_V30_PROVEN.md` | pending | `version/v30` can promote to `main` only after all V30 checks pass and promotion automation can commit generated canon. | @@ -210,6 +210,25 @@ No `_legacy/` source is active source truth. - Gate 7 may expose source-safe research posture to Terminal/API callers for operator review. - Gate 7 does not promote V30 or change the active canon pointer. +## Gate 8 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| Protocol telemetry is package-owned | `packages/btd/src/telemetry.ts`, `packages/btd/src/index.ts` | drafted | +| Receipt, BTC fee, ledger projection, source-to-shares, and bridge-readiness subjects are typed | `BTD_PROTOCOL_TELEMETRY_SUBJECT_KINDS`, `packages/btd/__tests__/telemetry.test.ts` | drafted | +| Telemetry rows and proof hooks reject protected source and secrets | `sourceSafety`, metadata source-safety tests | drafted | +| Proof hooks carry theorem, replay, witness, generated artifact, evidence, and telemetry roots | `BtdProtocolProofHook`, `buildBtdProtocolProofHook`, focused tests | drafted | +| API and Terminal boundary expose JSON-safe proof-admission telemetry | `buildBtdProtocolTelemetrySettlement`, `buildPostBtdProtocolTelemetryRoute`, `uapi/app/api/btd/protocol-telemetry/route.ts` | drafted | +| Gate checker protects telemetry/proof-hook boundaries | `scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs`, `pnpm run check:v30-gate8`, gate-quality workflow | drafted | + +## Gate 8 accepted boundaries + +- Gate 8 does not expose protected source, prompt bodies, private source text, private keys, service-role keys, OpenAI keys, JWT-looking secrets, or database passwords in telemetry. +- Gate 8 does not replace deployment-readiness crypto telemetry persistence; it adds Protocol/BTD source-safe proof hooks that later V32 and V35 work can consume. +- Gate 8 does not generate promotion artifacts yet; it reserves `.bitcode/v30-protocol-telemetry-proof-hooks.json` as a source-safe generated inventory. +- Gate 8 may expose telemetry/proof hooks to Terminal/API callers for operator review. +- Gate 8 does not promote V30 or change the active canon pointer. + ## completion condition Gate 1 is complete when the V30 draft family validates, `check:v30-gate1` passes, workflow posture is V30-aware, README and roadmap reflect V30 initiation, V31-V37 scopes are current enough to guide future gates, diff hygiene passes, and the gate branch is committed and pushed for review into `version/v30`. diff --git a/package.json b/package.json index 584b08467..fea2ea106 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "check:v30-gate5": "node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs", "check:v30-gate6": "node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs", "check:v30-gate7": "node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs", + "check:v30-gate8": "node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/api/src/routes/__tests__/btd-crypto.test.ts b/packages/api/src/routes/__tests__/btd-crypto.test.ts index 5301b09e3..2ea841460 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -25,9 +25,11 @@ import { buildBtdLicensedReadRevenueSettlement, buildBtdMintDraft, buildBtdOrganizationInterfaceAuthorityDecision, + buildBtdProtocolTelemetrySettlement, buildBtdReadAccessDecision, buildBtdSourceToSharesProofSettlement, buildBtdTerminalJournalSettlement, + buildBtdProtocolTelemetryRecord, buildBtcFeeQuote, createBtdMeasureMintState, } from '@bitcode/btd'; @@ -43,6 +45,7 @@ import { buildPostBtdLicensedReadRevenueRoute, buildPostBtdMintDraftRoute, buildPostBtdOrganizationInterfaceAuthorityRoute, + buildPostBtdProtocolTelemetryRoute, buildPostBtdReadAccessRoute, buildPostBtdSourceToSharesProofRoute, buildPostBtdTerminalJournalRoute, @@ -217,6 +220,45 @@ function bridgeReadinessResearchBody(overrides: Record = {}) { }; } +function protocolTelemetryBody(overrides: Record = {}) { + const telemetry = { + event: 'btd.source_to_shares_proof.emitted' as const, + subjectKind: 'source_to_shares_proof' as const, + subjectId: 'source-to-shares-api-1', + root: 'source-to-shares-api-root', + receiptRoot: 'source-to-shares-api-receipt-root', + proofRoot: 'source-to-shares-api-proof-root', + artifactPath: '.bitcode/source-to-shares-api-proof.json', + metadata: { + sourceSafe: true, + settlementAdmissible: true, + }, + issuedAt, + }; + const record = buildBtdProtocolTelemetryRecord(telemetry); + + return { + telemetry: [telemetry], + proofHooks: [ + { + proofFamily: 'source_to_shares' as const, + subjectKind: 'source_to_shares_proof' as const, + subjectId: 'source-to-shares-api-1', + evidenceRoot: 'source-to-shares-api-root', + telemetryRoot: record.telemetryRoot, + theoremIds: ['source-safe', 'settlement-conserved'], + replayStepIds: ['emit-telemetry', 'bind-source-to-shares-proof'], + witnessArtifactPaths: ['.bitcode/source-to-shares-api-proof.json'], + generatedArtifactPath: '.bitcode/generated/source-to-shares-api-proof.json', + issuedAt, + }, + ], + exchangeSequence: '20', + issuedAt, + ...overrides, + }; +} + describe('BTD crypto API builders', () => { it('builds a deterministic mint draft from accepted Read-Fit semantic units', () => { const draft = buildBtdMintDraft(mintDraftInput()); @@ -1002,6 +1044,32 @@ describe('BTD crypto API builders', () => { expect(settlement.terminalJournalEntry.receiptRoots).toContain(settlement.posture.proofRoot); }); + it('builds Protocol telemetry settlements with source-safe proof hooks', () => { + const settlement = buildBtdProtocolTelemetrySettlement({ + actorId: 'user-1', + ...protocolTelemetryBody(), + exchangeSequence: 20n, + } as any); + + expect(settlement.kind).toBe('btd_protocol_telemetry_settlement'); + expect(settlement.committed).toBe(false); + expect(settlement.envelope.compatibleWith).toEqual(['V32', 'V35']); + expect(settlement.envelope.sourceSafety.sourceSafe).toBe(true); + expect(settlement.envelope.telemetry[0]).toMatchObject({ + event: 'btd.source_to_shares_proof.emitted', + subjectKind: 'source_to_shares_proof', + }); + expect(settlement.envelope.telemetry[0].sourceSafety.containsProtectedSource).toBe(false); + expect(settlement.envelope.proofHooks[0]).toMatchObject({ + proofFamily: 'source_to_shares', + subjectKind: 'source_to_shares_proof', + }); + expect(settlement.terminalJournalEntry.transactionKind).toBe('proof_admission'); + expect(settlement.terminalJournalEntry.receiptRoots).toContain( + settlement.envelope.telemetryRoot, + ); + }); + it('builds deployment readiness, telemetry, and upgrade settlements', () => { const readiness = buildBtdDeploymentReadinessSettlement({ actorId: 'user-1', @@ -1592,6 +1660,28 @@ describe('BTD crypto API builders', () => { expect(body.terminalJournalEntry.exchangeSequence).toBe('19'); }); + it('returns JSON-safe Protocol telemetry proof hooks from the route boundary', async () => { + const route = buildPostBtdProtocolTelemetryRoute({ + resolveAuthenticatedUser: async () => ({ userId: 'user-1' }), + }); + const response = await route( + new Request('https://bitcode.test/api/btd/protocol-telemetry', { + method: 'POST', + body: JSON.stringify(protocolTelemetryBody()), + }), + ); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body.kind).toBe('btd_protocol_telemetry_settlement'); + expect(body.committed).toBe(false); + expect(body.envelope.compatibleWith).toEqual(['V32', 'V35']); + expect(body.envelope.sourceSafety.containsSecret).toBe(false); + expect(body.envelope.telemetry[0].event).toBe('btd.source_to_shares_proof.emitted'); + expect(body.envelope.proofHooks[0].proofFamily).toBe('source_to_shares'); + expect(body.terminalJournalEntry.exchangeSequence).toBe('20'); + }); + it('returns JSON-safe deployment readiness settlements and persists telemetry or upgrades', async () => { const insertCryptoTelemetryEvent = jest.fn(async (row) => ({ event: row.event, diff --git a/packages/api/src/routes/btd-crypto.ts b/packages/api/src/routes/btd-crypto.ts index eca85c4ec..106dc8728 100644 --- a/packages/api/src/routes/btd-crypto.ts +++ b/packages/api/src/routes/btd-crypto.ts @@ -26,6 +26,8 @@ import { type BtdMintDraft, type BtdMintDraftInput, type BtdOrganizationInterfaceAuthorityRouteInput, + type BtdProtocolTelemetryBoundaryInput, + type BtdProtocolTelemetrySettlement, type BtdReadAccessInput, type BtdReadAccessDecision, type BtdReadLicense, @@ -49,6 +51,7 @@ import { buildBtdLicensedReadRevenueSettlement, buildBtdMintDraft, buildBtdOrganizationInterfaceAuthorityDecision, + buildBtdProtocolTelemetrySettlement, buildBtdReadAccessDecision, buildBtdRegistrySnapshot, buildBtdSourceToSharesProofSettlement, @@ -72,6 +75,7 @@ export { buildBtdLicensedReadRevenueSettlement, buildBtdMintDraft, buildBtdOrganizationInterfaceAuthorityDecision, + buildBtdProtocolTelemetrySettlement, buildBtdReadAccessDecision, buildBtdRegistrySnapshot, buildBtdSourceToSharesProofSettlement, @@ -638,6 +642,39 @@ export function buildPostBtdBridgeReadinessResearchRoute(options: BtdRouteOption }); } +export function buildPostBtdProtocolTelemetryRoute(options: BtdRouteOptions = {}) { + return traceRoute('/btd/protocol-telemetry', async (request: Request) => { + const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( + request, + ); + if (!user) { + return createJsonResponse({ error: 'Unauthorized' }, 401); + } + + let body: Omit & { + exchangeSequence: string | number; + }; + try { + body = await request.json(); + } catch { + return createJsonResponse({ error: 'Invalid JSON body' }, 400); + } + + let settlement: BtdProtocolTelemetrySettlement; + try { + settlement = buildBtdProtocolTelemetrySettlement({ + ...body, + actorId: user.userId, + exchangeSequence: parseBtdRequiredBigInt(body.exchangeSequence, 'exchangeSequence'), + }); + } catch (error) { + return createJsonResponse({ error: toBadRequestMessage(error) }, 400); + } + + return createJsonResponse(toJsonSafe(settlement)); + }); +} + export function buildPostBtdDeploymentReadinessRoute(options: BtdRouteOptions = {}) { return traceRoute('/btd/deployment-readiness', async (request: Request) => { const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( @@ -699,6 +736,7 @@ export const postBtdLedgerDatabaseReconciliation = buildPostBtdLedgerDatabaseReconciliationRoute(); export const postBtdSourceToSharesProof = buildPostBtdSourceToSharesProofRoute(); export const postBtdBridgeReadinessResearch = buildPostBtdBridgeReadinessResearchRoute(); +export const postBtdProtocolTelemetry = buildPostBtdProtocolTelemetryRoute(); export const postBtdDeploymentReadiness = buildPostBtdDeploymentReadinessRoute(); function toBadRequestMessage(error: unknown): string { diff --git a/packages/btd/README.md b/packages/btd/README.md index b493c7a0b..8ac9c7fc0 100644 --- a/packages/btd/README.md +++ b/packages/btd/README.md @@ -23,6 +23,10 @@ This package owns: Binance Web3 Wallet, and future distribution paths; every bridge posture is research-only and cannot become current `$BTD` chain-of-record truth without explicit future proof and policy admission +- Protocol telemetry proof hooks through `BtdProtocolTelemetryEnvelope`, + source-safe `BtdProtocolTelemetryRecord` rows, and + `BtdProtocolProofHook` bindings for receipts, BTC fee states, ledger + projections, source-to-shares proofs, and bridge-readiness posture - ledger/database/object-storage projection reconciliation, including deterministic repair classes, source-safe object artifact roots, secret-free Supabase staging-testnet readback receipts, quarantine/retry @@ -59,6 +63,7 @@ import { buildSupabaseStagingTestnetProjectionReadback, buildSourceToSharesProof, buildBridgeReadinessResearchPosture, + buildBtdProtocolTelemetryEnvelope, reconcileLedgerDatabaseProjection, sourceToSharesProofToSettlementConservationCheck, toBtdJsonSafe, diff --git a/packages/btd/__tests__/telemetry.test.ts b/packages/btd/__tests__/telemetry.test.ts new file mode 100644 index 000000000..60482780c --- /dev/null +++ b/packages/btd/__tests__/telemetry.test.ts @@ -0,0 +1,190 @@ +import { + buildBtdProtocolProofHook, + buildBtdProtocolTelemetryEnvelope, + buildBtdProtocolTelemetryRecord, + type BtdProtocolProofHookFamily, + type BtdProtocolTelemetryEvent, + type BtdProtocolTelemetryInput, + type BtdProtocolTelemetrySubjectKind, +} from '../src/telemetry'; + +const issuedAt = '2026-05-21T00:00:00.000Z'; + +const subjects: Array<{ + event: BtdProtocolTelemetryEvent; + subjectKind: BtdProtocolTelemetrySubjectKind; + proofFamily: BtdProtocolProofHookFamily; + subjectId: string; + root: string; +}> = [ + { + event: 'btd.receipt.emitted', + subjectKind: 'btd_receipt', + proofFamily: 'btd_receipt', + subjectId: 'receipt-telemetry-1', + root: 'receipt-root-1', + }, + { + event: 'btd.btc_fee_state.emitted', + subjectKind: 'btc_fee_state', + proofFamily: 'btc_fee_state', + subjectId: 'btc-fee-telemetry-1', + root: 'btc-fee-root-1', + }, + { + event: 'btd.ledger_projection.emitted', + subjectKind: 'ledger_projection', + proofFamily: 'ledger_projection', + subjectId: 'ledger-projection-telemetry-1', + root: 'ledger-projection-root-1', + }, + { + event: 'btd.source_to_shares_proof.emitted', + subjectKind: 'source_to_shares_proof', + proofFamily: 'source_to_shares', + subjectId: 'source-to-shares-telemetry-1', + root: 'source-to-shares-root-1', + }, + { + event: 'btd.bridge_readiness_posture.emitted', + subjectKind: 'bridge_readiness_posture', + proofFamily: 'bridge_readiness', + subjectId: 'bridge-readiness-telemetry-1', + root: 'bridge-readiness-root-1', + }, +]; + +function telemetryInput( + subject: (typeof subjects)[number], +): BtdProtocolTelemetryInput { + return { + event: subject.event, + subjectKind: subject.subjectKind, + subjectId: subject.subjectId, + root: subject.root, + receiptRoot: `${subject.root}-receipt`, + proofRoot: `${subject.root}-proof`, + ledgerAnchorId: + subject.subjectKind === 'ledger_projection' ? 'ledger-anchor-telemetry-1' : undefined, + artifactPath: `.bitcode/${subject.subjectKind}.json`, + metadata: { + sourceSafe: true, + subjectKind: subject.subjectKind, + }, + issuedAt, + }; +} + +describe('Protocol telemetry and proof hooks', () => { + it('emits source-safe telemetry and proof hooks for receipts, fees, projections, shares, and bridges', () => { + const telemetry = subjects.map((subject) => + buildBtdProtocolTelemetryRecord(telemetryInput(subject)), + ); + const envelope = buildBtdProtocolTelemetryEnvelope({ + telemetry: subjects.map(telemetryInput), + proofHooks: subjects.map((subject, index) => ({ + proofFamily: subject.proofFamily, + subjectKind: subject.subjectKind, + subjectId: subject.subjectId, + evidenceRoot: subject.root, + telemetryRoot: telemetry[index].telemetryRoot, + theoremIds: ['source-safe', 'typed-output'], + replayStepIds: ['emit-telemetry', 'bind-proof-hook'], + witnessArtifactPaths: [`.bitcode/${subject.subjectKind}-proof.json`], + generatedArtifactPath: `.bitcode/generated/${subject.subjectKind}-proof.json`, + issuedAt, + })), + issuedAt, + }); + + expect(envelope.kind).toBe('btd.protocol_telemetry_envelope'); + expect(envelope.telemetry).toHaveLength(5); + expect(envelope.proofHooks).toHaveLength(5); + expect(envelope.compatibleWith).toEqual(['V32', 'V35']); + expect(envelope.sourceSafety).toEqual({ + sourceSafe: true, + protectedSourceVisible: false, + containsProtectedSource: false, + containsSecret: false, + }); + expect(envelope.proofHooks.map((hook) => hook.proofFamily)).toEqual([ + 'btd_receipt', + 'btc_fee_state', + 'ledger_projection', + 'source_to_shares', + 'bridge_readiness', + ]); + }); + + it('fails closed if an event and subject kind do not match', () => { + expect(() => + buildBtdProtocolTelemetryRecord({ + event: 'btd.btc_fee_state.emitted', + subjectKind: 'btd_receipt', + subjectId: 'receipt-mismatch', + root: 'receipt-root', + }), + ).toThrow(/event does not match subject kind/); + }); + + it('fails closed on secret-looking or protected-source telemetry metadata', () => { + expect(() => + buildBtdProtocolTelemetryRecord({ + event: 'btd.receipt.emitted', + subjectKind: 'btd_receipt', + subjectId: 'receipt-secret', + root: 'receipt-root', + metadata: { + secret: `sb_${'secret'}__not-allowed`, + }, + }), + ).toThrow(/metadata key is not source-safe/); + + expect(() => + buildBtdProtocolTelemetryRecord({ + event: 'btd.receipt.emitted', + subjectKind: 'btd_receipt', + subjectId: 'receipt-source', + root: 'receipt-root', + metadata: { + summary: 'private source text must not be logged', + }, + }), + ).toThrow(/must not contain secrets or protected source/); + }); + + it('requires proof hooks to reference envelope telemetry roots', () => { + expect(() => + buildBtdProtocolTelemetryEnvelope({ + telemetry: [telemetryInput(subjects[0])], + proofHooks: [ + { + proofFamily: 'btd_receipt', + subjectKind: 'btd_receipt', + subjectId: 'receipt-telemetry-1', + evidenceRoot: 'receipt-root-1', + telemetryRoot: 'missing-telemetry-root', + theoremIds: ['source-safe'], + replayStepIds: ['emit-telemetry'], + witnessArtifactPaths: ['.bitcode/receipt-proof.json'], + }, + ], + }), + ).toThrow(/telemetryRoot not present/); + }); + + it('requires proof hooks to carry replayable theorem and witness facts', () => { + expect(() => + buildBtdProtocolProofHook({ + proofFamily: 'btd_receipt', + subjectKind: 'btd_receipt', + subjectId: 'receipt-hook', + evidenceRoot: 'receipt-root', + telemetryRoot: 'telemetry-root', + theoremIds: [], + replayStepIds: ['emit-telemetry'], + witnessArtifactPaths: ['.bitcode/receipt-proof.json'], + }), + ).toThrow(/theoremId/); + }); +}); diff --git a/packages/btd/src/api-boundaries.ts b/packages/btd/src/api-boundaries.ts index e6dd45571..8f209dcf9 100644 --- a/packages/btd/src/api-boundaries.ts +++ b/packages/btd/src/api-boundaries.ts @@ -110,10 +110,16 @@ import type { SourceToSharesProofInput } from './source-to-shares'; import { buildSourceToSharesProof } from './source-to-shares'; import { createBtdSupplyState } from './supply'; import type { + BtdProtocolProofHookInput, + BtdProtocolTelemetryInput, + BtdProtocolTelemetryEnvelope, V27CryptoTelemetryEvent, V27CryptoTelemetryRecord, } from './telemetry'; -import { buildV27CryptoTelemetryRecord } from './telemetry'; +import { + buildBtdProtocolTelemetryEnvelope, + buildV27CryptoTelemetryRecord, +} from './telemetry'; import type { TerminalJournalEntry, TerminalJournalProjection, @@ -448,6 +454,15 @@ export interface BtdBridgeReadinessResearchInput { issuedAt?: string; } +export interface BtdProtocolTelemetryBoundaryInput { + envelopeId?: string; + telemetry: BtdProtocolTelemetryInput[]; + proofHooks: BtdProtocolProofHookInput[]; + exchangeSequence: bigint; + actorId?: string; + issuedAt?: string; +} + export type BtdDeploymentReadinessAction = | 'deployment_lane' | 'telemetry_event' @@ -569,6 +584,14 @@ export interface BtdBridgeReadinessResearchSettlement { committed: false; } +export interface BtdProtocolTelemetrySettlement { + kind: 'btd_protocol_telemetry_settlement'; + actorId: string; + envelope: BtdProtocolTelemetryEnvelope; + terminalJournalEntry: ReturnType; + committed: false; +} + export interface BtdDeploymentReadinessSettlement { kind: 'btd_deployment_readiness_settlement'; actorId: string; @@ -1358,6 +1381,57 @@ export function buildBtdBridgeReadinessResearchSettlement( }; } +export function buildBtdProtocolTelemetrySettlement( + input: BtdProtocolTelemetryBoundaryInput & { actorId: string }, +): BtdProtocolTelemetrySettlement { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { + throw new Error('Protocol telemetry settlement requires a positive Exchange sequence.'); + } + + const envelope = buildBtdProtocolTelemetryEnvelope({ + envelopeId: input.envelopeId, + telemetry: input.telemetry, + proofHooks: input.proofHooks, + issuedAt: input.issuedAt, + }); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-protocol-telemetry', [ + envelope.envelopeId, + input.exchangeSequence.toString(), + ]), + transactionKind: 'proof_admission', + actorId, + preStateRoot: buildBtdStableId('protocol-telemetry-pre-state', [ + envelope.telemetry[0].subjectKind, + envelope.telemetry[0].subjectId, + ]), + postStateRoot: buildBtdStableId('protocol-telemetry-post-state', [ + envelope.telemetryRoot, + envelope.proofRoot, + ]), + receiptRoots: [ + envelope.telemetryRoot, + envelope.proofRoot, + ...envelope.telemetry.map((record) => record.telemetryRoot), + ...envelope.proofHooks.map((hook) => hook.hookRoot), + ], + ledgerAnchorIds: envelope.telemetry + .map((record) => record.ledgerAnchorId) + .filter((ledgerAnchorId): ledgerAnchorId is string => Boolean(ledgerAnchorId)), + exchangeSequence: input.exchangeSequence, + issuedAt: envelope.issuedAt, + }); + + return { + kind: 'btd_protocol_telemetry_settlement', + actorId, + envelope, + terminalJournalEntry, + committed: false, + }; +} + export function buildBtdDeploymentReadinessSettlement( input: BtdDeploymentReadinessInput & { actorId: string }, ): Omit { diff --git a/packages/btd/src/telemetry.ts b/packages/btd/src/telemetry.ts index bbb868320..2ecc7a271 100644 --- a/packages/btd/src/telemetry.ts +++ b/packages/btd/src/telemetry.ts @@ -1,3 +1,4 @@ +import { createHash } from 'crypto'; import { assertNonEmptyString } from './constants'; export const V27_CRYPTO_TELEMETRY_EVENTS = [ @@ -80,3 +81,416 @@ export function buildV27CryptoTelemetryRecord(input: { issuedAt: input.issuedAt ?? new Date().toISOString(), }; } + +export const BTD_PROTOCOL_TELEMETRY_SUBJECT_KINDS = [ + 'btd_receipt', + 'btc_fee_state', + 'ledger_projection', + 'source_to_shares_proof', + 'bridge_readiness_posture', +] as const; + +export type BtdProtocolTelemetrySubjectKind = + (typeof BTD_PROTOCOL_TELEMETRY_SUBJECT_KINDS)[number]; + +export const BTD_PROTOCOL_TELEMETRY_EVENTS = [ + 'btd.receipt.emitted', + 'btd.btc_fee_state.emitted', + 'btd.ledger_projection.emitted', + 'btd.source_to_shares_proof.emitted', + 'btd.bridge_readiness_posture.emitted', +] as const; + +export type BtdProtocolTelemetryEvent = (typeof BTD_PROTOCOL_TELEMETRY_EVENTS)[number]; + +export type BtdProtocolTelemetryMetadataValue = string | number | boolean | null; + +export interface BtdProtocolTelemetrySourceSafety { + sourceSafe: true; + protectedSourceVisible: false; + containsProtectedSource: false; + containsSecret: false; +} + +export interface BtdProtocolTelemetryInput { + telemetryId?: string; + event: BtdProtocolTelemetryEvent; + subjectKind: BtdProtocolTelemetrySubjectKind; + subjectId: string; + root: string; + receiptRoot?: string; + proofRoot?: string; + ledgerAnchorId?: string; + artifactPath?: string; + severity?: V27CryptoTelemetrySeverity; + metadata?: Record; + issuedAt?: string; +} + +export interface BtdProtocolTelemetryRecord { + kind: 'btd.protocol_telemetry_record'; + telemetryId: string; + event: BtdProtocolTelemetryEvent; + subjectKind: BtdProtocolTelemetrySubjectKind; + subjectId: string; + root: string; + receiptRoot?: string; + proofRoot?: string; + ledgerAnchorId?: string; + artifactPath?: string; + severity: V27CryptoTelemetrySeverity; + metadata: Record; + sourceSafety: BtdProtocolTelemetrySourceSafety; + telemetryRoot: string; + issuedAt: string; +} + +export const BTD_PROTOCOL_PROOF_HOOK_FAMILIES = [ + 'btd_receipt', + 'btc_fee_state', + 'ledger_projection', + 'source_to_shares', + 'bridge_readiness', +] as const; + +export type BtdProtocolProofHookFamily = + (typeof BTD_PROTOCOL_PROOF_HOOK_FAMILIES)[number]; + +export interface BtdProtocolProofHookInput { + proofHookId?: string; + proofFamily: BtdProtocolProofHookFamily; + subjectKind: BtdProtocolTelemetrySubjectKind; + subjectId: string; + evidenceRoot: string; + telemetryRoot: string; + theoremIds: string[]; + replayStepIds: string[]; + witnessArtifactPaths: string[]; + generatedArtifactPath?: string; + issuedAt?: string; +} + +export interface BtdProtocolProofHook { + kind: 'btd.protocol_proof_hook'; + proofHookId: string; + proofFamily: BtdProtocolProofHookFamily; + subjectKind: BtdProtocolTelemetrySubjectKind; + subjectId: string; + evidenceRoot: string; + telemetryRoot: string; + theoremIds: string[]; + replayStepIds: string[]; + witnessArtifactPaths: string[]; + generatedArtifactPath?: string; + compatibleWith: ['V32', 'V35']; + sourceSafety: BtdProtocolTelemetrySourceSafety; + hookRoot: string; + issuedAt: string; +} + +export interface BtdProtocolTelemetryEnvelopeInput { + envelopeId?: string; + telemetry: BtdProtocolTelemetryInput[]; + proofHooks: BtdProtocolProofHookInput[]; + issuedAt?: string; +} + +export interface BtdProtocolTelemetryEnvelope { + kind: 'btd.protocol_telemetry_envelope'; + envelopeId: string; + telemetry: BtdProtocolTelemetryRecord[]; + proofHooks: BtdProtocolProofHook[]; + compatibleWith: ['V32', 'V35']; + sourceSafety: BtdProtocolTelemetrySourceSafety; + telemetryRoot: string; + proofRoot: string; + issuedAt: string; +} + +const PROTOCOL_EVENT_SUBJECT_KIND: Record< + BtdProtocolTelemetryEvent, + BtdProtocolTelemetrySubjectKind +> = { + 'btd.receipt.emitted': 'btd_receipt', + 'btd.btc_fee_state.emitted': 'btc_fee_state', + 'btd.ledger_projection.emitted': 'ledger_projection', + 'btd.source_to_shares_proof.emitted': 'source_to_shares_proof', + 'btd.bridge_readiness_posture.emitted': 'bridge_readiness_posture', +}; + +const SOURCE_SAFETY: BtdProtocolTelemetrySourceSafety = { + sourceSafe: true, + protectedSourceVisible: false, + containsProtectedSource: false, + containsSecret: false, +}; + +const SECRET_OR_SOURCE_PATTERNS = [ + new RegExp(`sb_${'secret'}__`, 'iu'), + /\bsk-(?:proj|live|test)?[-_A-Za-z0-9]{16,}\b/u, + /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/u, + /-----BEGIN [A-Z ]*PRIVATE KEY-----/u, + /\bprotected\s+source\b/iu, + /\bprivate\s+source\b/iu, +]; + +const SENSITIVE_METADATA_KEYS = new Set([ + 'protectedSource', + 'protectedSourceText', + 'rawSource', + 'sourceText', + 'privateKey', + 'secret', + 'token', +]); + +export function buildBtdProtocolTelemetryRecord( + input: BtdProtocolTelemetryInput, +): BtdProtocolTelemetryRecord { + assertProtocolTelemetrySubjectKind(input.subjectKind); + assertProtocolTelemetryEvent(input.event); + if (PROTOCOL_EVENT_SUBJECT_KIND[input.event] !== input.subjectKind) { + throw new Error('Protocol telemetry event does not match subject kind.'); + } + + const subjectId = assertSourceSafeString(input.subjectId, 'subjectId'); + const root = assertSourceSafeString(input.root, 'root'); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const metadata = normalizeProtocolTelemetryMetadata(input.metadata ?? {}); + const telemetryId = + input.telemetryId ?? + stableProtocolTelemetryRoot('btd-protocol-telemetry', [ + input.event, + input.subjectKind, + subjectId, + root, + ]); + const telemetryRoot = stableProtocolTelemetryRoot('btd-protocol-telemetry-root', [ + telemetryId, + input.event, + input.subjectKind, + subjectId, + root, + input.receiptRoot ?? '', + input.proofRoot ?? '', + input.ledgerAnchorId ?? '', + input.artifactPath ?? '', + ]); + + return { + kind: 'btd.protocol_telemetry_record', + telemetryId, + event: input.event, + subjectKind: input.subjectKind, + subjectId, + root, + receiptRoot: optionalSourceSafeString(input.receiptRoot, 'receiptRoot'), + proofRoot: optionalSourceSafeString(input.proofRoot, 'proofRoot'), + ledgerAnchorId: optionalSourceSafeString(input.ledgerAnchorId, 'ledgerAnchorId'), + artifactPath: optionalSourceSafeString(input.artifactPath, 'artifactPath'), + severity: input.severity ?? 'info', + metadata, + sourceSafety: { ...SOURCE_SAFETY }, + telemetryRoot, + issuedAt, + }; +} + +export function buildBtdProtocolProofHook( + input: BtdProtocolProofHookInput, +): BtdProtocolProofHook { + assertProtocolProofHookFamily(input.proofFamily); + assertProtocolTelemetrySubjectKind(input.subjectKind); + + if (!input.theoremIds.length) { + throw new Error('Protocol proof hook requires at least one theoremId.'); + } + if (!input.replayStepIds.length) { + throw new Error('Protocol proof hook requires at least one replayStepId.'); + } + if (!input.witnessArtifactPaths.length) { + throw new Error('Protocol proof hook requires at least one witnessArtifactPath.'); + } + + const subjectId = assertSourceSafeString(input.subjectId, 'subjectId'); + const evidenceRoot = assertSourceSafeString(input.evidenceRoot, 'evidenceRoot'); + const telemetryRoot = assertSourceSafeString(input.telemetryRoot, 'telemetryRoot'); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const proofHookId = + input.proofHookId ?? + stableProtocolTelemetryRoot('btd-protocol-proof-hook', [ + input.proofFamily, + input.subjectKind, + subjectId, + evidenceRoot, + telemetryRoot, + ]); + const theoremIds = input.theoremIds.map((id) => assertSourceSafeString(id, 'theoremId')); + const replayStepIds = input.replayStepIds.map((id) => + assertSourceSafeString(id, 'replayStepId'), + ); + const witnessArtifactPaths = input.witnessArtifactPaths.map((path) => + assertSourceSafeString(path, 'witnessArtifactPath'), + ); + const generatedArtifactPath = optionalSourceSafeString( + input.generatedArtifactPath, + 'generatedArtifactPath', + ); + const hookRoot = stableProtocolTelemetryRoot('btd-protocol-proof-hook-root', [ + proofHookId, + input.proofFamily, + input.subjectKind, + subjectId, + evidenceRoot, + telemetryRoot, + theoremIds.join(','), + replayStepIds.join(','), + witnessArtifactPaths.join(','), + generatedArtifactPath ?? '', + ]); + + return { + kind: 'btd.protocol_proof_hook', + proofHookId, + proofFamily: input.proofFamily, + subjectKind: input.subjectKind, + subjectId, + evidenceRoot, + telemetryRoot, + theoremIds, + replayStepIds, + witnessArtifactPaths, + generatedArtifactPath, + compatibleWith: ['V32', 'V35'], + sourceSafety: { ...SOURCE_SAFETY }, + hookRoot, + issuedAt, + }; +} + +export function buildBtdProtocolTelemetryEnvelope( + input: BtdProtocolTelemetryEnvelopeInput, +): BtdProtocolTelemetryEnvelope { + if (!input.telemetry.length) { + throw new Error('Protocol telemetry envelope requires at least one telemetry record.'); + } + if (!input.proofHooks.length) { + throw new Error('Protocol telemetry envelope requires at least one proof hook.'); + } + + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const telemetry = input.telemetry.map((record) => + buildBtdProtocolTelemetryRecord({ ...record, issuedAt: record.issuedAt ?? issuedAt }), + ); + const proofHooks = input.proofHooks.map((hook) => + buildBtdProtocolProofHook({ ...hook, issuedAt: hook.issuedAt ?? issuedAt }), + ); + const telemetryRoots = new Set(telemetry.map((record) => record.telemetryRoot)); + for (const hook of proofHooks) { + if (!telemetryRoots.has(hook.telemetryRoot)) { + throw new Error('Protocol proof hook references a telemetryRoot not present in the envelope.'); + } + } + + const telemetryRoot = stableProtocolTelemetryRoot( + 'btd-protocol-telemetry-envelope-root', + telemetry.map((record) => record.telemetryRoot), + ); + const proofRoot = stableProtocolTelemetryRoot( + 'btd-protocol-proof-envelope-root', + proofHooks.map((hook) => hook.hookRoot), + ); + const envelopeId = + input.envelopeId ?? + stableProtocolTelemetryRoot('btd-protocol-telemetry-envelope', [ + telemetryRoot, + proofRoot, + ]); + + return { + kind: 'btd.protocol_telemetry_envelope', + envelopeId, + telemetry, + proofHooks, + compatibleWith: ['V32', 'V35'], + sourceSafety: { ...SOURCE_SAFETY }, + telemetryRoot, + proofRoot, + issuedAt, + }; +} + +function assertProtocolTelemetryEvent(event: string): BtdProtocolTelemetryEvent { + if (!BTD_PROTOCOL_TELEMETRY_EVENTS.includes(event as BtdProtocolTelemetryEvent)) { + throw new Error(`Unsupported Protocol telemetry event: ${event}.`); + } + + return event as BtdProtocolTelemetryEvent; +} + +function assertProtocolTelemetrySubjectKind( + subjectKind: string, +): BtdProtocolTelemetrySubjectKind { + if ( + !BTD_PROTOCOL_TELEMETRY_SUBJECT_KINDS.includes( + subjectKind as BtdProtocolTelemetrySubjectKind, + ) + ) { + throw new Error(`Unsupported Protocol telemetry subject kind: ${subjectKind}.`); + } + + return subjectKind as BtdProtocolTelemetrySubjectKind; +} + +function assertProtocolProofHookFamily( + proofFamily: string, +): BtdProtocolProofHookFamily { + if (!BTD_PROTOCOL_PROOF_HOOK_FAMILIES.includes(proofFamily as BtdProtocolProofHookFamily)) { + throw new Error(`Unsupported Protocol proof hook family: ${proofFamily}.`); + } + + return proofFamily as BtdProtocolProofHookFamily; +} + +function normalizeProtocolTelemetryMetadata( + metadata: Record, +): Record { + return Object.fromEntries( + Object.entries(metadata).map(([key, value]) => { + if (SENSITIVE_METADATA_KEYS.has(key)) { + throw new Error(`Protocol telemetry metadata key is not source-safe: ${key}.`); + } + assertSourceSafeString(key, 'metadataKey'); + if (typeof value === 'string') { + return [key, assertSourceSafeString(value, `metadata.${key}`)]; + } + if ( + value === null || + typeof value === 'number' || + typeof value === 'boolean' + ) { + return [key, value]; + } + + throw new Error(`Protocol telemetry metadata value is not source-safe: ${key}.`); + }), + ); +} + +function optionalSourceSafeString(value: string | undefined, label: string): string | undefined { + return value === undefined ? undefined : assertSourceSafeString(value, label); +} + +function assertSourceSafeString(value: unknown, label: string): string { + const text = assertNonEmptyString(value, label); + if (SECRET_OR_SOURCE_PATTERNS.some((pattern) => pattern.test(text))) { + throw new Error(`${label} must not contain secrets or protected source.`); + } + + return text; +} + +function stableProtocolTelemetryRoot(prefix: string, parts: string[]): string { + const hash = createHash('sha256').update(parts.join('\u001f')).digest('hex').slice(0, 24); + return `${prefix}:${hash}`; +} diff --git a/scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs b/scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs new file mode 100644 index 000000000..03196b6e8 --- /dev/null +++ b/scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs @@ -0,0 +1,224 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 8 Protocol/BTD telemetry and proof hooks, source-safety, package/API route boundaries, tests, docs, and workflow readiness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-8-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 8 work must occur on version/v30 or v30/gate-8-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + 'packages/btd/src/telemetry.ts', + 'packages/btd/src/api-boundaries.ts', + 'packages/btd/src/index.ts', + 'packages/btd/__tests__/telemetry.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'uapi/app/api/btd/protocol-telemetry/route.ts', + 'packages/btd/README.md', + 'uapi/app/terminal/README.md', + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + ]) { + assertCheck(failures, fileExists(root, relativePath), `Missing V30 Gate 8 file: ${relativePath}`); + } + + const telemetry = read(root, 'packages/btd/src/telemetry.ts'); + const btdBoundary = read(root, 'packages/btd/src/api-boundaries.ts'); + const btdIndex = read(root, 'packages/btd/src/index.ts'); + const btdTest = read(root, 'packages/btd/__tests__/telemetry.test.ts'); + const apiRoute = read(root, 'packages/api/src/routes/btd-crypto.ts'); + const apiTest = read(root, 'packages/api/src/routes/__tests__/btd-crypto.test.ts'); + const uapiRoute = read(root, 'uapi/app/api/btd/protocol-telemetry/route.ts'); + const btdReadme = read(root, 'packages/btd/README.md'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + for (const symbol of [ + 'BtdProtocolTelemetryEnvelope', + 'BtdProtocolTelemetryRecord', + 'BtdProtocolProofHook', + 'buildBtdProtocolTelemetryEnvelope', + 'buildBtdProtocolTelemetryRecord', + 'buildBtdProtocolProofHook', + 'btd_receipt', + 'btc_fee_state', + 'ledger_projection', + 'source_to_shares_proof', + 'bridge_readiness_posture', + 'sourceSafety', + 'containsProtectedSource: false', + "compatibleWith: ['V32', 'V35']", + ]) { + assertCheck(failures, telemetry.includes(symbol), `BTD telemetry primitive is missing ${symbol}.`); + } + + for (const testEvidence of [ + 'receipts, fees, projections, shares, and bridges', + 'event and subject kind do not match', + 'secret-looking or protected-source telemetry metadata', + 'reference envelope telemetry roots', + 'replayable theorem and witness facts', + ]) { + assertCheck(failures, btdTest.includes(testEvidence), `BTD telemetry tests must cover ${testEvidence}.`); + } + + for (const boundaryEvidence of [ + 'BtdProtocolTelemetryBoundaryInput', + 'BtdProtocolTelemetrySettlement', + 'buildBtdProtocolTelemetrySettlement', + 'terminal-btd-protocol-telemetry', + 'proof_admission', + ]) { + assertCheck(failures, btdBoundary.includes(boundaryEvidence), `BTD API boundary must include ${boundaryEvidence}.`); + } + assertCheck(failures, btdIndex.includes("export * from './telemetry'"), 'BTD package index must export telemetry primitives.'); + + for (const apiEvidence of [ + 'buildPostBtdProtocolTelemetryRoute', + '/btd/protocol-telemetry', + ]) { + assertCheck(failures, apiRoute.includes(apiEvidence), `BTD API route must include ${apiEvidence}.`); + assertCheck(failures, apiTest.includes(apiEvidence), `BTD API tests must cover ${apiEvidence}.`); + } + assertCheck( + failures, + apiRoute.includes('postBtdProtocolTelemetry'), + 'BTD API route must export postBtdProtocolTelemetry.', + ); + assertCheck( + failures, + uapiRoute.includes('postBtdProtocolTelemetry'), + 'Next route must expose postBtdProtocolTelemetry.', + ); + + assertCheck( + failures, + btdReadme.includes('Protocol telemetry proof hooks') && + btdReadme.includes('BtdProtocolTelemetryEnvelope'), + 'BTD README must document Protocol telemetry proof hooks.', + ); + assertCheck( + failures, + terminalReadme.includes('Protocol telemetry proof hooks') && + terminalReadme.includes('/btd/protocol-telemetry'), + 'Terminal README must document Protocol telemetry proof-hook consumption.', + ); + assertCheck( + failures, + spec.includes('Gate 8 Protocol telemetry proof hooks') && + spec.includes('BtdProtocolTelemetryEnvelope'), + 'V30 SPEC must define Gate 8 Protocol telemetry proof hooks.', + ); + assertCheck( + failures, + delta.includes('Gate 8 implementation centers') && + delta.includes('/btd/protocol-telemetry'), + 'V30 DELTA must include Gate 8 implementation evidence.', + ); + assertCheck( + failures, + notes.includes('Gate 8 Protocol telemetry notes'), + 'V30 NOTES must include Gate 8 implementation notes.', + ); + assertCheck( + failures, + parity.includes('## Gate 8 Parity') && parity.includes('Gate 8 accepted boundaries'), + 'V30 PARITY must include Gate 8 parity and accepted boundaries.', + ); + assertCheck(failures, packageJson.includes('"check:v30-gate8"'), 'package.json must expose check:v30-gate8.'); + assertCheck( + failures, + gateWorkflow.includes('check-v30-gate8-protocol-telemetry-proof-hooks.mjs'), + 'Gate workflow must run the V30 Gate 8 checker.', + ); + + if (failures.length) { + process.stderr.write('V30 Gate 8 Protocol telemetry proof hooks check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V30 Gate 8 Protocol telemetry proof hooks check passed.\n'); +} + +main(); diff --git a/uapi/app/api/btd/protocol-telemetry/route.ts b/uapi/app/api/btd/protocol-telemetry/route.ts new file mode 100644 index 000000000..93d5da2c4 --- /dev/null +++ b/uapi/app/api/btd/protocol-telemetry/route.ts @@ -0,0 +1,3 @@ +import { postBtdProtocolTelemetry } from '@bitcode/api'; + +export const POST = postBtdProtocolTelemetry; diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 4500e4634..8b84441fc 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -158,6 +158,15 @@ feasibility, risks, rereview triggers, required proof, and required policy, and the selected-activity detail must preserve `no_bridge_chain_of_record` as the current `$BTD` truth until a future promoted spec admits otherwise. +Protocol telemetry proof hooks should enter Terminal through +`/btd/protocol-telemetry`, not through route-local log projection. The BTD +package emits `BtdProtocolTelemetryEnvelope` objects with source-safe telemetry +records and proof hooks for receipts, BTC fee states, ledger projections, +source-to-shares proofs, and bridge-readiness posture. Collapsed rows should +show event, subject kind, subject id, severity, and proof compatibility; +expanded metadata may show roots, theorem ids, replay steps, witness artifact +paths, and generated artifact paths, but never protected source or secrets. + The Organization Authority section is the selected-activity permission explainer. It projects registry-derived organization role, explicit grants, wallet binding, owner-read or licensed-read access, settlement state, From f1771573c885652055c86ced1b43ba06a3ba7706 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 20:27:10 -0300 Subject: [PATCH 10/15] V30 Gate 9: Prove interface integration regression (#41) Add package-owned BTD interface integration contracts and regression proof builders, including source-safe coverage for Terminal, API, MCP, ChatGPT App, Auxillaries hooks, and Exchange hooks. Expose the JSON-safe API admission route, wire Terminal/MCP/ChatGPT adapter records, and update V30 spec, parity, notes, README, gate workflow, and checker coverage. Proof: BTD/API/MCP/ChatGPT/Terminal focused tests, touched typechecks, V30 Gate 1-9 checkers, spec-family/canonical-input/posture checks, and diff hygiene passed locally. --- .github/workflows/bitcode-gate-quality.yml | 3 + BITCODE_SPEC_V30.md | 22 ++ BITCODE_SPEC_V30_DELTA.md | 14 + BITCODE_SPEC_V30_NOTES.md | 16 + BITCODE_SPEC_V30_PARITY_MATRIX.md | 21 +- package.json | 1 + .../src/routes/__tests__/btd-crypto.test.ts | 136 ++++++++ packages/api/src/routes/btd-crypto.ts | 39 +++ packages/btd/README.md | 15 + .../__tests__/interface-integration.test.ts | 128 ++++++++ packages/btd/package.json | 1 + packages/btd/src/api-boundaries.ts | 74 +++++ packages/btd/src/index.ts | 2 + .../btd/src/interface-integration-contract.ts | 41 +++ packages/btd/src/interface-integration.ts | 259 +++++++++++++++ packages/chatgptapp/README.md | 10 + .../chatgptapp/src/__tests__/tools.test.ts | 13 + packages/chatgptapp/src/index.ts | 1 + .../chatgptapp/src/interface-integration.ts | 19 ++ packages/chatgptapp/tsconfig.json | 1 + .../executions-mcp/src/mcp-server/README.md | 6 + .../src/__tests__/unit/auth.test.ts | 13 + .../src/mcp-server/src/index.ts | 1 + .../mcp-server/src/interface-integration.ts | 19 ++ ...interface-integration-regression-proof.mjs | 305 ++++++++++++++++++ tsconfig.json | 1 + .../interface-integration-regression/route.ts | 3 + uapi/app/terminal/README.md | 9 + ...rminal-interface-integration-regression.ts | 92 ++++++ .../terminal/terminal-protocol-projection.ts | 10 + .../terminal-transaction-detail-snapshot.ts | 8 + uapi/jest.config.cjs | 2 + ...inalInterfaceIntegrationRegression.test.ts | 53 +++ uapi/tests/terminalProtocolProjection.test.ts | 10 +- uapi/tsconfig.json | 3 + 35 files changed, 1349 insertions(+), 2 deletions(-) create mode 100644 packages/btd/__tests__/interface-integration.test.ts create mode 100644 packages/btd/src/interface-integration-contract.ts create mode 100644 packages/btd/src/interface-integration.ts create mode 100644 packages/chatgptapp/src/interface-integration.ts create mode 100644 packages/executions-mcp/src/mcp-server/src/interface-integration.ts create mode 100644 scripts/check-v30-gate9-interface-integration-regression-proof.mjs create mode 100644 uapi/app/api/btd/interface-integration-regression/route.ts create mode 100644 uapi/app/terminal/terminal-interface-integration-regression.ts create mode 100644 uapi/tests/terminalInterfaceIntegrationRegression.test.ts diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 879087698..175a7d65c 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -87,6 +87,7 @@ jobs: node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs --skip-branch-check node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs --skip-branch-check node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs --skip-branch-check + node scripts/check-v30-gate9-interface-integration-regression-proof.mjs --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 @@ -131,6 +132,8 @@ jobs: tests/terminalDepositReadWorkbench.test.ts \ tests/terminalTransactionQuery.test.ts \ tests/terminalTransactionReadModel.test.ts \ + tests/terminalProtocolProjection.test.ts \ + tests/terminalInterfaceIntegrationRegression.test.ts \ tests/terminalWalletBtcOperation.test.ts \ tests/terminalJournalReconciliation.test.ts \ tests/terminalOrganizationAuthority.test.ts \ diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index f52edad3f..2e2737dd0 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -349,6 +349,28 @@ The focused Playwright spec proves the cockpit in a real browser in deterministi Gate 9 acceptance does not change Reading law, source disclosure law, settlement law, or organization authority law. It makes the current V30 Terminal cockpit commercially operable enough that later local/staging promotion readiness can debug failures from the UI rather than from browser network logs alone. +### Gate 9 interface integration regression proof + +Gate 9 adds a package-owned proof that current interface surfaces consume the +Protocol/BTD rails instead of duplicating them: + +- `BtdInterfaceIntegrationRegressionProof` covers Terminal, API, MCP, + ChatGPT App, Auxillaries hook, and Exchange hook surfaces. +- `BtdInterfaceIntegrationRecordInput` and + `@bitcode/btd/interface-integration-contract` give browser-facing + interfaces a client-safe contract for surface and object-family coverage. +- `/btd/interface-integration-regression` wraps the package proof in a + source-safe Terminal journal `proof_admission` boundary. +- The proof covers BTD registry, read access, BTD receipts, BTC fee operation, + ledger projection, source-to-shares proof, Protocol telemetry, + organization authority, and Terminal journal object families. +- Every record must set `packageOwned: true`, + `routeLocalReimplementation: false`, `sourceSafeLowDetailIntact: true`, and + `transactionCockpitRegression: false`. +- The proof fails closed on missing surfaces, missing object families, + protected source, secrets, route-local policy copies, or low-detail cockpit + regression. + ## V30 local and staging promotion readiness canon V30 promotion is admissible only when the version branch can prove both source diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 376b6a1ed..84eac3fb8 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -305,6 +305,20 @@ Closure acceptance: - low-detail source-safe UX remains intact; - focused regression tests prove no V29 transaction cockpit behavior regresses. +Gate 9 implementation centers on: + +- `packages/btd/src/interface-integration-contract.ts` for client-safe + surface and object-family contracts; +- `packages/btd/src/interface-integration.ts` for + `BtdInterfaceIntegrationRegressionProof` and source-safe fail-closed + record validation; +- `buildBtdInterfaceIntegrationRegressionSettlement` and + `/btd/interface-integration-regression` for JSON-safe API admission; +- Terminal, MCP, and ChatGPT App adapter records proving package-owned + consumption without route-local BTD policy copies; +- focused BTD, API, MCP, ChatGPT App, and Terminal tests for source-safe + low-detail regression closure. + ### Gate 10: V30 Promotion Readiness Gate 10 owns final local/staging proof, generated artifacts, and V30 promotion workflow support. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index 5e4ad913d..9c1e866be 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -251,6 +251,22 @@ boundary exposes `/btd/protocol-telemetry` as a JSON-safe proof-admission route; it does not commit source-bearing artifacts, and it does not replace existing crypto telemetry rows used for deployment readiness health. +## Gate 9 interface integration notes + +Gate 9 makes interface reuse explicit. The accepted package shape is +`BtdInterfaceIntegrationRegressionProof` plus the browser-safe +`@bitcode/btd/interface-integration-contract` subpath. Terminal uses the +contract without importing storage-backed BTD entry points into the client. +API uses `buildBtdInterfaceIntegrationRegressionSettlement` and exposes +`/btd/interface-integration-regression` as a JSON-safe proof-admission route. +MCP and ChatGPT App expose small adapter records that name their package-owned +BTD object consumption. + +The proof is not a new user journey. It is regression evidence that the V30 +rails can be consumed by current interfaces without losing low-detail source +safety, reintroducing route-local BTD policy copies, or changing the selected +Terminal transaction behavior promoted in V29. + ## Gate 1 working notes Gate 1 is complete only when the V30 family exists, validates in draft mode over active V29, and makes the roadmap truthful enough to drive V31 through V37 without stale V27/V28/V29 posture. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index fdf662962..2e768033d 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -62,7 +62,7 @@ No `_legacy/` source is active source truth. | Source-to-shares proof cleanup | Gate 6 | `packages/btd/src/source-to-shares.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Measurement contribution, fee allocation, zero-cell/refit tail, ancestry evidence, and conservation invariants are testable. | | Bridge-readiness research boundaries | Gate 7 | `packages/btd/src/bridge-readiness.ts`, BTD/API tests, route boundary, docs, gate checker | drafted | Bridge paths are typed research-only records until admitted by explicit future proof and policy. | | Protocol telemetry/proof hooks | Gate 8 | `packages/btd/src/telemetry.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Receipts, fee states, projections, source-to-shares proofs, and bridge-readiness posture emit source-safe telemetry and proof hooks. | -| Interface integration regression | Gate 9 | Terminal/API/MCP/ChatGPT App adapters and tests | pending | Existing interfaces consume package-owned objects without regressing V29 behavior. | +| Interface integration regression | Gate 9 | `packages/btd/src/interface-integration.ts`, `packages/api/src/routes/btd-crypto.ts`, Terminal/MCP/ChatGPT adapters and tests, gate checker | drafted | Existing interfaces consume package-owned objects without regressing V29 behavior. | | Promotion readiness | Gate 10 | V30 promotion workflow, generated `.bitcode/v30-*`, `BITCODE_SPEC_V30_PROVEN.md` | pending | `version/v30` can promote to `main` only after all V30 checks pass and promotion automation can commit generated canon. | ## V30 implementation checklist @@ -229,6 +229,25 @@ No `_legacy/` source is active source truth. - Gate 8 may expose telemetry/proof hooks to Terminal/API callers for operator review. - Gate 8 does not promote V30 or change the active canon pointer. +## Gate 9 Parity + +| Requirement | Source evidence | Current V30 judgment | +| --- | --- | --- | +| Interface integration proof is package-owned | `packages/btd/src/interface-integration.ts`, `packages/btd/src/interface-integration-contract.ts`, `packages/btd/src/index.ts` | drafted | +| Terminal can consume client-safe package contracts | `uapi/app/terminal/terminal-interface-integration-regression.ts`, `uapi/app/terminal/terminal-protocol-projection.ts` | drafted | +| API exposes JSON-safe proof admission | `buildBtdInterfaceIntegrationRegressionSettlement`, `buildPostBtdInterfaceIntegrationRegressionRoute`, `uapi/app/api/btd/interface-integration-regression/route.ts` | drafted | +| MCP and ChatGPT App declare package-owned object records | `packages/executions-mcp/src/mcp-server/src/interface-integration.ts`, `packages/chatgptapp/src/interface-integration.ts` | drafted | +| Source-safe low-detail and transaction cockpit regression are tested | BTD interface-integration tests, BTD crypto route tests, Terminal projection tests, MCP auth test, ChatGPT tools test | drafted | +| Gate checker protects interface integration boundaries | `scripts/check-v30-gate9-interface-integration-regression-proof.mjs`, `pnpm run check:v30-gate9`, gate-quality workflow | drafted | + +## Gate 9 accepted boundaries + +- Gate 9 does not redesign Reading, settlement, source disclosure, organization authority, MCP, ChatGPT App, Auxillaries, or Exchange. +- Gate 9 does not expose protected AssetPack source, prompts, raw source, private keys, service keys, model keys, JWT-looking secrets, or database passwords. +- Gate 9 admits only source-safe interface integration records and a proof-admission route; it does not commit ledger state or deliver AssetPacks. +- Gate 9 proves current interfaces consume package-owned BTD object families without route-local policy copies. +- Gate 9 does not promote V30 or change the active canon pointer. + ## completion condition Gate 1 is complete when the V30 draft family validates, `check:v30-gate1` passes, workflow posture is V30-aware, README and roadmap reflect V30 initiation, V31-V37 scopes are current enough to guide future gates, diff hygiene passes, and the gate branch is committed and pushed for review into `version/v30`. diff --git a/package.json b/package.json index fea2ea106..8bb9bfddd 100644 --- a/package.json +++ b/package.json @@ -62,6 +62,7 @@ "check:v30-gate6": "node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs", "check:v30-gate7": "node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs", "check:v30-gate8": "node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs", + "check:v30-gate9": "node scripts/check-v30-gate9-interface-integration-regression-proof.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/api/src/routes/__tests__/btd-crypto.test.ts b/packages/api/src/routes/__tests__/btd-crypto.test.ts index 2ea841460..aa01f5852 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -21,6 +21,7 @@ import { buildBtdBtcFeeTransactionSettlement, buildBtdBridgeReadinessResearchSettlement, buildBtdDeploymentReadinessSettlement, + buildBtdInterfaceIntegrationRegressionSettlement, buildBtdLedgerDatabaseReconciliationSettlement, buildBtdLicensedReadRevenueSettlement, buildBtdMintDraft, @@ -41,6 +42,7 @@ import { buildPostBtdBtcFeeTransactionRoute, buildPostBtdBridgeReadinessResearchRoute, buildPostBtdDeploymentReadinessRoute, + buildPostBtdInterfaceIntegrationRegressionRoute, buildPostBtdLedgerDatabaseReconciliationRoute, buildPostBtdLicensedReadRevenueRoute, buildPostBtdMintDraftRoute, @@ -49,6 +51,7 @@ import { buildPostBtdReadAccessRoute, buildPostBtdSourceToSharesProofRoute, buildPostBtdTerminalJournalRoute, + postBtdInterfaceIntegrationRegression, } from '../btd-crypto'; const issuedAt = '2026-05-06T00:00:00.000Z'; @@ -259,6 +262,86 @@ function protocolTelemetryBody(overrides: Record = {}) { }; } +function interfaceIntegrationRegressionBody(overrides: Record = {}) { + const recordBase = { + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + notes: ['package-owned object consumed source-safely'], + issuedAt, + }; + + return { + records: [ + { + ...recordBase, + surface: 'terminal', + consumerId: 'terminal-transaction-cockpit', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_registry', 'read_access', 'terminal_journal'], + proofRoot: 'terminal-interface-proof-root', + }, + { + ...recordBase, + surface: 'api', + consumerId: 'btd-api-route-boundary', + packageExport: '@bitcode/btd', + adapterPath: 'packages/api/src/routes/btd-crypto.ts', + objectFamilies: [ + 'btd_receipts', + 'btc_fee_operation', + 'ledger_projection', + 'protocol_telemetry', + ], + proofRoot: 'api-interface-proof-root', + }, + { + ...recordBase, + surface: 'mcp', + consumerId: 'bitcode-mcp-interface', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'packages/executions-mcp/src/mcp-server/src/interface-integration.ts', + objectFamilies: ['source_to_shares_proof', 'organization_authority'], + proofRoot: 'mcp-interface-proof-root', + }, + { + ...recordBase, + surface: 'chatgpt_app', + consumerId: 'bitcode-chatgpt-app-interface', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'packages/chatgptapp/src/interface-integration.ts', + objectFamilies: ['read_access', 'organization_authority'], + proofRoot: 'chatgpt-app-interface-proof-root', + }, + { + ...recordBase, + surface: 'auxillaries_hook', + consumerId: 'auxillaries-interface-hook', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_registry', 'organization_authority'], + proofRoot: 'auxillaries-interface-proof-root', + }, + { + ...recordBase, + surface: 'exchange_hook', + consumerId: 'exchange-interface-hook', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_receipts', 'btc_fee_operation', 'ledger_projection'], + proofRoot: 'exchange-interface-proof-root', + }, + ], + lowDetailProofRoot: 'terminal-low-detail-source-safe-proof-root', + transactionCockpitProofRoot: 'terminal-transaction-cockpit-regression-proof-root', + exchangeSequence: '21', + issuedAt, + ...overrides, + }; +} + describe('BTD crypto API builders', () => { it('builds a deterministic mint draft from accepted Read-Fit semantic units', () => { const draft = buildBtdMintDraft(mintDraftInput()); @@ -1682,6 +1765,59 @@ describe('BTD crypto API builders', () => { expect(body.terminalJournalEntry.exchangeSequence).toBe('20'); }); + it('returns JSON-safe interface integration regression proof from the route boundary', async () => { + const direct = buildBtdInterfaceIntegrationRegressionSettlement({ + ...(interfaceIntegrationRegressionBody() as any), + exchangeSequence: 21n, + actorId: 'user-1', + }); + const route = buildPostBtdInterfaceIntegrationRegressionRoute({ + resolveAuthenticatedUser: async () => ({ userId: 'user-1' }), + }); + const response = await route( + new Request('https://bitcode.test/api/btd/interface-integration-regression', { + method: 'POST', + body: JSON.stringify(interfaceIntegrationRegressionBody()), + }), + ); + const body = await response.json(); + + expect(direct.kind).toBe('btd_interface_integration_regression_settlement'); + expect(postBtdInterfaceIntegrationRegression).toBeDefined(); + expect(response.status).toBe(200); + expect(body.kind).toBe('btd_interface_integration_regression_settlement'); + expect(body.committed).toBe(false); + expect(body.proof.coverage.surfaces.missing).toEqual([]); + expect(body.proof.coverage.objectFamilies.missing).toEqual([]); + expect(body.proof.packageOwned).toBe(true); + expect(body.proof.routeLocalReimplementation).toBe(false); + expect(body.proof.sourceSafeLowDetailIntact).toBe(true); + expect(body.proof.transactionCockpitRegression).toBe(false); + expect(body.terminalJournalEntry.exchangeSequence).toBe('21'); + }); + + it('fails interface integration regression when source-safe low detail is not proven', async () => { + const route = buildPostBtdInterfaceIntegrationRegressionRoute({ + resolveAuthenticatedUser: async () => ({ userId: 'user-1' }), + }); + const body = interfaceIntegrationRegressionBody({ + records: (interfaceIntegrationRegressionBody().records as any[]).map((record, index) => ({ + ...record, + sourceSafeLowDetailIntact: index === 0 ? false : record.sourceSafeLowDetailIntact, + })), + }); + const response = await route( + new Request('https://bitcode.test/api/btd/interface-integration-regression', { + method: 'POST', + body: JSON.stringify(body), + }), + ); + const payload = await response.json(); + + expect(response.status).toBe(400); + expect(payload.error).toContain('source-safe low-detail UX'); + }); + it('returns JSON-safe deployment readiness settlements and persists telemetry or upgrades', async () => { const insertCryptoTelemetryEvent = jest.fn(async (row) => ({ event: row.event, diff --git a/packages/api/src/routes/btd-crypto.ts b/packages/api/src/routes/btd-crypto.ts index 106dc8728..b85591dbc 100644 --- a/packages/api/src/routes/btd-crypto.ts +++ b/packages/api/src/routes/btd-crypto.ts @@ -19,6 +19,8 @@ import { type BtdBtcFeeTransactionSettlement, type BtdDeploymentReadinessInput, type BtdDeploymentReadinessSettlement, + type BtdInterfaceIntegrationRegressionInput, + type BtdInterfaceIntegrationRegressionSettlement, type BtdLedgerDatabaseReconciliationInput, type BtdLedgerDatabaseReconciliationSettlement, type BtdLicensedReadRevenueInput, @@ -47,6 +49,7 @@ import { buildBtdBridgeReadinessResearchSettlement, buildBtdBtcFeeTransactionSettlement, buildBtdDeploymentReadinessSettlement, + buildBtdInterfaceIntegrationRegressionSettlement, buildBtdLedgerDatabaseReconciliationSettlement, buildBtdLicensedReadRevenueSettlement, buildBtdMintDraft, @@ -71,6 +74,7 @@ export { buildBtdBridgeReadinessResearchSettlement, buildBtdBtcFeeTransactionSettlement, buildBtdDeploymentReadinessSettlement, + buildBtdInterfaceIntegrationRegressionSettlement, buildBtdLedgerDatabaseReconciliationSettlement, buildBtdLicensedReadRevenueSettlement, buildBtdMintDraft, @@ -675,6 +679,39 @@ export function buildPostBtdProtocolTelemetryRoute(options: BtdRouteOptions = {} }); } +export function buildPostBtdInterfaceIntegrationRegressionRoute(options: BtdRouteOptions = {}) { + return traceRoute('/btd/interface-integration-regression', async (request: Request) => { + const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( + request, + ); + if (!user) { + return createJsonResponse({ error: 'Unauthorized' }, 401); + } + + let body: Omit & { + exchangeSequence: string | number; + }; + try { + body = await request.json(); + } catch { + return createJsonResponse({ error: 'Invalid JSON body' }, 400); + } + + let settlement: BtdInterfaceIntegrationRegressionSettlement; + try { + settlement = buildBtdInterfaceIntegrationRegressionSettlement({ + ...body, + actorId: user.userId, + exchangeSequence: parseBtdRequiredBigInt(body.exchangeSequence, 'exchangeSequence'), + }); + } catch (error) { + return createJsonResponse({ error: toBadRequestMessage(error) }, 400); + } + + return createJsonResponse(toJsonSafe(settlement)); + }); +} + export function buildPostBtdDeploymentReadinessRoute(options: BtdRouteOptions = {}) { return traceRoute('/btd/deployment-readiness', async (request: Request) => { const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( @@ -737,6 +774,8 @@ export const postBtdLedgerDatabaseReconciliation = export const postBtdSourceToSharesProof = buildPostBtdSourceToSharesProofRoute(); export const postBtdBridgeReadinessResearch = buildPostBtdBridgeReadinessResearchRoute(); export const postBtdProtocolTelemetry = buildPostBtdProtocolTelemetryRoute(); +export const postBtdInterfaceIntegrationRegression = + buildPostBtdInterfaceIntegrationRegressionRoute(); export const postBtdDeploymentReadiness = buildPostBtdDeploymentReadinessRoute(); function toBadRequestMessage(error: unknown): string { diff --git a/packages/btd/README.md b/packages/btd/README.md index 8ac9c7fc0..339e345d2 100644 --- a/packages/btd/README.md +++ b/packages/btd/README.md @@ -27,6 +27,12 @@ This package owns: source-safe `BtdProtocolTelemetryRecord` rows, and `BtdProtocolProofHook` bindings for receipts, BTC fee states, ledger projections, source-to-shares proofs, and bridge-readiness posture +- Interface integration regression proof through + `BtdInterfaceIntegrationRegressionProof`, the client-safe + `@bitcode/btd/interface-integration-contract` subpath, and source-safe + records proving Terminal, API, MCP, ChatGPT App, Auxillaries hooks, and + Exchange hooks consume package-owned Protocol/BTD objects without local + policy copies - ledger/database/object-storage projection reconciliation, including deterministic repair classes, source-safe object artifact roots, secret-free Supabase staging-testnet readback receipts, quarantine/retry @@ -64,6 +70,7 @@ import { buildSourceToSharesProof, buildBridgeReadinessResearchPosture, buildBtdProtocolTelemetryEnvelope, + buildBtdInterfaceIntegrationRegressionProof, reconcileLedgerDatabaseProjection, sourceToSharesProofToSettlementConservationCheck, toBtdJsonSafe, @@ -87,3 +94,11 @@ client-safe read model without importing storage-backed package entry points: ```ts import { buildTerminalOperationalHealthRead } from '@bitcode/btd/terminal-operational-health'; ``` + +Terminal and other browser-facing interfaces should consume +`@bitcode/btd/interface-integration-contract` when they only need source-safe +surface and object-family contracts. Server-side boundaries can use +`buildBtdInterfaceIntegrationRegressionProof` or +`buildBtdInterfaceIntegrationRegressionSettlement` to prove those records +without reimplementing BTD receipt, fee, ledger, telemetry, access, authority, +or journal policy in route-local code. diff --git a/packages/btd/__tests__/interface-integration.test.ts b/packages/btd/__tests__/interface-integration.test.ts new file mode 100644 index 000000000..a3f41863a --- /dev/null +++ b/packages/btd/__tests__/interface-integration.test.ts @@ -0,0 +1,128 @@ +import { + BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES, + BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES, + buildBtdInterfaceIntegrationRecord, + buildBtdInterfaceIntegrationRegressionProof, + type BtdInterfaceIntegrationRecordInput, +} from '../src/interface-integration'; + +const issuedAt = '2026-05-21T00:00:00.000Z'; + +function record( + input: Pick< + BtdInterfaceIntegrationRecordInput, + 'surface' | 'consumerId' | 'packageExport' | 'adapterPath' | 'objectFamilies' + >, +): BtdInterfaceIntegrationRecordInput { + return { + ...input, + proofRoot: `${input.consumerId}-proof-root`, + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + notes: ['package-owned object consumed with source-safe disclosure'], + issuedAt, + }; +} + +function records(): BtdInterfaceIntegrationRecordInput[] { + return [ + record({ + surface: 'terminal', + consumerId: 'terminal-transaction-cockpit', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_registry', 'read_access', 'terminal_journal'], + }), + record({ + surface: 'api', + consumerId: 'btd-api-route-boundary', + packageExport: '@bitcode/btd', + adapterPath: 'packages/api/src/routes/btd-crypto.ts', + objectFamilies: ['btd_receipts', 'btc_fee_operation', 'ledger_projection', 'protocol_telemetry'], + }), + record({ + surface: 'mcp', + consumerId: 'bitcode-mcp-interface', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'packages/executions-mcp/src/mcp-server/src/interface-integration.ts', + objectFamilies: ['source_to_shares_proof', 'organization_authority'], + }), + record({ + surface: 'chatgpt_app', + consumerId: 'bitcode-chatgpt-app-interface', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'packages/chatgptapp/src/interface-integration.ts', + objectFamilies: ['read_access', 'organization_authority'], + }), + record({ + surface: 'auxillaries_hook', + consumerId: 'auxillaries-interface-hook', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_registry', 'organization_authority'], + }), + record({ + surface: 'exchange_hook', + consumerId: 'exchange-interface-hook', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_receipts', 'btc_fee_operation', 'ledger_projection'], + }), + ]; +} + +describe('interface integration regression proof', () => { + it('proves Terminal, API, MCP, ChatGPT App, Auxillaries, and Exchange hooks use package-owned objects', () => { + const proof = buildBtdInterfaceIntegrationRegressionProof({ + records: records(), + lowDetailProofRoot: 'terminal-low-detail-source-safe-proof-root', + transactionCockpitProofRoot: 'terminal-transaction-cockpit-regression-proof-root', + issuedAt, + }); + + expect(proof.kind).toBe('btd.interface_integration_regression_proof'); + expect(proof.coverage.surfaces.required).toEqual([ + ...BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES, + ]); + expect(proof.coverage.objectFamilies.required).toEqual([ + ...BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES, + ]); + expect(proof.coverage.surfaces.missing).toEqual([]); + expect(proof.coverage.objectFamilies.missing).toEqual([]); + expect(proof.packageOwned).toBe(true); + expect(proof.routeLocalReimplementation).toBe(false); + expect(proof.sourceSafeLowDetailIntact).toBe(true); + expect(proof.transactionCockpitRegression).toBe(false); + expect(proof.sourceSafety.containsProtectedSource).toBe(false); + }); + + it('fails closed when an interface record is route-local reimplementation', () => { + expect(() => + buildBtdInterfaceIntegrationRecord({ + ...records()[0], + routeLocalReimplementation: true, + }), + ).toThrow(/route-local reimplementation/); + }); + + it('fails closed when required interface coverage is missing', () => { + expect(() => + buildBtdInterfaceIntegrationRegressionProof({ + records: records().filter((entry) => entry.surface !== 'mcp'), + lowDetailProofRoot: 'terminal-low-detail-source-safe-proof-root', + transactionCockpitProofRoot: 'terminal-transaction-cockpit-regression-proof-root', + }), + ).toThrow(/missing surfaces: mcp/); + }); + + it('fails closed on secret-looking or protected-source labels', () => { + expect(() => + buildBtdInterfaceIntegrationRecord({ + ...records()[0], + notes: ['private source should not be summarized here'], + }), + ).toThrow(/must not contain secrets or protected source/); + }); +}); diff --git a/packages/btd/package.json b/packages/btd/package.json index 0db059752..36d2c729e 100644 --- a/packages/btd/package.json +++ b/packages/btd/package.json @@ -6,6 +6,7 @@ "types": "src/index.ts", "exports": { ".": "./src/index.ts", + "./interface-integration-contract": "./src/interface-integration-contract.ts", "./terminal-operational-health": "./src/terminal-operational-health.ts" }, "scripts": { diff --git a/packages/btd/src/api-boundaries.ts b/packages/btd/src/api-boundaries.ts index 8f209dcf9..2c6e01e23 100644 --- a/packages/btd/src/api-boundaries.ts +++ b/packages/btd/src/api-boundaries.ts @@ -66,6 +66,11 @@ import { createAssetPackExchangeOrder, settleAssetPackExchangeOrder, } from './exchange'; +import type { + BtdInterfaceIntegrationRecordInput, + BtdInterfaceIntegrationRegressionProof, +} from './interface-integration'; +import { buildBtdInterfaceIntegrationRegressionProof } from './interface-integration'; import type { AssetPackLedgerAnchor, LedgerFinalityState, @@ -463,6 +468,16 @@ export interface BtdProtocolTelemetryBoundaryInput { issuedAt?: string; } +export interface BtdInterfaceIntegrationRegressionInput { + proofId?: string; + records: BtdInterfaceIntegrationRecordInput[]; + lowDetailProofRoot: string; + transactionCockpitProofRoot: string; + exchangeSequence: bigint; + actorId?: string; + issuedAt?: string; +} + export type BtdDeploymentReadinessAction = | 'deployment_lane' | 'telemetry_event' @@ -592,6 +607,14 @@ export interface BtdProtocolTelemetrySettlement { committed: false; } +export interface BtdInterfaceIntegrationRegressionSettlement { + kind: 'btd_interface_integration_regression_settlement'; + actorId: string; + proof: BtdInterfaceIntegrationRegressionProof; + terminalJournalEntry: ReturnType; + committed: false; +} + export interface BtdDeploymentReadinessSettlement { kind: 'btd_deployment_readiness_settlement'; actorId: string; @@ -1432,6 +1455,57 @@ export function buildBtdProtocolTelemetrySettlement( }; } +export function buildBtdInterfaceIntegrationRegressionSettlement( + input: BtdInterfaceIntegrationRegressionInput & { actorId: string }, +): BtdInterfaceIntegrationRegressionSettlement { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + if (typeof input.exchangeSequence !== 'bigint' || input.exchangeSequence <= 0n) { + throw new Error('Interface integration regression settlement requires a positive Exchange sequence.'); + } + + const proof = buildBtdInterfaceIntegrationRegressionProof({ + proofId: input.proofId, + records: input.records, + lowDetailProofRoot: input.lowDetailProofRoot, + transactionCockpitProofRoot: input.transactionCockpitProofRoot, + issuedAt: input.issuedAt, + }); + const terminalJournalEntry = buildTerminalJournalEntry({ + journalEntryId: buildBtdStableId('terminal-btd-interface-integration-regression', [ + proof.proofId, + input.exchangeSequence.toString(), + ]), + transactionKind: 'proof_admission', + actorId, + preStateRoot: buildBtdStableId('interface-integration-pre-state', [ + proof.lowDetailProofRoot, + proof.transactionCockpitProofRoot, + ]), + postStateRoot: buildBtdStableId('interface-integration-post-state', [ + proof.proofRoot, + proof.coverage.surfaces.observed.join(','), + proof.coverage.objectFamilies.observed.join(','), + ]), + receiptRoots: [ + proof.proofRoot, + proof.lowDetailProofRoot, + proof.transactionCockpitProofRoot, + ...proof.records.map((record) => record.recordRoot), + ], + ledgerAnchorIds: [], + exchangeSequence: input.exchangeSequence, + issuedAt: proof.issuedAt, + }); + + return { + kind: 'btd_interface_integration_regression_settlement', + actorId, + proof, + terminalJournalEntry, + committed: false, + }; +} + export function buildBtdDeploymentReadinessSettlement( input: BtdDeploymentReadinessInput & { actorId: string }, ): Omit { diff --git a/packages/btd/src/index.ts b/packages/btd/src/index.ts index c8d4ff5b1..84c9620e6 100644 --- a/packages/btd/src/index.ts +++ b/packages/btd/src/index.ts @@ -166,6 +166,8 @@ export * from './authority'; export * from './constants'; export * from './deployment-lanes'; export * from './exchange'; +export * from './interface-integration'; +export * from './interface-integration-contract'; export * from './ledger-anchor'; export * from './measuremint'; export * from './plans'; diff --git a/packages/btd/src/interface-integration-contract.ts b/packages/btd/src/interface-integration-contract.ts new file mode 100644 index 000000000..23f9a2e12 --- /dev/null +++ b/packages/btd/src/interface-integration-contract.ts @@ -0,0 +1,41 @@ +export const BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES = [ + 'terminal', + 'api', + 'mcp', + 'chatgpt_app', + 'auxillaries_hook', + 'exchange_hook', +] as const; + +export type BtdInterfaceIntegrationSurface = + (typeof BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES)[number]; + +export const BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES = [ + 'btd_registry', + 'read_access', + 'btd_receipts', + 'btc_fee_operation', + 'ledger_projection', + 'source_to_shares_proof', + 'protocol_telemetry', + 'organization_authority', + 'terminal_journal', +] as const; + +export type BtdInterfaceIntegrationObjectFamily = + (typeof BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES)[number]; + +export interface BtdInterfaceIntegrationRecordInput { + surface: BtdInterfaceIntegrationSurface; + consumerId: string; + packageExport: string; + adapterPath: string; + objectFamilies: readonly BtdInterfaceIntegrationObjectFamily[]; + proofRoot: string; + packageOwned: boolean; + routeLocalReimplementation: boolean; + sourceSafeLowDetailIntact: boolean; + transactionCockpitRegression: boolean; + notes?: readonly string[]; + issuedAt?: string; +} diff --git a/packages/btd/src/interface-integration.ts b/packages/btd/src/interface-integration.ts new file mode 100644 index 000000000..3a81b2cef --- /dev/null +++ b/packages/btd/src/interface-integration.ts @@ -0,0 +1,259 @@ +import { createHash } from 'crypto'; +import { assertNonEmptyString } from './constants'; +import { + BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES, + BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES, + type BtdInterfaceIntegrationObjectFamily, + type BtdInterfaceIntegrationRecordInput, + type BtdInterfaceIntegrationSurface, +} from './interface-integration-contract'; +import type { BtdProtocolTelemetrySourceSafety } from './telemetry'; + +export { + BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES, + BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES, + type BtdInterfaceIntegrationObjectFamily, + type BtdInterfaceIntegrationRecordInput, + type BtdInterfaceIntegrationSurface, +} from './interface-integration-contract'; + +export interface BtdInterfaceIntegrationRecord { + kind: 'btd.interface_integration_record'; + surface: BtdInterfaceIntegrationSurface; + consumerId: string; + packageExport: string; + adapterPath: string; + objectFamilies: BtdInterfaceIntegrationObjectFamily[]; + proofRoot: string; + packageOwned: true; + routeLocalReimplementation: false; + sourceSafeLowDetailIntact: true; + transactionCockpitRegression: false; + notes: string[]; + sourceSafety: BtdProtocolTelemetrySourceSafety; + recordRoot: string; + issuedAt: string; +} + +export interface BtdInterfaceIntegrationRegressionProofInput { + proofId?: string; + records: BtdInterfaceIntegrationRecordInput[]; + requiredSurfaces?: readonly BtdInterfaceIntegrationSurface[]; + requiredObjectFamilies?: readonly BtdInterfaceIntegrationObjectFamily[]; + lowDetailProofRoot: string; + transactionCockpitProofRoot: string; + issuedAt?: string; +} + +export interface BtdInterfaceIntegrationCoverage { + required: T[]; + observed: T[]; + missing: T[]; +} + +export interface BtdInterfaceIntegrationRegressionProof { + kind: 'btd.interface_integration_regression_proof'; + proofId: string; + records: BtdInterfaceIntegrationRecord[]; + coverage: { + surfaces: BtdInterfaceIntegrationCoverage; + objectFamilies: BtdInterfaceIntegrationCoverage; + recordCount: number; + }; + packageOwned: true; + routeLocalReimplementation: false; + sourceSafeLowDetailIntact: true; + transactionCockpitRegression: false; + lowDetailProofRoot: string; + transactionCockpitProofRoot: string; + sourceSafety: BtdProtocolTelemetrySourceSafety; + proofRoot: string; + issuedAt: string; +} + +const SOURCE_SAFETY: BtdProtocolTelemetrySourceSafety = { + sourceSafe: true, + protectedSourceVisible: false, + containsProtectedSource: false, + containsSecret: false, +}; + +const SECRET_OR_SOURCE_PATTERNS = [ + new RegExp(`sb_${'secret'}__`, 'iu'), + /\bsk-(?:proj|live|test)?[-_A-Za-z0-9]{16,}\b/u, + /\beyJ[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\.[A-Za-z0-9_-]{10,}\b/u, + /-----BEGIN [A-Z ]*PRIVATE KEY-----/u, + /\bprotected\s+source\b/iu, + /\bprivate\s+source\b/iu, + /\braw\s+source\b/iu, +]; + +export function buildBtdInterfaceIntegrationRecord( + input: BtdInterfaceIntegrationRecordInput, +): BtdInterfaceIntegrationRecord { + const surface = assertInterfaceSurface(input.surface); + const objectFamilies = assertObjectFamilies(input.objectFamilies); + if (input.packageOwned !== true) { + throw new Error('Interface integration records must consume package-owned objects.'); + } + if (input.routeLocalReimplementation !== false) { + throw new Error('Interface integration records must not admit route-local reimplementation.'); + } + if (input.sourceSafeLowDetailIntact !== true) { + throw new Error('Interface integration records must preserve source-safe low-detail UX.'); + } + if (input.transactionCockpitRegression !== false) { + throw new Error('Interface integration records must prove no transaction cockpit regression.'); + } + + const consumerId = assertSourceSafeString(input.consumerId, 'consumerId'); + const packageExport = assertSourceSafeString(input.packageExport, 'packageExport'); + const adapterPath = assertSourceSafeString(input.adapterPath, 'adapterPath'); + const proofRoot = assertSourceSafeString(input.proofRoot, 'proofRoot'); + const notes = (input.notes ?? []).map((note) => assertSourceSafeString(note, 'note')); + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const recordRoot = stableInterfaceIntegrationRoot('btd-interface-integration-record', [ + surface, + consumerId, + packageExport, + adapterPath, + objectFamilies.join(','), + proofRoot, + ]); + + return { + kind: 'btd.interface_integration_record', + surface, + consumerId, + packageExport, + adapterPath, + objectFamilies, + proofRoot, + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + notes, + sourceSafety: { ...SOURCE_SAFETY }, + recordRoot, + issuedAt, + }; +} + +export function buildBtdInterfaceIntegrationRegressionProof( + input: BtdInterfaceIntegrationRegressionProofInput, +): BtdInterfaceIntegrationRegressionProof { + if (!input.records.length) { + throw new Error('Interface integration regression proof requires at least one record.'); + } + + const issuedAt = input.issuedAt ?? new Date().toISOString(); + const records = input.records.map((record) => + buildBtdInterfaceIntegrationRecord({ ...record, issuedAt: record.issuedAt ?? issuedAt }), + ); + const requiredSurfaces = [ + ...(input.requiredSurfaces ?? BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES), + ]; + const requiredObjectFamilies = [ + ...(input.requiredObjectFamilies ?? BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES), + ]; + const surfaceCoverage = coverage(requiredSurfaces, records.map((record) => record.surface)); + const objectFamilyCoverage = coverage( + requiredObjectFamilies, + records.flatMap((record) => record.objectFamilies), + ); + + if (surfaceCoverage.missing.length) { + throw new Error( + `Interface integration regression proof is missing surfaces: ${surfaceCoverage.missing.join(', ')}.`, + ); + } + if (objectFamilyCoverage.missing.length) { + throw new Error( + `Interface integration regression proof is missing object families: ${objectFamilyCoverage.missing.join(', ')}.`, + ); + } + + const lowDetailProofRoot = assertSourceSafeString(input.lowDetailProofRoot, 'lowDetailProofRoot'); + const transactionCockpitProofRoot = assertSourceSafeString( + input.transactionCockpitProofRoot, + 'transactionCockpitProofRoot', + ); + const proofRoot = stableInterfaceIntegrationRoot('btd-interface-integration-proof-root', [ + ...records.map((record) => record.recordRoot), + lowDetailProofRoot, + transactionCockpitProofRoot, + ]); + const proofId = + input.proofId ?? + stableInterfaceIntegrationRoot('btd-interface-integration-proof', [proofRoot]); + + return { + kind: 'btd.interface_integration_regression_proof', + proofId, + records, + coverage: { + surfaces: surfaceCoverage, + objectFamilies: objectFamilyCoverage, + recordCount: records.length, + }, + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + lowDetailProofRoot, + transactionCockpitProofRoot, + sourceSafety: { ...SOURCE_SAFETY }, + proofRoot, + issuedAt, + }; +} + +function coverage(required: readonly T[], observed: readonly T[]) { + const observedUnique = Array.from(new Set(observed)).sort() as T[]; + const observedSet = new Set(observedUnique); + return { + required: [...required], + observed: observedUnique, + missing: required.filter((item) => !observedSet.has(item)), + }; +} + +function assertInterfaceSurface(surface: string): BtdInterfaceIntegrationSurface { + if (!BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES.includes(surface as BtdInterfaceIntegrationSurface)) { + throw new Error(`Unsupported interface integration surface: ${surface}.`); + } + + return surface as BtdInterfaceIntegrationSurface; +} + +function assertObjectFamilies( + objectFamilies: readonly BtdInterfaceIntegrationObjectFamily[], +): BtdInterfaceIntegrationObjectFamily[] { + if (!Array.isArray(objectFamilies) || objectFamilies.length === 0) { + throw new Error('Interface integration record requires at least one object family.'); + } + + const deduped = Array.from(new Set(objectFamilies)); + for (const family of deduped) { + if (!BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES.includes(family)) { + throw new Error(`Unsupported interface integration object family: ${family}.`); + } + } + + return deduped.sort(); +} + +function assertSourceSafeString(value: unknown, label: string): string { + const text = assertNonEmptyString(value, label); + if (SECRET_OR_SOURCE_PATTERNS.some((pattern) => pattern.test(text))) { + throw new Error(`${label} must not contain secrets or protected source.`); + } + + return text; +} + +function stableInterfaceIntegrationRoot(prefix: string, parts: string[]): string { + const hash = createHash('sha256').update(parts.join('\u001f')).digest('hex').slice(0, 24); + return `${prefix}:${hash}`; +} diff --git a/packages/chatgptapp/README.md b/packages/chatgptapp/README.md index fbb3aabdd..b9a467f12 100644 --- a/packages/chatgptapp/README.md +++ b/packages/chatgptapp/README.md @@ -76,6 +76,16 @@ The `tools/list` call should display the canonical Bitcode identifiers below wit Refer to `TLDR.md` for a quick-start checklist and `TODO.md` for the active backlog. +## Protocol/BTD interface integration + +The ChatGPT App consumes the shared +`@bitcode/btd/interface-integration-contract` surface through +`src/interface-integration.ts`. That record is source-safe and states that +ChatGPT write carriers reuse package-owned read-access, organization-authority, +and Protocol telemetry objects rather than copying BTD policy locally. The +record is regression evidence for the same connected-interface contract the +Terminal and API expose. + ## Prompt playbook **Golden prompts** diff --git a/packages/chatgptapp/src/__tests__/tools.test.ts b/packages/chatgptapp/src/__tests__/tools.test.ts index 2296f41cf..b0fd997b1 100644 --- a/packages/chatgptapp/src/__tests__/tools.test.ts +++ b/packages/chatgptapp/src/__tests__/tools.test.ts @@ -1,4 +1,5 @@ import { getBitcodeTools, type BitcodeToolExecutionResult } from '../tools'; +import { buildChatGptAppInterfaceIntegrationRecord } from '../interface-integration'; jest.mock('@bitcode/generic-tools-simple-system-text-search', () => ({ simpleSystemTextSearch: { execute: jest.fn() }, @@ -114,6 +115,18 @@ This product delivers voice-first social conversations for builders. } }); + it('declares the ChatGPT App interface integration record through the package-owned BTD contract', () => { + expect(buildChatGptAppInterfaceIntegrationRecord()).toMatchObject({ + surface: 'chatgpt_app', + packageExport: '@bitcode/btd/interface-integration-contract', + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + objectFamilies: expect.arrayContaining(['read_access', 'organization_authority']), + }); + }); + it('answer_codebase_query returns annotated matches', async () => { const result = await runTool<{ answer: string; metadata: { matchCount: number } }>('answer_codebase_query', { query: 'handler', diff --git a/packages/chatgptapp/src/index.ts b/packages/chatgptapp/src/index.ts index 66bc31c67..b0cc4d085 100644 --- a/packages/chatgptapp/src/index.ts +++ b/packages/chatgptapp/src/index.ts @@ -1,2 +1,3 @@ export { BitcodeMCPServer, createBitcodeServer, runBitcodeServer } from './server'; export type { BitcodeTool, BitcodeToolExecutionResult } from './tools'; +export { buildChatGptAppInterfaceIntegrationRecord } from './interface-integration'; diff --git a/packages/chatgptapp/src/interface-integration.ts b/packages/chatgptapp/src/interface-integration.ts new file mode 100644 index 000000000..cc72b5764 --- /dev/null +++ b/packages/chatgptapp/src/interface-integration.ts @@ -0,0 +1,19 @@ +import { + type BtdInterfaceIntegrationRecordInput, +} from '@bitcode/btd/interface-integration-contract'; + +export function buildChatGptAppInterfaceIntegrationRecord(): BtdInterfaceIntegrationRecordInput { + return { + surface: 'chatgpt_app', + consumerId: 'bitcode-chatgpt-app-interface', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'packages/chatgptapp/src/interface-integration.ts', + objectFamilies: ['read_access', 'organization_authority', 'protocol_telemetry'], + proofRoot: 'chatgpt-app-interface-regression-proof-root', + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + notes: ['ChatGPT App connected-interface write carriers reuse package-owned BTD contracts'], + }; +} diff --git a/packages/chatgptapp/tsconfig.json b/packages/chatgptapp/tsconfig.json index 623759d62..0745a5936 100644 --- a/packages/chatgptapp/tsconfig.json +++ b/packages/chatgptapp/tsconfig.json @@ -7,6 +7,7 @@ "types": ["node", "jest"], "paths": { "@bitcode/btd": ["packages/btd/src/authority.ts"], + "@bitcode/btd/interface-integration-contract": ["packages/btd/src/interface-integration-contract.ts"], "@bitcode/tools-generics": ["packages/chatgptapp/src/__stubs__/tools-generics.ts"], "@bitcode/generic-tools-simple-system-text-search": ["packages/chatgptapp/src/__stubs__/generic-tools-simple-system-text-search.ts"], "@bitcode/generic-tools-web-search": ["packages/chatgptapp/src/__stubs__/generic-tools-web-search.ts"], diff --git a/packages/executions-mcp/src/mcp-server/README.md b/packages/executions-mcp/src/mcp-server/README.md index 0ef722d7d..048fc52d7 100644 --- a/packages/executions-mcp/src/mcp-server/README.md +++ b/packages/executions-mcp/src/mcp-server/README.md @@ -9,6 +9,12 @@ The **Bitcode MCP Server** is the Exchange-facing Model Context Protocol interfa This server should teach Bitcode activity, repository scope, attachments/connections as ingress/input context, and asset packs as output meaning. It should not read like a parallel product or a generic engineering-intelligence platform. +The MCP server consumes the shared +`@bitcode/btd/interface-integration-contract` through +`src/interface-integration.ts`. That source-safe record proves the machine +interface uses package-owned source-to-shares, organization authority, and +Protocol telemetry objects rather than route-local BTD policy copies. + ## 🚀 Features ### Core Capabilities diff --git a/packages/executions-mcp/src/mcp-server/src/__tests__/unit/auth.test.ts b/packages/executions-mcp/src/mcp-server/src/__tests__/unit/auth.test.ts index ad917521e..a50385681 100644 --- a/packages/executions-mcp/src/mcp-server/src/__tests__/unit/auth.test.ts +++ b/packages/executions-mcp/src/mcp-server/src/__tests__/unit/auth.test.ts @@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it, jest } from '@jest/globals'; import { authenticateMCPRequest, authCache, validatePermissions } from '../../auth/middleware'; +import { buildMcpInterfaceIntegrationRecord } from '../../interface-integration'; import { createClient } from '@bitcode/supabase'; import { BtdRegistryModel, @@ -83,6 +84,18 @@ describe('Authentication Middleware', () => { }); describe('authenticateMCPRequest', () => { + it('declares the MCP interface integration record through the package-owned BTD contract', () => { + expect(buildMcpInterfaceIntegrationRecord()).toMatchObject({ + surface: 'mcp', + packageExport: '@bitcode/btd/interface-integration-contract', + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + objectFamilies: expect.arrayContaining(['source_to_shares_proof', 'organization_authority']), + }); + }); + it('authenticates a valid API key and derives current Bitcode permissions', async () => { mockGetByKeyHash.mockResolvedValue({ id: 'key123', diff --git a/packages/executions-mcp/src/mcp-server/src/index.ts b/packages/executions-mcp/src/mcp-server/src/index.ts index 2ab25006c..d528adf9b 100644 --- a/packages/executions-mcp/src/mcp-server/src/index.ts +++ b/packages/executions-mcp/src/mcp-server/src/index.ts @@ -47,6 +47,7 @@ export { export { enforceResourceLimits, createResourceLimitedExecutor } from './middleware/resource-limits'; export { RateLimiter, CircuitBreaker } from './middleware/rate-limit'; export { SandboxedFileSystem, validateLocalPath } from './local-repository/handler'; +export { buildMcpInterfaceIntegrationRecord } from './interface-integration'; // Export health check utilities export { performHealthCheck, isReady, isAlive } from './health/health-check'; diff --git a/packages/executions-mcp/src/mcp-server/src/interface-integration.ts b/packages/executions-mcp/src/mcp-server/src/interface-integration.ts new file mode 100644 index 000000000..5912e4b3a --- /dev/null +++ b/packages/executions-mcp/src/mcp-server/src/interface-integration.ts @@ -0,0 +1,19 @@ +import { + type BtdInterfaceIntegrationRecordInput, +} from '@bitcode/btd/interface-integration-contract'; + +export function buildMcpInterfaceIntegrationRecord(): BtdInterfaceIntegrationRecordInput { + return { + surface: 'mcp', + consumerId: 'bitcode-mcp-interface', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'packages/executions-mcp/src/mcp-server/src/interface-integration.ts', + objectFamilies: ['source_to_shares_proof', 'organization_authority', 'protocol_telemetry'], + proofRoot: 'mcp-interface-regression-proof-root', + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + notes: ['MCP exposes package-owned Protocol objects instead of local BTD policy copies'], + }; +} diff --git a/scripts/check-v30-gate9-interface-integration-regression-proof.mjs b/scripts/check-v30-gate9-interface-integration-regression-proof.mjs new file mode 100644 index 000000000..dde1e1f28 --- /dev/null +++ b/scripts/check-v30-gate9-interface-integration-regression-proof.mjs @@ -0,0 +1,305 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + skipBranchCheck: false, + repoRoot, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate9-interface-integration-regression-proof.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 9 interface integration regression proof, package-owned BTD contracts, API route admission, interface adapters, tests, docs, and workflow readiness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + pointer === 'V29', + `BITCODE_SPEC.txt must remain V29 during V30 gate work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-9-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 9 work must occur on version/v30 or v30/gate-9-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + 'packages/btd/src/interface-integration.ts', + 'packages/btd/src/interface-integration-contract.ts', + 'packages/btd/src/api-boundaries.ts', + 'packages/btd/src/index.ts', + 'packages/btd/__tests__/interface-integration.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'uapi/app/api/btd/interface-integration-regression/route.ts', + 'uapi/app/terminal/terminal-interface-integration-regression.ts', + 'uapi/app/terminal/terminal-protocol-projection.ts', + 'uapi/tests/terminalInterfaceIntegrationRegression.test.ts', + 'uapi/tests/terminalProtocolProjection.test.ts', + 'packages/chatgptapp/src/interface-integration.ts', + 'packages/chatgptapp/src/__tests__/tools.test.ts', + 'packages/executions-mcp/src/mcp-server/src/interface-integration.ts', + 'packages/executions-mcp/src/mcp-server/src/__tests__/unit/auth.test.ts', + 'packages/btd/README.md', + 'uapi/app/terminal/README.md', + 'packages/chatgptapp/README.md', + 'packages/executions-mcp/src/mcp-server/README.md', + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + ]) { + assertCheck(failures, fileExists(root, relativePath), `Missing V30 Gate 9 file: ${relativePath}`); + } + + const contract = read(root, 'packages/btd/src/interface-integration-contract.ts'); + const integration = read(root, 'packages/btd/src/interface-integration.ts'); + const boundary = read(root, 'packages/btd/src/api-boundaries.ts'); + const index = read(root, 'packages/btd/src/index.ts'); + const btdTest = read(root, 'packages/btd/__tests__/interface-integration.test.ts'); + const apiRoute = read(root, 'packages/api/src/routes/btd-crypto.ts'); + const apiTest = read(root, 'packages/api/src/routes/__tests__/btd-crypto.test.ts'); + const nextRoute = read(root, 'uapi/app/api/btd/interface-integration-regression/route.ts'); + const terminalAdapter = read(root, 'uapi/app/terminal/terminal-interface-integration-regression.ts'); + const terminalProjection = read(root, 'uapi/app/terminal/terminal-protocol-projection.ts'); + const terminalTest = read(root, 'uapi/tests/terminalInterfaceIntegrationRegression.test.ts'); + const terminalProjectionTest = read(root, 'uapi/tests/terminalProtocolProjection.test.ts'); + const chatgptAdapter = read(root, 'packages/chatgptapp/src/interface-integration.ts'); + const chatgptTest = read(root, 'packages/chatgptapp/src/__tests__/tools.test.ts'); + const mcpAdapter = read(root, 'packages/executions-mcp/src/mcp-server/src/interface-integration.ts'); + const mcpTest = read(root, 'packages/executions-mcp/src/mcp-server/src/__tests__/unit/auth.test.ts'); + const btdReadme = read(root, 'packages/btd/README.md'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const chatgptReadme = read(root, 'packages/chatgptapp/README.md'); + const mcpReadme = read(root, 'packages/executions-mcp/src/mcp-server/README.md'); + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + for (const surface of [ + 'terminal', + 'api', + 'mcp', + 'chatgpt_app', + 'auxillaries_hook', + 'exchange_hook', + ]) { + assertCheck(failures, contract.includes(surface), `Interface contract must include surface ${surface}.`); + assertCheck(failures, btdTest.includes(surface), `BTD tests must cover surface ${surface}.`); + } + + for (const family of [ + 'btd_registry', + 'read_access', + 'btd_receipts', + 'btc_fee_operation', + 'ledger_projection', + 'source_to_shares_proof', + 'protocol_telemetry', + 'organization_authority', + 'terminal_journal', + ]) { + assertCheck(failures, contract.includes(family), `Interface contract must include object family ${family}.`); + assertCheck(failures, btdTest.includes(family), `BTD tests must cover object family ${family}.`); + } + + for (const symbol of [ + 'BtdInterfaceIntegrationRegressionProof', + 'BtdInterfaceIntegrationRecordInput', + 'buildBtdInterfaceIntegrationRegressionProof', + 'buildBtdInterfaceIntegrationRecord', + 'sourceSafeLowDetailIntact', + 'transactionCockpitRegression', + 'routeLocalReimplementation', + 'packageOwned', + ]) { + assertCheck(failures, integration.includes(symbol), `BTD interface integration primitive is missing ${symbol}.`); + } + + for (const boundaryEvidence of [ + 'BtdInterfaceIntegrationRegressionInput', + 'BtdInterfaceIntegrationRegressionSettlement', + 'buildBtdInterfaceIntegrationRegressionSettlement', + 'terminal-btd-interface-integration-regression', + 'proof_admission', + ]) { + assertCheck(failures, boundary.includes(boundaryEvidence), `BTD API boundary must include ${boundaryEvidence}.`); + } + assertCheck(failures, index.includes("export * from './interface-integration'"), 'BTD package index must export interface integration primitives.'); + assertCheck( + failures, + index.includes("export * from './interface-integration-contract'"), + 'BTD package index must export interface integration contracts.', + ); + + for (const apiEvidence of [ + 'buildPostBtdInterfaceIntegrationRegressionRoute', + '/btd/interface-integration-regression', + 'postBtdInterfaceIntegrationRegression', + ]) { + assertCheck(failures, apiRoute.includes(apiEvidence), `BTD API route must include ${apiEvidence}.`); + assertCheck(failures, apiTest.includes(apiEvidence), `BTD API tests must cover ${apiEvidence}.`); + } + assertCheck( + failures, + nextRoute.includes('postBtdInterfaceIntegrationRegression'), + 'Next route must expose postBtdInterfaceIntegrationRegression.', + ); + + for (const adapterEvidence of [ + '@bitcode/btd/interface-integration-contract', + 'buildTerminalInterfaceIntegrationRegressionRecords', + 'buildTerminalInterfaceIntegrationRegressionSummary', + ]) { + assertCheck(failures, terminalAdapter.includes(adapterEvidence), `Terminal adapter must include ${adapterEvidence}.`); + } + assertCheck( + failures, + terminalProjection.includes('interfaceIntegrationRegression'), + 'Terminal protocol projection must expose interface integration regression summary.', + ); + assertCheck( + failures, + terminalTest.includes('source-safe low-detail') && + terminalProjectionTest.includes('interfaceIntegrationRegression'), + 'Terminal tests must cover low-detail interface integration regression.', + ); + + assertCheck( + failures, + chatgptAdapter.includes('@bitcode/btd/interface-integration-contract') && + chatgptTest.includes('buildChatGptAppInterfaceIntegrationRecord'), + 'ChatGPT App must expose and test package-owned BTD interface records.', + ); + assertCheck( + failures, + mcpAdapter.includes('@bitcode/btd/interface-integration-contract') && + mcpTest.includes('buildMcpInterfaceIntegrationRecord'), + 'MCP server must expose and test package-owned BTD interface records.', + ); + + assertCheck( + failures, + btdReadme.includes('Interface integration regression proof') && + btdReadme.includes('BtdInterfaceIntegrationRegressionProof'), + 'BTD README must document interface integration regression proof.', + ); + assertCheck( + failures, + terminalReadme.includes('/btd/interface-integration-regression') && + terminalReadme.includes('@bitcode/btd/interface-integration-contract'), + 'Terminal README must document interface integration proof consumption.', + ); + assertCheck( + failures, + chatgptReadme.includes('@bitcode/btd/interface-integration-contract'), + 'ChatGPT README must document BTD interface integration contract.', + ); + assertCheck( + failures, + mcpReadme.includes('@bitcode/btd/interface-integration-contract'), + 'MCP README must document BTD interface integration contract.', + ); + assertCheck( + failures, + spec.includes('Gate 9 interface integration regression proof') && + spec.includes('BtdInterfaceIntegrationRegressionProof'), + 'V30 SPEC must define Gate 9 interface integration regression proof.', + ); + assertCheck( + failures, + delta.includes('Gate 9 implementation centers') && + delta.includes('/btd/interface-integration-regression'), + 'V30 DELTA must include Gate 9 implementation evidence.', + ); + assertCheck( + failures, + notes.includes('Gate 9 interface integration notes'), + 'V30 NOTES must include Gate 9 implementation notes.', + ); + assertCheck( + failures, + parity.includes('## Gate 9 Parity') && parity.includes('Gate 9 accepted boundaries'), + 'V30 PARITY must include Gate 9 parity and accepted boundaries.', + ); + assertCheck(failures, packageJson.includes('"check:v30-gate9"'), 'package.json must expose check:v30-gate9.'); + assertCheck( + failures, + gateWorkflow.includes('check-v30-gate9-interface-integration-regression-proof.mjs'), + 'Gate workflow must run the V30 Gate 9 checker.', + ); + assertCheck( + failures, + gateWorkflow.includes('terminalInterfaceIntegrationRegression.test.ts'), + 'Gate workflow must run Terminal interface integration regression tests.', + ); + + if (failures.length) { + process.stderr.write('V30 Gate 9 interface integration regression proof check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V30 Gate 9 interface integration regression proof check passed.\n'); +} + +main(); diff --git a/tsconfig.json b/tsconfig.json index f2bf4f74c..8c50c3ed7 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -169,6 +169,7 @@ "@bitcode/dryrun": ["packages/observability/src/dryrun.ts"], "@bitcode/dryrun/*": ["packages/observability/src/dryrun/*"], "@bitcode/dockerUtils": ["packages/docker/src/index.ts"], + "@bitcode/btd/interface-integration-contract": ["packages/btd/src/interface-integration-contract.ts"], "@bitcode/supabase": ["packages/supabase/src/index.ts"], // Git helpers alias (defined earlier; keep only one canonical mapping) "@/lib/validation/validationOTFAdherencePhaseModule": ["packages/validation/validationOTFAdherencePhaseModule.ts"], diff --git a/uapi/app/api/btd/interface-integration-regression/route.ts b/uapi/app/api/btd/interface-integration-regression/route.ts new file mode 100644 index 000000000..c5df90868 --- /dev/null +++ b/uapi/app/api/btd/interface-integration-regression/route.ts @@ -0,0 +1,3 @@ +import { postBtdInterfaceIntegrationRegression } from '@bitcode/api'; + +export const POST = postBtdInterfaceIntegrationRegression; diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 8b84441fc..63eb4748f 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -167,6 +167,15 @@ show event, subject kind, subject id, severity, and proof compatibility; expanded metadata may show roots, theorem ids, replay steps, witness artifact paths, and generated artifact paths, but never protected source or secrets. +Interface integration regression proof enters Terminal through the client-safe +`@bitcode/btd/interface-integration-contract` subpath and the server-side +`/btd/interface-integration-regression` route. Terminal records the current +Terminal, API, MCP, ChatGPT App, Auxillaries hook, and Exchange hook consumers +as package-owned BTD object consumers. The low-detail cockpit must remain +source-safe, and the proof must reject route-local BTD policy copies, source +leakage, or selected-transaction behavior regression before Gate 10 promotion +readiness. + The Organization Authority section is the selected-activity permission explainer. It projects registry-derived organization role, explicit grants, wallet binding, owner-read or licensed-read access, settlement state, diff --git a/uapi/app/terminal/terminal-interface-integration-regression.ts b/uapi/app/terminal/terminal-interface-integration-regression.ts new file mode 100644 index 000000000..57bde0a27 --- /dev/null +++ b/uapi/app/terminal/terminal-interface-integration-regression.ts @@ -0,0 +1,92 @@ +import { + BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES, + BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES, + type BtdInterfaceIntegrationRecordInput, +} from '@bitcode/btd/interface-integration-contract'; + +export type TerminalInterfaceIntegrationRegressionSummary = { + surfaces: typeof BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES; + objectFamilies: typeof BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES; + lowDetailSourceSafe: true; + transactionCockpitRegression: false; + routeLocalReimplementation: false; + records: BtdInterfaceIntegrationRecordInput[]; +}; + +const recordDefaults = { + packageOwned: true, + routeLocalReimplementation: false, + sourceSafeLowDetailIntact: true, + transactionCockpitRegression: false, + notes: ['Terminal consumes package-owned Protocol objects through a source-safe contract'], +} as const; + +export function buildTerminalInterfaceIntegrationRegressionRecords(): BtdInterfaceIntegrationRecordInput[] { + return [ + { + ...recordDefaults, + surface: 'terminal', + consumerId: 'terminal-transaction-cockpit', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_registry', 'read_access', 'terminal_journal'], + proofRoot: 'terminal-interface-regression-proof-root', + }, + { + ...recordDefaults, + surface: 'api', + consumerId: 'btd-api-route-boundary', + packageExport: '@bitcode/btd', + adapterPath: 'packages/api/src/routes/btd-crypto.ts', + objectFamilies: ['btd_receipts', 'btc_fee_operation', 'ledger_projection', 'protocol_telemetry'], + proofRoot: 'api-interface-regression-proof-root', + }, + { + ...recordDefaults, + surface: 'mcp', + consumerId: 'bitcode-mcp-interface', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'packages/executions-mcp/src/mcp-server/src/interface-integration.ts', + objectFamilies: ['source_to_shares_proof', 'organization_authority'], + proofRoot: 'mcp-interface-regression-proof-root', + }, + { + ...recordDefaults, + surface: 'chatgpt_app', + consumerId: 'bitcode-chatgpt-app-interface', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'packages/chatgptapp/src/interface-integration.ts', + objectFamilies: ['read_access', 'organization_authority'], + proofRoot: 'chatgpt-interface-regression-proof-root', + }, + { + ...recordDefaults, + surface: 'auxillaries_hook', + consumerId: 'auxillaries-interface-hook', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_registry', 'organization_authority'], + proofRoot: 'auxillaries-interface-regression-proof-root', + }, + { + ...recordDefaults, + surface: 'exchange_hook', + consumerId: 'exchange-interface-hook', + packageExport: '@bitcode/btd/interface-integration-contract', + adapterPath: 'uapi/app/terminal/terminal-interface-integration-regression.ts', + objectFamilies: ['btd_receipts', 'btc_fee_operation', 'ledger_projection'], + proofRoot: 'exchange-interface-regression-proof-root', + }, + ]; +} + +export function buildTerminalInterfaceIntegrationRegressionSummary(): TerminalInterfaceIntegrationRegressionSummary { + return { + surfaces: BTD_INTERFACE_INTEGRATION_REQUIRED_SURFACES, + objectFamilies: BTD_INTERFACE_INTEGRATION_REQUIRED_OBJECT_FAMILIES, + lowDetailSourceSafe: true, + transactionCockpitRegression: false, + routeLocalReimplementation: false, + records: buildTerminalInterfaceIntegrationRegressionRecords(), + }; +} diff --git a/uapi/app/terminal/terminal-protocol-projection.ts b/uapi/app/terminal/terminal-protocol-projection.ts index 5811d93a4..d8ca20867 100644 --- a/uapi/app/terminal/terminal-protocol-projection.ts +++ b/uapi/app/terminal/terminal-protocol-projection.ts @@ -7,6 +7,7 @@ import type { TerminalRepositoryContextState } from './terminal-repository-conte import type { WorkspaceRun } from './terminal-run-data'; import { normalizeTerminalSupplySelection } from './terminal-supply-selection'; import type { TerminalRunDetailSnapshot } from './terminal-transaction-detail-snapshot'; +import { buildTerminalInterfaceIntegrationRegressionSummary } from './terminal-interface-integration-regression'; function normalizeWhitespace(value?: string | null) { return value?.trim() || ''; @@ -171,6 +172,7 @@ export function buildProtocolProjectedRunDetail( const supplySelection = normalizeTerminalSupplySelection(snapshot, repositoryContext); const selectedAuthSession = supplySelection?.authSessions.find((session) => session.selected) || supplySelection?.authSessions[0] || null; + const interfaceIntegrationRegression = buildTerminalInterfaceIntegrationRegressionSummary(); return { summary: readSummary(snapshot, repositoryLabel, scenarioLabel, canonicalType), @@ -260,6 +262,14 @@ export function buildProtocolProjectedRunDetail( }, } : {}), + interfaceIntegrationRegression: { + surfaceCount: interfaceIntegrationRegression.surfaces.length, + objectFamilyCount: interfaceIntegrationRegression.objectFamilies.length, + recordCount: interfaceIntegrationRegression.records.length, + lowDetailSourceSafe: interfaceIntegrationRegression.lowDetailSourceSafe, + routeLocalReimplementation: interfaceIntegrationRegression.routeLocalReimplementation, + transactionCockpitRegression: interfaceIntegrationRegression.transactionCockpitRegression, + }, } : null, historyItemCount: readItemCount(snapshot), diff --git a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts index 899c8748d..495456844 100644 --- a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts +++ b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts @@ -161,6 +161,14 @@ export interface TerminalRunDetailSnapshot { inventorySource?: string | null; }; } | null; + interfaceIntegrationRegression?: { + surfaceCount: number; + objectFamilyCount: number; + recordCount: number; + lowDetailSourceSafe: true; + routeLocalReimplementation: false; + transactionCockpitRegression: false; + }; } | null; historyItemCount: number; eventCount: number; diff --git a/uapi/jest.config.cjs b/uapi/jest.config.cjs index e1a7f09f9..9930beb29 100644 --- a/uapi/jest.config.cjs +++ b/uapi/jest.config.cjs @@ -140,6 +140,8 @@ module.exports = { '/tests/terminalSupplySelectionPanel.test.tsx', '/tests/terminalDepositReadWorkbench.test.ts', '/tests/terminalPipelineHarnessClient.test.ts', + '/tests/terminalProtocolProjection.test.ts', + '/tests/terminalInterfaceIntegrationRegression.test.ts', '/tests/pipelineExecutionLogHeader.test.tsx', '/tests/terminalJournalReconciliation.test.ts', '/tests/terminalOrganizationAuthority.test.ts', diff --git a/uapi/tests/terminalInterfaceIntegrationRegression.test.ts b/uapi/tests/terminalInterfaceIntegrationRegression.test.ts new file mode 100644 index 000000000..5e34bbc87 --- /dev/null +++ b/uapi/tests/terminalInterfaceIntegrationRegression.test.ts @@ -0,0 +1,53 @@ +import { + buildTerminalInterfaceIntegrationRegressionRecords, + buildTerminalInterfaceIntegrationRegressionSummary, +} from '@/app/terminal/terminal-interface-integration-regression'; + +describe('terminal interface integration regression contract', () => { + it('keeps Terminal source-safe low-detail proof while listing package-owned consumers', () => { + const summary = buildTerminalInterfaceIntegrationRegressionSummary(); + + expect(summary.surfaces).toEqual([ + 'terminal', + 'api', + 'mcp', + 'chatgpt_app', + 'auxillaries_hook', + 'exchange_hook', + ]); + expect(summary.objectFamilies).toEqual([ + 'btd_registry', + 'read_access', + 'btd_receipts', + 'btc_fee_operation', + 'ledger_projection', + 'source_to_shares_proof', + 'protocol_telemetry', + 'organization_authority', + 'terminal_journal', + ]); + expect(summary.lowDetailSourceSafe).toBe(true); + expect(summary.routeLocalReimplementation).toBe(false); + expect(summary.transactionCockpitRegression).toBe(false); + expect(summary.records).toHaveLength(6); + expect(summary.records.every((record) => record.packageOwned)).toBe(true); + expect(summary.records.every((record) => record.sourceSafeLowDetailIntact)).toBe(true); + }); + + it('names the current interface hooks without exposing protected AssetPack source', () => { + const records = buildTerminalInterfaceIntegrationRegressionRecords(); + + expect(records.map((record) => record.surface)).toEqual([ + 'terminal', + 'api', + 'mcp', + 'chatgpt_app', + 'auxillaries_hook', + 'exchange_hook', + ]); + expect(records.flatMap((record) => record.objectFamilies)).toEqual( + expect.arrayContaining(['source_to_shares_proof', 'protocol_telemetry', 'terminal_journal']), + ); + expect(JSON.stringify(records)).not.toMatch(/protected source|private source|raw source/i); + }); +}); diff --git a/uapi/tests/terminalProtocolProjection.test.ts b/uapi/tests/terminalProtocolProjection.test.ts index b4d64b777..5ba664e43 100644 --- a/uapi/tests/terminalProtocolProjection.test.ts +++ b/uapi/tests/terminalProtocolProjection.test.ts @@ -131,7 +131,7 @@ describe('terminal-protocol-projection', () => { branch: 'main', }, bitcodeActivityState: { - giveWorkbench: { + depositWorkbench: { projectionPrincipal: 'depositor', scenarioLabel: 'auth-remediation', }, @@ -214,6 +214,14 @@ describe('terminal-protocol-projection', () => { fullName: 'bitcode/terminal', }, }, + interfaceIntegrationRegression: { + surfaceCount: 6, + objectFamilyCount: 9, + recordCount: 6, + lowDetailSourceSafe: true, + routeLocalReimplementation: false, + transactionCockpitRegression: false, + }, }, }); }); diff --git a/uapi/tsconfig.json b/uapi/tsconfig.json index 7c2094420..9dddcb9aa 100644 --- a/uapi/tsconfig.json +++ b/uapi/tsconfig.json @@ -43,6 +43,9 @@ "@bitcode/btd/terminal-operational-health": [ "../packages/btd/src/terminal-operational-health.ts" ], + "@bitcode/btd/interface-integration-contract": [ + "../packages/btd/src/interface-integration-contract.ts" + ], "@bitcode/pipeline-asset-pack": [ "../packages/pipelines/asset-pack/src/index.ts" ], From 5ca8f99202d96ecb62dcf9bbcf23745c770db6a4 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 20:44:10 -0300 Subject: [PATCH 11/15] V30 Gate 10: Prove promotion readiness Add the V30 promotion workflow, Gate 10 readiness checker, promotion command support, and generated V30 proof artifacts. Extend canonical proven generation and runtime/spec-family promotion helpers for V30, update roadmap and QA documentation, and wire Gate 10 into repository checks.\n\nProof: pnpm run check:v30-gate10; git diff --cached --check; staged secret-marker scan for Supabase/OpenAI credential markers. --- .bitcode/v30-canon-posture-drift-report.json | 85 + .bitcode/v30-canonical-input-report.json | 24 + .../v30-protocol-telemetry-proof-hooks.json | 45 + .bitcode/v30-spec-family-report.json | 34 + .github/workflows/bitcode-canon-quality.yml | 11 +- .github/workflows/bitcode-gate-quality.yml | 6 + .github/workflows/v30-canon-promotion.yml | 147 + BITCODE_SPEC_V30.md | 15 +- BITCODE_SPEC_V30_DELTA.md | 11 +- BITCODE_SPEC_V30_NOTES.md | 33 +- BITCODE_SPEC_V30_PARITY_MATRIX.md | 20 +- BITCODE_SPEC_V30_PROVEN.md | 2632 +++++++++++++++++ BITCODE_V30_QA.md | 44 + README.md | 8 +- SPECIFICATIONS_ROADMAP.md | 3 +- package.json | 1 + packages/protocol/README.md | 3 + .../src/canonical/proven-generator.js | 252 ++ .../protocol/src/canonical/v21-specifying.js | 9 + .../check-v30-gate10-promotion-readiness.mjs | 292 ++ ...repare-bitcode-runtime-canon-promotion.mjs | 3 + .../prepare-bitcode-spec-family-promotion.mjs | 33 +- scripts/promote-bitcode-canon.mjs | 125 +- 23 files changed, 3816 insertions(+), 20 deletions(-) create mode 100644 .bitcode/v30-canon-posture-drift-report.json create mode 100644 .bitcode/v30-canonical-input-report.json create mode 100644 .bitcode/v30-protocol-telemetry-proof-hooks.json create mode 100644 .bitcode/v30-spec-family-report.json create mode 100644 .github/workflows/v30-canon-promotion.yml create mode 100644 BITCODE_SPEC_V30_PROVEN.md create mode 100644 BITCODE_V30_QA.md create mode 100644 scripts/check-v30-gate10-promotion-readiness.mjs diff --git a/.bitcode/v30-canon-posture-drift-report.json b/.bitcode/v30-canon-posture-drift-report.json new file mode 100644 index 000000000..fd89863d4 --- /dev/null +++ b/.bitcode/v30-canon-posture-drift-report.json @@ -0,0 +1,85 @@ +{ + "reportId": "v30-canon-posture-drift-report", + "version": "V30", + "checkedActiveCanonVersion": "V30", + "checkedDraftTargetVersion": "V31", + "pointerVersion": "V29", + "proofSourceCommit": "f1771573c885652055c86ced1b43ba06a3ba7706", + "generatedAt": "2026-05-21T20:27:10-03:00", + "generatorId": "bitcode.proven-generator.v1", + "worktreeState": "dirty-preview", + "passed": false, + "checkCount": 10, + "blockingFailureCount": 7, + "blockingFailures": [ + "pointer-active-canon-alignment: BITCODE_SPEC.txt points to V29 while runtime expects V30.", + "canon-posture-constant-alignment: canon-posture constants resolve V29/V30 with operator label V29 active canon / V30 system draft.", + "proven-appendix-alignment: active generated appendix path is BITCODE_SPEC_V29_PROVEN.md.", + "policy-ref-alignment: policy reference is policy://bitcode/spec-v29-active-v30-system-draft/current.", + "runtime-state-alignment: buildInitialState() reports Bitcode Spec V29 active canon / V30 system draft with canon posture V29/V30.", + "public-state-alignment: publicState() reports Bitcode Spec V29 active canon / V30 system draft with canon posture V29/V30.", + "readme-alignment: README states V30 active canon and BITCODE_SPEC_V29_PROVEN.md as the current generated appendix." + ], + "runtimeSpecVersion": "Bitcode Spec V29 active canon / V30 system draft", + "publicSpecVersion": "Bitcode Spec V29 active canon / V30 system draft", + "activeProvenAppendixPath": "BITCODE_SPEC_V29_PROVEN.md", + "policyRef": "policy://bitcode/spec-v29-active-v30-system-draft/current", + "checkedFiles": [ + "protocol-demonstration/README.md", + "protocol-demonstration/public/index.html", + "protocol-demonstration/public/app.js", + "protocol-demonstration/server.js" + ], + "checks": [ + { + "checkId": "pointer-active-canon-alignment", + "passed": false, + "detail": "BITCODE_SPEC.txt points to V29 while runtime expects V30." + }, + { + "checkId": "canon-posture-constant-alignment", + "passed": false, + "detail": "canon-posture constants resolve V29/V30 with operator label V29 active canon / V30 system draft." + }, + { + "checkId": "proven-appendix-alignment", + "passed": false, + "detail": "active generated appendix path is BITCODE_SPEC_V29_PROVEN.md." + }, + { + "checkId": "policy-ref-alignment", + "passed": false, + "detail": "policy reference is policy://bitcode/spec-v29-active-v30-system-draft/current." + }, + { + "checkId": "runtime-state-alignment", + "passed": false, + "detail": "buildInitialState() reports Bitcode Spec V29 active canon / V30 system draft with canon posture V29/V30." + }, + { + "checkId": "public-state-alignment", + "passed": false, + "detail": "publicState() reports Bitcode Spec V29 active canon / V30 system draft with canon posture V29/V30." + }, + { + "checkId": "server-api-alignment", + "passed": true, + "detail": "server.js keeps API posture sourced from SPEC_VERSION and buildPublicState(...)." + }, + { + "checkId": "browser-shell-placeholder-alignment", + "passed": true, + "detail": "public/index.html exposes canon-posture placeholders and no stale hardcoded hero posture." + }, + { + "checkId": "browser-shell-render-alignment", + "passed": true, + "detail": "public/app.js renders canon posture from runtime state and omits stale V15 explainer keys." + }, + { + "checkId": "readme-alignment", + "passed": false, + "detail": "README states V30 active canon and BITCODE_SPEC_V29_PROVEN.md as the current generated appendix." + } + ] +} diff --git a/.bitcode/v30-canonical-input-report.json b/.bitcode/v30-canonical-input-report.json new file mode 100644 index 000000000..a83923e32 --- /dev/null +++ b/.bitcode/v30-canonical-input-report.json @@ -0,0 +1,24 @@ +{ + "reportId": "v30-canonical-input-report", + "version": "V30", + "proofSourceCommit": "f1771573c885652055c86ced1b43ba06a3ba7706", + "generatedAt": "2026-05-21T20:27:10-03:00", + "generatorId": "bitcode.proven-generator.v1", + "worktreeState": "dirty-preview", + "checkedTargetVersion": "V30", + "pointerVersion": "V29", + "passed": true, + "failureCount": 0, + "failures": [], + "specPath": "BITCODE_SPEC_V30.md", + "notesPath": "BITCODE_SPEC_V30_NOTES.md", + "provenPath": "BITCODE_SPEC_V30_PROVEN.md", + "parityPath": "BITCODE_SPEC_V30_PARITY_MATRIX.md", + "requiredGeneratedArtifactPaths": [ + ".bitcode/v30-spec-family-report.json", + ".bitcode/v30-canonical-input-report.json", + ".bitcode/v30-canon-posture-drift-report.json", + ".bitcode/v30-protocol-telemetry-proof-hooks.json" + ], + "requiredGeneratedArtifactCount": 4 +} diff --git a/.bitcode/v30-protocol-telemetry-proof-hooks.json b/.bitcode/v30-protocol-telemetry-proof-hooks.json new file mode 100644 index 000000000..c1bef9d70 --- /dev/null +++ b/.bitcode/v30-protocol-telemetry-proof-hooks.json @@ -0,0 +1,45 @@ +{ + "reportId": "v30-protocol-telemetry-proof-hooks", + "version": "V30", + "proofSourceCommit": "f1771573c885652055c86ced1b43ba06a3ba7706", + "generatedAt": "2026-05-21T20:27:10-03:00", + "generatorId": "bitcode.proven-generator.v1", + "worktreeState": "dirty-preview", + "passed": true, + "sourceSafe": true, + "checkedFileCount": 12, + "checkedFiles": [ + "packages/btd/src/telemetry.ts", + "packages/btd/src/api-boundaries.ts", + "packages/btd/__tests__/telemetry.test.ts", + "packages/api/src/routes/btd-crypto.ts", + "packages/api/src/routes/__tests__/btd-crypto.test.ts", + "uapi/app/api/btd/protocol-telemetry/route.ts", + "packages/btd/README.md", + "uapi/app/terminal/README.md", + "BITCODE_SPEC_V30.md", + "BITCODE_SPEC_V30_DELTA.md", + "BITCODE_SPEC_V30_NOTES.md", + "BITCODE_SPEC_V30_PARITY_MATRIX.md" + ], + "requiredTelemetryFamilies": [ + "btd_receipt", + "btc_fee_state", + "ledger_projection", + "source_to_shares_proof", + "bridge_readiness_posture" + ], + "proofHookCoverage": [ + "theorem ids", + "replay step ids", + "witness artifact paths", + "generated artifact paths", + "evidence roots", + "telemetry roots" + ], + "compatibleWith": [ + "V32", + "V35" + ], + "failures": [] +} diff --git a/.bitcode/v30-spec-family-report.json b/.bitcode/v30-spec-family-report.json new file mode 100644 index 000000000..1b66e90a1 --- /dev/null +++ b/.bitcode/v30-spec-family-report.json @@ -0,0 +1,34 @@ +{ + "reportId": "v30-spec-family-report", + "version": "V30", + "proofSourceCommit": "f1771573c885652055c86ced1b43ba06a3ba7706", + "generatedAt": "2026-05-21T20:27:10-03:00", + "generatorId": "bitcode.proven-generator.v1", + "worktreeState": "dirty-preview", + "checkedVersion": "V30", + "mode": "draft", + "currentTarget": "V29", + "pointerVersion": "V29", + "passed": true, + "failureCount": 0, + "failures": [], + "requiredFiles": [ + "BITCODE_SPEC_V30.md", + "BITCODE_SPEC_V30_DELTA.md", + "BITCODE_SPEC_V30_NOTES.md", + "BITCODE_SPEC_V30_PARITY_MATRIX.md" + ], + "supportFiles": [ + "BITCODE_SPECIFYING.md", + "BITCODE_SPEC_TEMPLATEGUIDE.md" + ], + "requiredStatusLabelCount": 4, + "requiredPromotedStatusLabelCount": 1, + "requiredSpecSectionCount": 18, + "requiredAppendixSectionCount": 14, + "requiredProofFamilyCount": 9, + "requiredGeneratedArtifactCatalogSectionCount": 9, + "requiredGeneratedArtifactPathCount": 4, + "requiredNotesSectionCount": 4, + "requiredSubsystemCoverageCount": 18 +} diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index c07148f3c..40410fdd5 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -33,6 +33,10 @@ jobs: node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V29 --draft-target V30 node scripts/check-bitcode-spec-family.mjs --version V29 --mode promoted --current-target V29 node scripts/check-bitcode-spec-family.mjs --version V30 --mode draft --current-target V29 + elif [ "$POINTER" = "V30" ]; then + node scripts/check-bitcode-canonical-inputs.mjs --current-target V30 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V30 --draft-target V31 + node scripts/check-bitcode-spec-family.mjs --version V30 --mode promoted --current-target V30 else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 @@ -77,7 +81,12 @@ jobs: fi ;; spec:\ V30*|spec:\ v30*) - node scripts/check-bitcode-spec-family.mjs --version V30 --mode draft --current-target V29 + POINTER="$(cat BITCODE_SPEC.txt)" + if [ "$POINTER" = "V30" ]; then + node scripts/check-bitcode-spec-family.mjs --version V30 --mode promoted --current-target V30 + else + node scripts/check-bitcode-spec-family.mjs --version V30 --mode draft --current-target V29 + fi ;; *) echo "Skipping strict spec-title conformance; title is not a V29/V30 spec change." diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 175a7d65c..dd91281a9 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -88,6 +88,12 @@ jobs: node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs --skip-branch-check node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs --skip-branch-check node scripts/check-v30-gate9-interface-integration-regression-proof.mjs --skip-branch-check + node scripts/check-v30-gate10-promotion-readiness.mjs --promotion-mode --skip-branch-check + elif [ "$POINTER" = "V30" ]; then + node scripts/check-bitcode-spec-family.mjs --version V30 --mode promoted --current-target V30 + node scripts/check-bitcode-canonical-inputs.mjs --current-target V30 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V30 --draft-target V31 + node scripts/check-v30-gate10-promotion-readiness.mjs --promotion-mode --skip-branch-check else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 exit 1 diff --git a/.github/workflows/v30-canon-promotion.yml b/.github/workflows/v30-canon-promotion.yml new file mode 100644 index 000000000..8b74197c0 --- /dev/null +++ b/.github/workflows/v30-canon-promotion.yml @@ -0,0 +1,147 @@ +name: V30 Canon Promotion + +on: + pull_request: + branches: + - main + types: + - opened + - synchronize + - reopened + - ready_for_review + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +permissions: + contents: write + pull-requests: read + +jobs: + promote-v30: + name: V30 Promotion Validation + if: >- + ${{ + github.event_name == 'workflow_dispatch' || + ( + github.event.pull_request.base.ref == 'main' && + github.event.pull_request.head.ref == 'version/v30' && + github.event.pull_request.head.repo.full_name == github.repository + ) + }} + runs-on: ubuntu-latest + + steps: + - name: Checkout version branch + uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.ref || github.ref_name }} + token: ${{ github.token }} + fetch-depth: 0 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node + uses: actions/setup-node@v4 + with: + node-version: "24" + cache: pnpm + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Validate V30 promotion readiness + run: | + POINTER="$(cat BITCODE_SPEC.txt)" + if [ "$POINTER" = "V29" ]; then + node scripts/check-bitcode-spec-family.mjs --version V30 --mode draft --current-target V29 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V29 --draft-target V30 + node scripts/check-bitcode-canonical-inputs.mjs --current-target V29 + node scripts/check-v30-gate1-roadmap-and-gating.mjs --skip-branch-check + node scripts/check-v30-gate2-protocol-package-api-boundaries.mjs --skip-branch-check + node scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs --skip-branch-check + node scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs --skip-branch-check + node scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs --skip-branch-check + node scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs --skip-branch-check + node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs --skip-branch-check + node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs --skip-branch-check + node scripts/check-v30-gate9-interface-integration-regression-proof.mjs --skip-branch-check + node scripts/check-v30-gate10-promotion-readiness.mjs --promotion-mode --skip-branch-check + node scripts/promote-bitcode-canon.mjs --version V30 --commit HEAD --dry-run + elif [ "$POINTER" = "V30" ]; then + node scripts/check-bitcode-spec-family.mjs --version V30 --mode promoted --current-target V30 + node scripts/check-bitcode-canonical-inputs.mjs --current-target V30 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V30 --draft-target V31 + node scripts/check-v30-gate10-promotion-readiness.mjs --promotion-mode --skip-branch-check + else + echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 + exit 1 + fi + pnpm test:qa:v28:pipeline-readback + pnpm --filter @bitcode/protocol typecheck + pnpm --filter @bitcode/protocol test + pnpm --filter @bitcode/btd typecheck + pnpm --filter @bitcode/btd test + npm --prefix protocol-demonstration test + npm --prefix protocol-demonstration run test:v28-mvp-qa + pnpm --filter @bitcode/pipeline-asset-pack typecheck + pnpm --filter @bitcode/pipeline-hosts typecheck + pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --passWithNoTests --forceExit + pnpm --filter @bitcode/pipeline-hosts exec jest --config jest.config.cjs --passWithNoTests --forceExit + pnpm --dir uapi exec jest --runTestsByPath \ + tests/api/readReviewRoute.test.ts \ + tests/api/pipelineHarnessRoute.test.ts \ + tests/terminalPipelineHarnessClient.test.ts \ + tests/terminalDepositReadWorkbench.test.ts \ + tests/terminalTransactionQuery.test.ts \ + tests/terminalTransactionReadModel.test.ts \ + tests/terminalProtocolProjection.test.ts \ + tests/terminalInterfaceIntegrationRegression.test.ts \ + tests/terminalWalletBtcOperation.test.ts \ + tests/terminalJournalReconciliation.test.ts \ + tests/terminalOrganizationAuthority.test.ts \ + tests/protocolCommercialBoundary.test.ts \ + tests/terminalTransactionDetailCards.test.tsx \ + tests/terminalTransactionDetailSnapshot.test.ts \ + tests/terminalUxBrowserProof.test.tsx \ + tests/pipelineExecutionLogHeader.test.tsx \ + --runInBand + pnpm --dir uapi exec playwright install chromium --with-deps + pnpm --dir uapi run test:e2e:terminal-ux + git diff --check + + - name: Promote V30 canon files + if: >- + ${{ + github.event_name == 'pull_request' && + github.event.pull_request.head.ref == 'version/v30' + }} + env: + HEAD_BRANCH: ${{ github.event.pull_request.head.ref }} + run: | + if [ "$(cat BITCODE_SPEC.txt)" = "V30" ]; then + echo "BITCODE_SPEC.txt already points to V30." + exit 0 + fi + PROOF_SOURCE_COMMIT="$(git rev-parse HEAD)" + npm run promote:canon -- --version V30 --commit "$PROOF_SOURCE_COMMIT" + git config user.name "github-actions[bot]" + git config user.email "41898282+github-actions[bot]@users.noreply.github.com" + git add \ + BITCODE_SPEC.txt \ + BITCODE_SPEC_V30.md \ + BITCODE_SPEC_V30_DELTA.md \ + BITCODE_SPEC_V30_NOTES.md \ + BITCODE_SPEC_V30_PARITY_MATRIX.md \ + BITCODE_SPEC_V30_PROVEN.md \ + protocol-demonstration/src/canon-posture.js \ + protocol-demonstration/README.md \ + packages/protocol/src/canon-posture.js \ + packages/protocol/data/state.json \ + packages/protocol/README.md \ + .bitcode + git commit -m "Promote Bitcode canon to V30" + git push origin "HEAD:$HEAD_BRANCH" diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index 2e2737dd0..823bea409 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -7,8 +7,8 @@ - Current canonical/latest target: `V29` - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` -- Generated structured artifact inventory: none for V30 yet; V30 gate work must create `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, and `BITCODE_SPEC_V30_PROVEN.md` only as promotion evidence -- Source parity state: V30 source parity is draft-opened for Protocol/BTD package hardening, Bitcoin/PSBT rigor, BTD receipt boundaries, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness boundaries, telemetry hooks, and promotion automation +- Generated structured artifact inventory: V30 Gate 10 generates `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and `BITCODE_SPEC_V30_PROVEN.md` as promotion evidence +- Source parity state: V30 source parity is draft-opened for Protocol/BTD package hardening, Bitcoin/PSBT rigor, BTD receipt boundaries, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness boundaries, telemetry hooks, interface regression, and promotion automation - State: draft target opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` - Draft target source: `protocol-demonstration/src/canon-posture.js` declares `DRAFT_TARGET_VERSION = 'V30'` @@ -409,6 +409,17 @@ It closes when `version/v30` can be pull-requested to `main` and the V30 promotion workflow has enough scripted proof to produce the standalone canonical promotion commit. +Gate 10's source implementation is the V30 promotion-readiness control surface: +`scripts/check-v30-gate10-promotion-readiness.mjs`, +`scripts/promote-bitcode-canon.mjs`, `scripts/generate-bitcode-proven.mjs`, +`scripts/prepare-bitcode-spec-family-promotion.mjs`, +`scripts/prepare-bitcode-runtime-canon-promotion.mjs`, +`.github/workflows/v30-canon-promotion.yml`, and the generated +`.bitcode/v30-*` artifacts must agree on the same V29 draft / V30 promoted +transition. The generated telemetry artifact is source-safe and exists to bind +Gate 8 Protocol telemetry/proof hooks into promotion proof without exposing +protected source or secrets. + ## V30 Wallet/BTC operation canon Wallet and BTC fee state is an ordinary Terminal transaction surface, not an opaque settlement footnote. diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index 84eac3fb8..cb3f0a385 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -7,7 +7,7 @@ - Current canonical/latest target: `V29` - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` -- Generated structured artifact inventory: none for V30 yet; draft gates must create V30 reports and generated proof only as acceptance evidence +- Generated structured artifact inventory: V30 Gate 10 generates `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and `BITCODE_SPEC_V30_PROVEN.md` as promotion evidence - Source parity state: V30 source parity is draft-opened for Protocol/BTD package APIs, Bitcoin/Taproot/PSBT rigor, BTD receipts, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness boundaries, telemetry hooks, and promotion automation - State: draft target delta opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` @@ -329,3 +329,12 @@ Closure acceptance: - V30 promotion workflow validates source branch, local proof commands, staging-testnet readback evidence, generated `.bitcode/v30-*` reports, and `BITCODE_SPEC_V30_PROVEN.md`; - promotion scripts support V30 and rewrite post-promotion active V30 / draft V31 posture; - `version/v30` can be requested into `main` only after all V30 gates close. + +Gate 10 implementation centers: + +- `scripts/check-v30-gate10-promotion-readiness.mjs`; +- `.github/workflows/v30-canon-promotion.yml`; +- V30 support in `scripts/promote-bitcode-canon.mjs`; +- V30 status rewriting in `scripts/prepare-bitcode-spec-family-promotion.mjs`; +- V30 generated appendix/artifact support in `packages/protocol/src/canonical/proven-generator.js`; +- generated `.bitcode/v30-*` artifacts and source-safe `BITCODE_V30_QA.md`. diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index 9c1e866be..074636aa7 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -11,7 +11,7 @@ - Active generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` -- Generated structured artifact inventory: none for V30 yet +- Generated structured artifact inventory: V30 Gate 10 generates `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and `BITCODE_SPEC_V30_PROVEN.md` - Source parity state: V30 source parity begins with Gate 1 roadmap/gating and then closes through Protocol/BTD package API, Bitcoin/PSBT, BTD receipt, ledger projection, source-to-shares, bridge-readiness, telemetry/proof, interface-regression, and promotion-readiness gates - Scope: future notes for Protocol/BTD hardening after V28 commercial Protocol/Terminal MVP and V29 deeper Terminal work. Exchange is deferred beyond V35. @@ -249,7 +249,36 @@ Gate 8 rejects event/subject mismatches and secret-shaped metadata before a row can reach Terminal, API, generated proof, or persistence surfaces. The API boundary exposes `/btd/protocol-telemetry` as a JSON-safe proof-admission route; it does not commit source-bearing artifacts, and it does not replace existing -crypto telemetry rows used for deployment readiness health. +crypto telemetry rows used for deployment readiness health. Gate 10 carries +that same source-safety rule into generated promotion artifacts. + +## Gate 10 promotion-readiness notes + +Gate 10 is the V30 promotion-control closure. It does not change the active +pointer directly; it makes the version branch ready for the V30 promotion +workflow to do so from a clean `version/v30` pull request into `main`. + +The promotion-readiness implementation must validate four layers: + +- local proof: every V30 gate checker, Protocol package checks, BTD package + checks, pipeline package checks, UAPI route/Terminal tests, browser cockpit + proof, pipeline readback, and protocol demonstration QA; +- generated proof: `.bitcode/v30-spec-family-report.json`, + `.bitcode/v30-canonical-input-report.json`, + `.bitcode/v30-canon-posture-drift-report.json`, + `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and + `BITCODE_SPEC_V30_PROVEN.md`; +- workflow proof: gate-quality accepts V29/V30 draft state and V30/V31 promoted + state, canon-quality accepts V30 after promotion, and + `v30-canon-promotion.yml` commits the generated canon artifacts; +- staging-testnet readback: evidence is source-safe and names environment + readiness, Terminal cockpit readback, ledger/database/object-storage + reconciliation, package posture, and promotion dry-run status without + committing secrets. + +After promotion, runtime posture carriers must report V30 active and V31 as the +next draft target. V31's full draft family is opened by V31 Gate 1; V30 Gate 10 +only prepares the post-promotion pointer and runtime posture. ## Gate 9 interface integration notes diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index 2e768033d..384ece4db 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -7,7 +7,7 @@ - Current canonical/latest target: `V29` - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` -- Generated structured artifact inventory: none for V30 yet; V30 gates must create and validate generated artifacts before promotion +- Generated structured artifact inventory: V30 Gate 10 generates `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and `BITCODE_SPEC_V30_PROVEN.md` - Source parity state: V30 parity begins with roadmap/gating, then hardens package APIs, Bitcoin/PSBT, BTD receipts, ledger projection, source-to-shares proof, bridge-readiness boundaries, telemetry/proof hooks, interface regression, and promotion readiness - State: draft target parity matrix opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` @@ -63,7 +63,7 @@ No `_legacy/` source is active source truth. | Bridge-readiness research boundaries | Gate 7 | `packages/btd/src/bridge-readiness.ts`, BTD/API tests, route boundary, docs, gate checker | drafted | Bridge paths are typed research-only records until admitted by explicit future proof and policy. | | Protocol telemetry/proof hooks | Gate 8 | `packages/btd/src/telemetry.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Receipts, fee states, projections, source-to-shares proofs, and bridge-readiness posture emit source-safe telemetry and proof hooks. | | Interface integration regression | Gate 9 | `packages/btd/src/interface-integration.ts`, `packages/api/src/routes/btd-crypto.ts`, Terminal/MCP/ChatGPT adapters and tests, gate checker | drafted | Existing interfaces consume package-owned objects without regressing V29 behavior. | -| Promotion readiness | Gate 10 | V30 promotion workflow, generated `.bitcode/v30-*`, `BITCODE_SPEC_V30_PROVEN.md` | pending | `version/v30` can promote to `main` only after all V30 checks pass and promotion automation can commit generated canon. | +| Promotion readiness | Gate 10 | V30 promotion workflow, generated `.bitcode/v30-*`, `BITCODE_SPEC_V30_PROVEN.md` | drafted | `version/v30` can promote to `main` only after all V30 checks pass and promotion automation can commit generated canon. | ## V30 implementation checklist @@ -240,6 +240,22 @@ No `_legacy/` source is active source truth. | Source-safe low-detail and transaction cockpit regression are tested | BTD interface-integration tests, BTD crypto route tests, Terminal projection tests, MCP auth test, ChatGPT tools test | drafted | | Gate checker protects interface integration boundaries | `scripts/check-v30-gate9-interface-integration-regression-proof.mjs`, `pnpm run check:v30-gate9`, gate-quality workflow | drafted | +## Gate 10 Parity + +| Gate 10 surface | Source evidence | Judgment | Closure signal | +| --- | --- | --- | --- | +| V30 promotion checker | `scripts/check-v30-gate10-promotion-readiness.mjs`, `package.json`, gate-quality workflow | drafted | `pnpm run check:v30-gate10` validates V29/V30 draft state and V30/V31 promoted state. | +| V30 promotion workflow | `.github/workflows/v30-canon-promotion.yml` | drafted | `version/v30` pull requests into `main` run V30 proof, generate canon artifacts, and commit promotion output. | +| Promotion command support | `scripts/promote-bitcode-canon.mjs` | drafted | `--version V30` plans all V30 gate checks, package proof, UAPI/browser proof, generated appendix, and post-promotion validations. | +| Hand-authored status rewriting | `scripts/prepare-bitcode-spec-family-promotion.mjs` | drafted | V30 SPEC, DELTA, NOTES, and PARITY status lines are rewritten to promoted truth with proof-source commit. | +| Runtime posture rewriting | `scripts/prepare-bitcode-runtime-canon-promotion.mjs`, `packages/protocol/src/canon-posture.js`, `packages/protocol/data/state.json` | drafted | Promotion rewrites runtime posture from V29/V30 to V30/V31. | +| Generated artifact support | `packages/protocol/src/canonical/proven-generator.js`, `packages/protocol/src/canonical/v21-specifying.js`, `.bitcode/v30-*` | drafted | Spec-family, canonical-input, canon-posture, and Protocol telemetry proof-hook reports are generated and source-safe. | +| Source-safe QA ledger | `BITCODE_V30_QA.md` | drafted | Local and staging-testnet readiness evidence is recorded without secrets or protected source. | + +## Gate 10 completion condition + +Gate 10 is complete when `check:v30-gate10` passes, V30 promotion dry-run prints a full command plan, V30 generated artifacts are present and valid, local proof commands pass, documentation and specification files name the generated proof surface, the gate branch is committed and pushed, and the pull request into `version/v30` is green. + ## Gate 9 accepted boundaries - Gate 9 does not redesign Reading, settlement, source disclosure, organization authority, MCP, ChatGPT App, Auxillaries, or Exchange. diff --git a/BITCODE_SPEC_V30_PROVEN.md b/BITCODE_SPEC_V30_PROVEN.md new file mode 100644 index 000000000..42c49c478 --- /dev/null +++ b/BITCODE_SPEC_V30_PROVEN.md @@ -0,0 +1,2632 @@ +# Bitcode Spec V30 Proven + +- canonicalVersion: `V30` +- canonicalCommit: `f1771573c885652055c86ced1b43ba06a3ba7706` +- canonicalCommitRecordedAt: `2026-05-21T20:27:10-03:00` +- worktreeState: `dirty-preview` +- generatorId: `bitcode.proven-generator.v1` +- generatedAt: `2026-05-21T20:27:10-03:00` +- outputPath: `BITCODE_SPEC_V30_PROVEN.md` +- scenarioIds: `auth-issuer-rollback`, `rust-validator-proof-gap`, `config-policy-precedence-incident`, `unsafe-patch-review-recovery`, `infra-deployment-mismatch`, `privacy-boundary-proof-export`, `polyglot-gateway-benchmark-remediation`, `auth-many-asset-normalization` +- branchModes: `patch`, `context` + +## Aggregate Verdict + +- fullyProven: `false` +- runCount: `16` +- familyCount: `9` +- theoremCount: `58` +- memberCount: `46` +- artifactDigestCount: `736` +- v19PositiveMatrixCellCount: `1864` +- v19MutationCellCount: `10` +- v19MutationCoverageMode: `representative-first-gate` +- v19VolatilityBlockingFindings: `0` +- v19ReplayDeterministic: `true` +- v19ContractLedgerPassed: `true` +- v20QualityPassed: `true` +- v20QualityReportCount: `5` +- v20GeneratedQualityArtifactCount: `6` +- v20QualityBlockingFailures: `0` +- v20ProjectionSmokeCells: `4` + +## V19 Reproducible Canon Reports + +### V19 Generated Artifact Inventory + +| artifactPath | digest | byteLength | +| --- | --- | --- | +| `.bitcode/v19-contract-change-ledger.json` | `sha256:94b35e79de119c0a13a2d46ae7ad27ae2015ecdb3dc2cc3139d5e3b9b51ce6ea` | 3311 | +| `.bitcode/v19-deterministic-replay-report.json` | `sha256:86674e92f2e5dcc32c350d111423f62157baa8bea044ee1837cd4edaa2be0d4f` | 8459 | +| `.bitcode/v19-negative-proof-mutation-matrix.json` | `sha256:50a5750cd371aa15cb8da60dc02ada762aa4c6b977b469eb5d44e625aa75c47b` | 8085 | +| `.bitcode/v19-proof-member-semantic-matrix.json` | `sha256:ad6eb883dd76f2488ddcfc6bbd73ae2f5d3c6ebf50cb0ed3b80aa382ef4f180b` | 1815750 | +| `.bitcode/v19-state-machine-matrix.json` | `sha256:51c99848cc8fc2427d989e39fccca1c6024d2282f6896cf98e646c771ddf1529` | 154965 | +| `.bitcode/v19-theorem-evidence-matrix.json` | `sha256:cadb4106c003cbe3e572348a14d0ec987da647c4259477f0caca84ffacc907ae` | 2405676 | +| `.bitcode/v19-volatility-inventory.json` | `sha256:41ce5afc23b73d693cccbbc09a9db4263bd9cfb2b8d79128390a10dad5a83ac7` | 6206 | + +### V19 Inherited Positive Matrix Summaries + +| matrixId | sourceRunCount | cellCount | passedCellCount | failedCellCount | acceptedExclusionCount | +| --- | --- | --- | --- | --- | --- | +| `v19-proof-member-semantic-matrix` | 16 | 736 | 736 | 0 | 0 | +| `v19-theorem-evidence-matrix` | 16 | 928 | 928 | 0 | 0 | +| `v19-state-machine-matrix` | 16 | 200 | 200 | 0 | 0 | + +### V19 Deterministic Replay + +- reportId: `v19-deterministic-replay-report` +- runCount: `2` +- passed: `true` +- failureReason: `none` + +| artifactPath | firstDigest | secondDigest | byteEqual | +| --- | --- | --- | --- | +| `.bitcode/v19-contract-change-ledger.json` | `sha256:94b35e79de119c0a13a2d46ae7ad27ae2015ecdb3dc2cc3139d5e3b9b51ce6ea` | `sha256:94b35e79de119c0a13a2d46ae7ad27ae2015ecdb3dc2cc3139d5e3b9b51ce6ea` | `true` | +| `.bitcode/v19-negative-proof-mutation-matrix.json` | `sha256:50a5750cd371aa15cb8da60dc02ada762aa4c6b977b469eb5d44e625aa75c47b` | `sha256:50a5750cd371aa15cb8da60dc02ada762aa4c6b977b469eb5d44e625aa75c47b` | `true` | +| `.bitcode/v19-proof-member-semantic-matrix.json` | `sha256:ad6eb883dd76f2488ddcfc6bbd73ae2f5d3c6ebf50cb0ed3b80aa382ef4f180b` | `sha256:ad6eb883dd76f2488ddcfc6bbd73ae2f5d3c6ebf50cb0ed3b80aa382ef4f180b` | `true` | +| `.bitcode/v19-state-machine-matrix.json` | `sha256:51c99848cc8fc2427d989e39fccca1c6024d2282f6896cf98e646c771ddf1529` | `sha256:51c99848cc8fc2427d989e39fccca1c6024d2282f6896cf98e646c771ddf1529` | `true` | +| `.bitcode/v19-theorem-evidence-matrix.json` | `sha256:cadb4106c003cbe3e572348a14d0ec987da647c4259477f0caca84ffacc907ae` | `sha256:cadb4106c003cbe3e572348a14d0ec987da647c4259477f0caca84ffacc907ae` | `true` | +| `.bitcode/v19-volatility-inventory.json` | `sha256:41ce5afc23b73d693cccbbc09a9db4263bd9cfb2b8d79128390a10dad5a83ac7` | `sha256:41ce5afc23b73d693cccbbc09a9db4263bd9cfb2b8d79128390a10dad5a83ac7` | `true` | +| `_legacy/ENGI_SPEC_V19_PROVEN.md` | `sha256:5fc14d4cc38c116d1e3e30daaf625e3264d740f6906fa170e4fbc3595f8cd7d4` | `sha256:5fc14d4cc38c116d1e3e30daaf625e3264d740f6906fa170e4fbc3595f8cd7d4` | `true` | + +### V19 Volatility Inventory + +- inventoryId: `v19-volatility-inventory` +- scannedArtifactCount: `4` +- findingCount: `21` +- blockingFindingCount: `0` +- passed: `true` + +| classification | count | +| --- | --- | +| `canonical-stable` | 16 | +| `context-bound` | 5 | +| `preview-volatile` | 0 | +| `blocking-volatile` | 0 | + +### V19 Negative Proof Mutation Matrix + +- matrixId: `v19-negative-proof-mutation-matrix` +- coverageMode: `representative-first-gate` +- mutationClassCount: `10` +- cellCount: `10` +- rejectedCellCount: `10` +- unexpectedPassCount: `0` +- unexpectedErrorCount: `0` + +| mutationClass | expectedErrorClass | actualErrorClass | rejectedAsExpected | +| --- | --- | --- | --- | +| `missing-digest` | `missing-digest` | `missing-digest` | `true` | +| `proof-family-catalog-drift` | `catalog-drift` | `catalog-drift` | `true` | +| `corrupted-replay-step` | `corrupted-replay-step` | `corrupted-replay-step` | `true` | +| `dropped-theorem-verdict` | `missing-theorem-verdict` | `missing-theorem-verdict` | `true` | +| `mutated-member-payload` | `member-predicate-failed` | `member-predicate-failed` | `true` | +| `changed-projection-policy` | `projection-policy-mismatch` | `projection-policy-mismatch` | `true` | +| `missing-witness-path` | `missing-witness-path` | `missing-witness-path` | `true` | +| `changed-matrix-axis` | `changed-matrix-axis` | `changed-matrix-axis` | `true` | +| `unsorted-artifact-inventory` | `unsorted-artifact-inventory` | `unsorted-artifact-inventory` | `true` | +| `volatile-timestamp` | `volatile-timestamp` | `volatile-timestamp` | `true` | + +### V19 Omitted Mutation Cross-Products + +| omittedPermutation | reason | reopenCondition | +| --- | --- | --- | +| `every mutation class across every proof family member` | representative fail-closed class coverage is the V19 target | a member-payload mutation passes unexpectedly or failure classification varies by member class | +| `every mutation class across every theorem id` | V18 theorem evidence matrix already proves positive theorem coverage | a theorem mutation passes unexpectedly or replay-step validation varies by theorem group | +| `every mutation class across every artifact path` | digest, path, and inventory classes are sampled by required artifact category | missing-path, missing-digest, or artifact-inventory mutation has path-specific behavior | +| `every mutation class across every scenario and branch mode` | required only where mutation target varies by run | a mutation result differs by scenario or branch mode | +| `projection mutation across every principal` | full projection behavior is inherited from V17 browser proof | projection policy source changes or visibility changes | +| `mutation under every materialization mode` | V19 accepts committed generated artifacts as the only canonical mode | a side-artifact or preview-only materialization mode is introduced | + +### V19 Contract-Change Ledger + +- ledgerId: `v19-contract-change-ledger` +- fromVersion: `V18` +- toVersion: `V19` +- passed: `true` +- proofCatalogDelta: `unchanged-inherited-positive-baseline` + +| changeType | fromMatrixId | toMatrixId | cellCount | +| --- | --- | --- | --- | +| `renamed-materialized-artifact` | `v18-proof-member-semantic-matrix` | `v19-proof-member-semantic-matrix` | 736 | +| `renamed-materialized-artifact` | `v18-theorem-evidence-matrix` | `v19-theorem-evidence-matrix` | 928 | +| `renamed-materialized-artifact` | `v18-state-machine-matrix` | `v19-state-machine-matrix` | 200 | +| `added-negative-proof-coverage` | `none` | `v19-negative-proof-mutation-matrix` | 10 | + +## V20 Operator Quality Reports + +### V20 Generated Quality Artifact Inventory + +| artifactPath | digest | byteLength | +| --- | --- | --- | +| `.bitcode/v20-accessibility-report.json` | `sha256:7e4101be2eac723d66184ebf64477ae682eeb801c2a959ebe866998880bca67e` | 8226 | +| `.bitcode/v20-operator-acceptance-transcript.json` | `sha256:eb6f506f5e26272ff8ef77c8db938cee534eed159b92ff8520a4d3e7d6889553` | 10929 | +| `.bitcode/v20-performance-budget-report.json` | `sha256:5cef33fd3836cac6cf0b23ffa297c7c3a3aa56ac4d867ee0b7af5ca21b6380c7` | 5054 | +| `.bitcode/v20-projection-quality-smoke-matrix.json` | `sha256:143bd7c761fafc679e513baedaeb7f66c5030f4eb7338f31329fe23f64013346` | 4951 | +| `.bitcode/v20-quality-summary.json` | `sha256:f52c2fe263c8067d674b7489ac293bc4d6f9d1d3d554f0ef1b6154e6d794c614` | 4480 | +| `.bitcode/v20-visual-regression-report.json` | `sha256:d33cd04d779f4ff62fff9b35927f0047fa780fd1397a346b239a6af90dc8a7fb` | 19385 | + +### V20 Quality Summary + +- reportId: `v20-quality-summary` +- passed: `true` +- qualityReportCount: `5` +- generatedArtifactCount: `6` +- inheritedPositiveMatrixCellCount: `1864` +- inheritedNegativeMutationCellCount: `10` +- inheritedDeterministicReplayPassed: `true` + +| reportId | artifactPath | passed | blockingFailures | acceptedExclusions | +| --- | --- | --- | --- | --- | +| `v20-operator-acceptance-transcript` | `.bitcode/v20-operator-acceptance-transcript.json` | `true` | 0 | 0 | +| `v20-visual-regression-report` | `.bitcode/v20-visual-regression-report.json` | `true` | 0 | 0 | +| `v20-accessibility-report` | `.bitcode/v20-accessibility-report.json` | `true` | 0 | 0 | +| `v20-performance-budget-report` | `.bitcode/v20-performance-budget-report.json` | `true` | 0 | 1 | +| `v20-projection-quality-smoke-matrix` | `.bitcode/v20-projection-quality-smoke-matrix.json` | `true` | 0 | 0 | + +### V20 Operator Acceptance Transcript + +- reportId: `v20-operator-acceptance-transcript` +- transcriptMode: `executable-browser-workflow-summary` +- flowCount: `10` +- stepCount: `10` +- passed: `true` + +| flowId | stepId | scenarioId | branchMode | principal | passed | +| --- | --- | --- | --- | --- | --- | +| `seeded-shell-posture` | `seeded-shell-visible` | `auth-issuer-rollback` | `patch` | `buyer` | `true` | +| `targeted-branch-run` | `targeted-deposit-to-settlement` | `auth-issuer-rollback` | `patch` | `buyer` | `true` | +| `normalization-branch-run` | `normalization-source-to-shares` | `auth-many-asset-normalization` | `context` | `buyer` | `true` | +| `public-privacy-boundary-projection` | `public-projection-quality-visible` | `privacy-boundary-proof-export` | `patch` | `public` | `true` | +| `reviewer-privacy-boundary-projection` | `reviewer-projection-quality-visible` | `privacy-boundary-proof-export` | `patch` | `reviewer` | `true` | +| `buyer-targeted-projection` | `buyer-projection-quality-visible` | `auth-issuer-rollback` | `patch` | `buyer` | `true` | +| `internal-privacy-boundary-projection` | `internal-projection-quality-visible` | `privacy-boundary-proof-export` | `patch` | `internal` | `true` | +| `invalid-deposit-error` | `invalid-deposit-fails-without-state-mutation` | `auth-issuer-rollback` | `patch` | `buyer` | `true` | +| `no-survivor-conflict-reset` | `no-survivor-conflict-recovers-after-reset` | `auth-issuer-rollback` | `patch` | `buyer` | `true` | +| `generated-appendix-report-discovery` | `generated-proof-and-quality-report-reference-visible` | `auth-issuer-rollback` | `patch` | `buyer` | `true` | + +### V20 Visual Regression Budget + +- reportId: `v20-visual-regression-report` +- signatureMode: `deterministic-dom-geometry-signature` +- screenshotMode: `deferred-until-local-ci-screenshot-stability` +- stateCount: `10` +- passed: `true` + +| stateId | scenarioId | branchMode | principal | signatureDigest | passed | +| --- | --- | --- | --- | --- | --- | +| `initial-seeded-shell` | `auth-issuer-rollback` | `patch` | `buyer` | `sha256:46e31a90a55a3977d6747b0200dbd441077fa34b167846c9d85cf94316c58f64` | `true` | +| `targeted-branch-run` | `auth-issuer-rollback` | `patch` | `buyer` | `sha256:f783c8de2a49678bb7ee2b0fed8e1bd5ca294a7dab91b9e244dc7519d925f51e` | `true` | +| `normalization-branch-run` | `auth-many-asset-normalization` | `context` | `buyer` | `sha256:19313616e2f72dc3273cb5f7f3b8411ae050e4e328215d10714385827ad1506b` | `true` | +| `public-privacy-boundary-projection` | `privacy-boundary-proof-export` | `patch` | `public` | `sha256:6f1c0efce5abfea06241b85d1eeadca1a0fd4f4b2a67c1b28053705f9c65f026` | `true` | +| `reviewer-privacy-boundary-projection` | `privacy-boundary-proof-export` | `patch` | `reviewer` | `sha256:08cdf8898535afff0b9d36673707de6894193e1c44e8f8ba7603800411d71895` | `true` | +| `buyer-targeted-projection` | `auth-issuer-rollback` | `patch` | `buyer` | `sha256:8dc35576526041a6b3b922213d51aa9641d8ea3aa91c8cfaef6aa4b5cc91385d` | `true` | +| `internal-privacy-boundary-projection` | `privacy-boundary-proof-export` | `patch` | `internal` | `sha256:e295312ba215829d49c1162e82de4c292893d885779de50f0d0f8b371fdf0112` | `true` | +| `invalid-deposit-error` | `auth-issuer-rollback` | `patch` | `buyer` | `sha256:10b2c66c83978f5f0275271a67d4e7f45c45707470d616aef3fed48580e8d179` | `true` | +| `no-survivor-conflict` | `auth-issuer-rollback` | `patch` | `buyer` | `sha256:1a681d66e8657a5927acbc617033fb35ae85c2dfff5ce6d88366b70a1b283b9a` | `true` | +| `generated-appendix-report-reference` | `auth-issuer-rollback` | `patch` | `buyer` | `sha256:729bf4d2a934338eb78b303a1b5be9505fbdf20673e82bf91589187e9b60998f` | `true` | + +### V20 Accessibility Budget + +- reportId: `v20-accessibility-report` +- engine: `deterministic-dom-accessibility-contract` +- checkCount: `11` +- normalTextContrast: `4.5` +- nonTextUiContrast: `3` +- passed: `true` + +| checkId | passed | assertionCount | +| --- | --- | --- | +| `control-names` | `true` | 4 | +| `form-labeling` | `true` | 2 | +| `keyboard-operation` | `true` | 3 | +| `focus-order` | `true` | 8 | +| `focus-visibility` | `true` | 5 | +| `status-announcements` | `true` | 3 | +| `landmarks-and-sections` | `true` | 4 | +| `toggle-state` | `true` | 3 | +| `contrast` | `true` | 4 | +| `reduced-motion` | `true` | 1 | +| `projection-safety` | `true` | 3 | + +### V20 Performance Budget + +- reportId: `v20-performance-budget-report` +- measurementMode: `live-test-hard-gate-with-canonical-normalized-class` +- operationCount: `9` +- passed: `true` + +| operationId | budgetMs | hardGate | normalizedElapsedClass | passed | +| --- | --- | --- | --- | --- | +| `initial-seeded-shell-ready` | 1500 | `true` | `within-budget` | `true` | +| `scenario-switch-summary-update` | 500 | `true` | `within-budget` | `true` | +| `projection-switch-summary-update` | 500 | `true` | `within-budget` | `true` | +| `targeted-branch-creation` | 5000 | `true` | `within-budget` | `true` | +| `normalization-branch-creation` | 7000 | `true` | `within-budget` | `true` | +| `proof-family-catalog-render-after-branch` | 1000 | `true` | `within-budget` | `true` | +| `raw-visual-surface-mode-toggle` | 250 | `true` | `within-budget` | `true` | +| `reset-to-ready-state` | 1500 | `true` | `within-budget` | `true` | +| `full-quality-suite-duration` | `report-only` | `false` | `telemetry-only` | `true` | + +### V20 Projection Quality Smoke Matrix + +- reportId: `v20-projection-quality-smoke-matrix` +- matrixMode: `representative-principal-quality-smoke` +- cellCount: `4` +- inheritedBrowserMatrixCells: `64` +- passed: `true` + +| principal | scenarioId | rawFiles | sourceVisible | authVisible | qualityRequiresForbidden | passed | +| --- | --- | --- | --- | --- | --- | --- | +| `public` | `privacy-boundary-proof-export` | `false` | `false` | `false` | `false` | `true` | +| `reviewer` | `privacy-boundary-proof-export` | `false` | `false` | `false` | `false` | `true` | +| `buyer` | `auth-issuer-rollback` | `false` | `false` | `true` | `false` | `true` | +| `internal` | `privacy-boundary-proof-export` | `true` | `true` | `true` | `false` | `true` | + +## Proof Family Inventory + +| proofFamily | proofArtifactPath | memberCount | theoremCount | witnessArtifactCount | replayArtifactCount | replayStepCount | +| --- | --- | --- | --- | --- | --- | --- | +| `inference-synthesis` | `.bitcode/inference-synthesis-proof.json` | 5 | 6 | 6 | 7 | 3 | +| `prompt-completeness` | `.bitcode/prompt-completeness-proof.json` | 5 | 8 | 5 | 5 | 4 | +| `static-code-analysis` | `.bitcode/static-measurement-proof.json` | 4 | 5 | 5 | 5 | 3 | +| `verification-decisions` | `.bitcode/verification-decisions-proof.json` | 5 | 7 | 3 | 3 | 2 | +| `selection-and-materialization` | `.bitcode/selection-and-materialization-proof.json` | 5 | 7 | 7 | 7 | 2 | +| `authorization-and-sensitive-flow` | `.bitcode/authorization-and-sensitive-flow-proof.json` | 5 | 6 | 6 | 6 | 2 | +| `settlement-source-to-shares` | `.bitcode/settlement-source-to-shares-proof.json` | 8 | 8 | 8 | 8 | 2 | +| `disclosure-boundary` | `.bitcode/disclosure-boundary-proof.json` | 4 | 5 | 5 | 5 | 2 | +| `proof-contract` | `.bitcode/proof-contract.json` | 5 | 6 | 3 | 3 | 3 | + +## Family Details + +### inference-synthesis + +- proofArtifactPath: `.bitcode/inference-synthesis-proof.json` +- witnessArtifactPaths: `.bitcode/inference-moment-contracts.json`, `.bitcode/inference-proofs.json`, `.bitcode/prompt-implementation-surface.json`, `.bitcode/prompt-surfaces.json`, `.bitcode/parsed-completion-envelopes.json`, `.bitcode/inference-synthesis-proof.json` +- replayArtifacts: `.bitcode/inference-moment-contracts.json`, `.bitcode/inference-proofs.json`, `.bitcode/prompt-implementation-surface.json`, `.bitcode/prompt-surfaces.json`, `.bitcode/parsed-completion-envelopes.json`, `.bitcode/eval-manifest.json`, `.bitcode/inference-synthesis-proof.json` +- replayStepIds: `inference-synthesis.coverage-reconciliation`, `inference-synthesis.evaluator-status-replay`, `inference-synthesis.evidence-basis-replay` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `task` | 16 | 16 | `evaluatorStatusTruthful`, `evidenceBasisClosed`, `field`, `fieldProofPresent`, `momentContractPresent`, `parsedEnvelopePresent`, `passed`, `promptSurfacePresent` | `none` | +| `failureModes` | 16 | 16 | `evaluatorStatusTruthful`, `evidenceBasisClosed`, `field`, `fieldProofPresent`, `momentContractPresent`, `parsedEnvelopePresent`, `passed`, `promptSurfacePresent` | `none` | +| `constraints` | 16 | 16 | `evaluatorStatusTruthful`, `evidenceBasisClosed`, `field`, `fieldProofPresent`, `momentContractPresent`, `parsedEnvelopePresent`, `passed`, `promptSurfacePresent` | `none` | +| `targetArtifactKinds` | 16 | 16 | `evaluatorStatusTruthful`, `evidenceBasisClosed`, `field`, `fieldProofPresent`, `momentContractPresent`, `parsedEnvelopePresent`, `passed`, `promptSurfacePresent` | `none` | +| `closureCriteria` | 16 | 16 | `evaluatorStatusTruthful`, `evidenceBasisClosed`, `field`, `fieldProofPresent`, `momentContractPresent`, `parsedEnvelopePresent`, `passed`, `promptSurfacePresent` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `inference_synthesis.coverage_totality` | 16 | 16 | `inference-synthesis.coverage-reconciliation` | `none` | `none` | +| `inference_synthesis.evaluator_status_truth` | 16 | 16 | `inference-synthesis.evaluator-status-replay` | `none` | `none` | +| `inference_synthesis.evidence_basis_closure` | 16 | 16 | `inference-synthesis.evidence-basis-replay` | `none` | `none` | +| `inference_synthesis.ownership_traceability_closure` | 16 | 16 | `inference-synthesis.evidence-basis-replay` | `none` | `none` | +| `inference_synthesis.witness_materialization_closure` | 16 | 16 | `inference-synthesis.coverage-reconciliation`, `inference-synthesis.evaluator-status-replay`, `inference-synthesis.evidence-basis-replay` | `none` | `none` | +| `inference_synthesis.replay_closure` | 16 | 16 | `inference-synthesis.coverage-reconciliation`, `inference-synthesis.evaluator-status-replay`, `inference-synthesis.evidence-basis-replay` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `inference-synthesis.coverage-reconciliation` | `inference_synthesis.coverage_totality` | `.bitcode/inference-moment-contracts.json`, `.bitcode/inference-proofs.json`, `.bitcode/inference-synthesis-proof.json`, `.bitcode/prompt-surfaces.json` | +| `inference-synthesis.evaluator-status-replay` | `inference_synthesis.evaluator_status_truth` | `.bitcode/inference-moment-contracts.json`, `.bitcode/inference-proofs.json`, `.bitcode/prompt-surfaces.json`, `.bitcode/eval-manifest.json` | +| `inference-synthesis.evidence-basis-replay` | `inference_synthesis.evidence_basis_closure`, `inference_synthesis.ownership_traceability_closure` | `.bitcode/inference-moment-contracts.json`, `.bitcode/inference-proofs.json`, `.bitcode/prompt-surfaces.json`, `.bitcode/parsed-completion-envelopes.json`, `.bitcode/inference-synthesis-proof.json` | + +### prompt-completeness + +- proofArtifactPath: `.bitcode/prompt-completeness-proof.json` +- witnessArtifactPaths: `.bitcode/prompt-family-registry.json`, `.bitcode/prompt-contracts.json`, `.bitcode/prompt-surfaces.json`, `.bitcode/parsed-completion-envelopes.json`, `.bitcode/prompt-completeness-proof.json` +- replayArtifacts: `.bitcode/prompt-family-registry.json`, `.bitcode/prompt-contracts.json`, `.bitcode/prompt-surfaces.json`, `.bitcode/parsed-completion-envelopes.json`, `.bitcode/prompt-completeness-proof.json` +- replayStepIds: `prompt-completeness.member-set-reconciliation`, `prompt-completeness.parse-admissibility`, `prompt-completeness.consumer-closure`, `prompt-completeness.provenance-truth` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `task` | 16 | 16 | `classified`, `contractComplete`, `downstreamConsumersClosed`, `explicitlyExcluded`, `field`, `inDeclaredFamilyRegistry`, `parsedEnvelopeAdmissible`, `passed`, `provenanceAnnotationsTruthful`, `registered` | `none` | +| `failureModes` | 16 | 16 | `classified`, `contractComplete`, `downstreamConsumersClosed`, `explicitlyExcluded`, `field`, `inDeclaredFamilyRegistry`, `parsedEnvelopeAdmissible`, `passed`, `provenanceAnnotationsTruthful`, `registered` | `none` | +| `constraints` | 16 | 16 | `classified`, `contractComplete`, `downstreamConsumersClosed`, `explicitlyExcluded`, `field`, `inDeclaredFamilyRegistry`, `parsedEnvelopeAdmissible`, `passed`, `provenanceAnnotationsTruthful`, `registered` | `none` | +| `targetArtifactKinds` | 16 | 16 | `classified`, `contractComplete`, `downstreamConsumersClosed`, `explicitlyExcluded`, `field`, `inDeclaredFamilyRegistry`, `parsedEnvelopeAdmissible`, `passed`, `provenanceAnnotationsTruthful`, `registered` | `none` | +| `closureCriteria` | 16 | 16 | `classified`, `contractComplete`, `downstreamConsumersClosed`, `explicitlyExcluded`, `field`, `inDeclaredFamilyRegistry`, `parsedEnvelopeAdmissible`, `passed`, `provenanceAnnotationsTruthful`, `registered` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `prompt_completeness.coverage_totality` | 16 | 16 | `prompt-completeness.member-set-reconciliation` | `none` | `none` | +| `prompt_completeness.no_ghost_coverage` | 16 | 16 | `prompt-completeness.member-set-reconciliation` | `none` | `none` | +| `prompt_completeness.explicit_exclusion_closure` | 16 | 16 | `prompt-completeness.member-set-reconciliation` | `none` | `none` | +| `prompt_completeness.contract_closure` | 16 | 16 | `prompt-completeness.parse-admissibility` | `none` | `none` | +| `prompt_completeness.parsed_envelope_admissibility` | 16 | 16 | `prompt-completeness.parse-admissibility` | `none` | `none` | +| `prompt_completeness.downstream_consumer_closure` | 16 | 16 | `prompt-completeness.consumer-closure` | `none` | `none` | +| `prompt_completeness.provenance_truth` | 16 | 16 | `prompt-completeness.provenance-truth` | `none` | `none` | +| `prompt_completeness.witness_replay_closure` | 16 | 16 | `prompt-completeness.member-set-reconciliation`, `prompt-completeness.parse-admissibility`, `prompt-completeness.consumer-closure`, `prompt-completeness.provenance-truth` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `prompt-completeness.member-set-reconciliation` | `prompt_completeness.coverage_totality`, `prompt_completeness.no_ghost_coverage`, `prompt_completeness.explicit_exclusion_closure` | `.bitcode/prompt-family-registry.json`, `.bitcode/prompt-contracts.json`, `.bitcode/prompt-surfaces.json` | +| `prompt-completeness.parse-admissibility` | `prompt_completeness.contract_closure`, `prompt_completeness.parsed_envelope_admissibility` | `.bitcode/prompt-contracts.json`, `.bitcode/parsed-completion-envelopes.json` | +| `prompt-completeness.consumer-closure` | `prompt_completeness.downstream_consumer_closure` | `.bitcode/prompt-surfaces.json` | +| `prompt-completeness.provenance-truth` | `prompt_completeness.provenance_truth` | `.bitcode/prompt-surfaces.json`, `.bitcode/prompt-contracts.json` | + +### static-code-analysis + +- proofArtifactPath: `.bitcode/static-measurement-proof.json` +- witnessArtifactPaths: `.bitcode/code-analysis-fact-registry.json`, `.bitcode/static-heuristics-registry.json`, `.bitcode/measurement-receipts.json`, `.bitcode/static-measurement-report.json`, `.bitcode/static-measurement-proof.json` +- replayArtifacts: `.bitcode/code-analysis-fact-registry.json`, `.bitcode/static-heuristics-registry.json`, `.bitcode/measurement-receipts.json`, `.bitcode/static-measurement-report.json`, `.bitcode/static-measurement-proof.json` +- replayStepIds: `static-code-analysis.stage-domain`, `static-code-analysis.stage-mapping`, `static-code-analysis.receipt-report-proof` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `deterministic-parser` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | +| `repo-context` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | +| `content-unit` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | +| `measurement-stages` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `static_code_analysis.stage_domain_purity` | 16 | 16 | `static-code-analysis.stage-domain` | `none` | `none` | +| `static_code_analysis.abstract_to_concrete_stage_mapping` | 16 | 16 | `static-code-analysis.stage-mapping` | `none` | `none` | +| `static_code_analysis.registry_role_closure` | 16 | 16 | `static-code-analysis.stage-mapping` | `none` | `none` | +| `static_code_analysis.receipt_report_proof_agreement` | 16 | 16 | `static-code-analysis.receipt-report-proof` | `none` | `none` | +| `static_code_analysis.witness_replay_closure` | 16 | 16 | `static-code-analysis.stage-domain`, `static-code-analysis.stage-mapping`, `static-code-analysis.receipt-report-proof` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `static-code-analysis.stage-domain` | `static_code_analysis.stage_domain_purity` | `.bitcode/measurement-receipts.json`, `.bitcode/static-measurement-proof.json` | +| `static-code-analysis.stage-mapping` | `static_code_analysis.abstract_to_concrete_stage_mapping`, `static_code_analysis.registry_role_closure` | `.bitcode/measurement-receipts.json`, `.bitcode/code-analysis-fact-registry.json`, `.bitcode/static-heuristics-registry.json` | +| `static-code-analysis.receipt-report-proof` | `static_code_analysis.receipt_report_proof_agreement`, `static_code_analysis.witness_replay_closure` | `.bitcode/measurement-receipts.json`, `.bitcode/static-measurement-report.json`, `.bitcode/static-measurement-proof.json` | + +### verification-decisions + +- proofArtifactPath: `.bitcode/verification-decisions-proof.json` +- witnessArtifactPaths: `.bitcode/verification-report.json`, `.bitcode/verification-receipts.json`, `.bitcode/verification-decisions-proof.json` +- replayArtifacts: `.bitcode/verification-report.json`, `.bitcode/verification-receipts.json`, `.bitcode/verification-decisions-proof.json` +- replayStepIds: `verification-decisions.stage-mapping`, `verification-decisions.use-tier-consequence` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `issuance` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | +| `provenance` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | +| `sufficiency` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | +| `issuer-policy` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | +| `use-tier-consequence` | 16 | 16 | `memberId`, `passed`, `stageIds` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `verification_decisions.issuance_closure` | 16 | 16 | `verification-decisions.stage-mapping` | `none` | `none` | +| `verification_decisions.provenance_closure` | 16 | 16 | `verification-decisions.stage-mapping` | `none` | `none` | +| `verification_decisions.sufficiency_closure` | 16 | 16 | `verification-decisions.stage-mapping` | `none` | `none` | +| `verification_decisions.issuer_policy_closure` | 16 | 16 | `verification-decisions.stage-mapping` | `none` | `none` | +| `verification_decisions.use_tier_consequence_closure` | 16 | 16 | `verification-decisions.use-tier-consequence` | `none` | `none` | +| `verification_decisions.receipt_report_role_closure` | 16 | 16 | `verification-decisions.use-tier-consequence` | `none` | `none` | +| `verification_decisions.witness_replay_closure` | 16 | 16 | `verification-decisions.stage-mapping`, `verification-decisions.use-tier-consequence` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `verification-decisions.stage-mapping` | `verification_decisions.issuance_closure`, `verification_decisions.provenance_closure`, `verification_decisions.sufficiency_closure`, `verification_decisions.issuer_policy_closure` | `.bitcode/verification-receipts.json`, `.bitcode/verification-report.json` | +| `verification-decisions.use-tier-consequence` | `verification_decisions.use_tier_consequence_closure`, `verification_decisions.receipt_report_role_closure` | `.bitcode/verification-receipts.json`, `.bitcode/verification-report.json`, `.bitcode/verification-decisions-proof.json` | + +### selection-and-materialization + +- proofArtifactPath: `.bitcode/selection-and-materialization-proof.json` +- witnessArtifactPaths: `.bitcode/asset-pack.lock.json`, `.bitcode/selected-source-material.json`, `.bitcode/materialization-exclusions.json`, `.bitcode/materialization-visibility-proof.json`, `.bitcode/selection-consistency-proof.json`, `.bitcode/materialization-proof.json`, `.bitcode/selection-and-materialization-proof.json` +- replayArtifacts: `.bitcode/asset-pack.lock.json`, `.bitcode/selected-source-material.json`, `.bitcode/materialization-exclusions.json`, `.bitcode/materialization-visibility-proof.json`, `.bitcode/selection-consistency-proof.json`, `.bitcode/materialization-proof.json`, `.bitcode/selection-and-materialization-proof.json` +- replayStepIds: `selection-and-materialization.selected-set`, `selection-and-materialization.visibility` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `selected-assets` | 16 | 16 | `memberId`, `passed` | `none` | +| `locked-units` | 16 | 16 | `memberId`, `passed` | `none` | +| `materialized-source` | 16 | 16 | `memberId`, `passed` | `none` | +| `exclusions` | 16 | 16 | `memberId`, `passed` | `none` | +| `visibility-rules` | 16 | 16 | `memberId`, `passed` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `selection_and_materialization.selected_asset_closure` | 16 | 16 | `selection-and-materialization.selected-set` | `none` | `none` | +| `selection_and_materialization.lock_closure` | 16 | 16 | `selection-and-materialization.selected-set` | `none` | `none` | +| `selection_and_materialization.materialized_source_closure` | 16 | 16 | `selection-and-materialization.selected-set` | `none` | `none` | +| `selection_and_materialization.exclusion_closure` | 16 | 16 | `selection-and-materialization.visibility` | `none` | `none` | +| `selection_and_materialization.visibility_closure` | 16 | 16 | `selection-and-materialization.visibility` | `none` | `none` | +| `selection_and_materialization.selection_consistency_closure` | 16 | 16 | `selection-and-materialization.selected-set` | `none` | `none` | +| `selection_and_materialization.materialization_proof_closure` | 16 | 16 | `selection-and-materialization.selected-set`, `selection-and-materialization.visibility` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `selection-and-materialization.selected-set` | `selection_and_materialization.selected_asset_closure`, `selection_and_materialization.lock_closure`, `selection_and_materialization.materialized_source_closure`, `selection_and_materialization.selection_consistency_closure` | `.bitcode/asset-pack.lock.json`, `.bitcode/selected-source-material.json`, `.bitcode/selection-consistency-proof.json`, `.bitcode/materialization-proof.json` | +| `selection-and-materialization.visibility` | `selection_and_materialization.visibility_closure`, `selection_and_materialization.exclusion_closure` | `.bitcode/materialization-exclusions.json`, `.bitcode/materialization-visibility-proof.json` | + +### authorization-and-sensitive-flow + +- proofArtifactPath: `.bitcode/authorization-and-sensitive-flow-proof.json` +- witnessArtifactPaths: `.bitcode/identity-bindings.json`, `.bitcode/authorization-decisions.json`, `.bitcode/sensitive-data-flow.json`, `.bitcode/identity-authorization-proof.json`, `.bitcode/sensitive-data-flow-proof.json`, `.bitcode/authorization-and-sensitive-flow-proof.json` +- replayArtifacts: `.bitcode/identity-bindings.json`, `.bitcode/authorization-decisions.json`, `.bitcode/sensitive-data-flow.json`, `.bitcode/identity-authorization-proof.json`, `.bitcode/sensitive-data-flow-proof.json`, `.bitcode/authorization-and-sensitive-flow-proof.json` +- replayStepIds: `authorization-sensitive-flow.identity`, `authorization-sensitive-flow.flows` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `principals` | 16 | 16 | `memberId`, `passed` | `none` | +| `authorization-decisions` | 16 | 16 | `memberId`, `passed` | `none` | +| `confidentiality-classes` | 16 | 16 | `memberId`, `passed` | `none` | +| `retention-disclosure-rules` | 16 | 16 | `memberId`, `passed` | `none` | +| `sensitive-data-flows` | 16 | 16 | `memberId`, `passed` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `authorization_and_sensitive_flow.principal_authority_totality` | 16 | 16 | `authorization-sensitive-flow.identity` | `none` | `none` | +| `authorization_and_sensitive_flow.authorization_decision_closure` | 16 | 16 | `authorization-sensitive-flow.identity` | `none` | `none` | +| `authorization_and_sensitive_flow.classification_closure` | 16 | 16 | `authorization-sensitive-flow.flows` | `none` | `none` | +| `authorization_and_sensitive_flow.policy_assignment_closure` | 16 | 16 | `authorization-sensitive-flow.flows` | `none` | `none` | +| `authorization_and_sensitive_flow.no_unauthorized_public_flow` | 16 | 16 | `authorization-sensitive-flow.flows` | `none` | `none` | +| `authorization_and_sensitive_flow.witness_replay_closure` | 16 | 16 | `authorization-sensitive-flow.identity`, `authorization-sensitive-flow.flows` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `authorization-sensitive-flow.identity` | `authorization_and_sensitive_flow.principal_authority_totality`, `authorization_and_sensitive_flow.authorization_decision_closure` | `.bitcode/identity-bindings.json`, `.bitcode/authorization-decisions.json`, `.bitcode/identity-authorization-proof.json` | +| `authorization-sensitive-flow.flows` | `authorization_and_sensitive_flow.classification_closure`, `authorization_and_sensitive_flow.policy_assignment_closure`, `authorization_and_sensitive_flow.no_unauthorized_public_flow` | `.bitcode/sensitive-data-flow.json`, `.bitcode/sensitive-data-flow-proof.json` | + +### settlement-source-to-shares + +- proofArtifactPath: `.bitcode/settlement-source-to-shares-proof.json` +- witnessArtifactPaths: `.bitcode/source-to-shares.json`, `.bitcode/settlement-participation.json`, `.bitcode/settlement-preview.json`, `.bitcode/accounting-precision-report.json`, `.bitcode/journal-diff.json`, `.bitcode/journal-completeness-proof.json`, `.bitcode/settlement-proof.json`, `.bitcode/settlement-source-to-shares-proof.json` +- replayArtifacts: `.bitcode/source-to-shares.json`, `.bitcode/settlement-participation.json`, `.bitcode/settlement-preview.json`, `.bitcode/accounting-precision-report.json`, `.bitcode/journal-diff.json`, `.bitcode/journal-completeness-proof.json`, `.bitcode/settlement-proof.json`, `.bitcode/settlement-source-to-shares-proof.json` +- replayStepIds: `settlement-source-to-shares.contribution-allocation`, `settlement-source-to-shares.journal-theorem` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `contribution` | 16 | 16 | `memberId`, `passed` | `none` | +| `clipping` | 16 | 16 | `memberId`, `passed` | `none` | +| `normalization` | 16 | 16 | `memberId`, `passed` | `none` | +| `participation` | 16 | 16 | `memberId`, `passed` | `none` | +| `allocation` | 16 | 16 | `memberId`, `passed` | `none` | +| `quantized-fit-quality-receipting` | 16 | 16 | `memberId`, `passed` | `none` | +| `journal` | 16 | 16 | `memberId`, `passed` | `none` | +| `settlement-proof` | 16 | 16 | `memberId`, `passed` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `settlement_source_to_shares.contribution_totality` | 16 | 16 | `settlement-source-to-shares.contribution-allocation` | `none` | `none` | +| `settlement_source_to_shares.clipping_determinism` | 16 | 16 | `settlement-source-to-shares.contribution-allocation` | `none` | `none` | +| `settlement_source_to_shares.normalization_exactness` | 16 | 16 | `settlement-source-to-shares.contribution-allocation` | `none` | `none` | +| `settlement_source_to_shares.participation_totality` | 16 | 16 | `settlement-source-to-shares.contribution-allocation` | `none` | `none` | +| `settlement_source_to_shares.allocation_conservation` | 16 | 16 | `settlement-source-to-shares.contribution-allocation` | `none` | `none` | +| `settlement_source_to_shares.quantized_fit_quality_receipting` | 16 | 16 | `settlement-source-to-shares.contribution-allocation` | `none` | `none` | +| `settlement_source_to_shares.journal_completeness` | 16 | 16 | `settlement-source-to-shares.journal-theorem` | `none` | `none` | +| `settlement_source_to_shares.settlement_theorem_integrity` | 16 | 16 | `settlement-source-to-shares.journal-theorem` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `settlement-source-to-shares.contribution-allocation` | `settlement_source_to_shares.contribution_totality`, `settlement_source_to_shares.clipping_determinism`, `settlement_source_to_shares.normalization_exactness`, `settlement_source_to_shares.participation_totality`, `settlement_source_to_shares.allocation_conservation`, `settlement_source_to_shares.quantized_fit_quality_receipting` | `.bitcode/source-to-shares.json`, `.bitcode/settlement-participation.json`, `.bitcode/settlement-preview.json`, `.bitcode/accounting-precision-report.json` | +| `settlement-source-to-shares.journal-theorem` | `settlement_source_to_shares.journal_completeness`, `settlement_source_to_shares.settlement_theorem_integrity` | `.bitcode/journal-diff.json`, `.bitcode/journal-completeness-proof.json`, `.bitcode/settlement-proof.json` | + +### disclosure-boundary + +- proofArtifactPath: `.bitcode/disclosure-boundary-proof.json` +- witnessArtifactPaths: `.bitcode/projection-policy.json`, `.bitcode/bounded-public-proof.json`, `.bitcode/redaction-proof.json`, `.bitcode/disclosure-proof.json`, `.bitcode/disclosure-boundary-proof.json` +- replayArtifacts: `.bitcode/projection-policy.json`, `.bitcode/bounded-public-proof.json`, `.bitcode/redaction-proof.json`, `.bitcode/disclosure-proof.json`, `.bitcode/disclosure-boundary-proof.json` +- replayStepIds: `disclosure-boundary.policy-bounded-public`, `disclosure-boundary.redaction-disclosure` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `projection-policy` | 16 | 16 | `memberId`, `passed` | `none` | +| `bounded-public-proof` | 16 | 16 | `memberId`, `passed` | `none` | +| `redaction-proof` | 16 | 16 | `memberId`, `passed` | `none` | +| `disclosure-proof` | 16 | 16 | `memberId`, `passed` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `disclosure_boundary.projection_policy_closure` | 16 | 16 | `disclosure-boundary.policy-bounded-public` | `none` | `none` | +| `disclosure_boundary.bounded_public_metadata_only` | 16 | 16 | `disclosure-boundary.policy-bounded-public` | `none` | `none` | +| `disclosure_boundary.redaction_alignment` | 16 | 16 | `disclosure-boundary.redaction-disclosure` | `none` | `none` | +| `disclosure_boundary.disclosure_verdict_alignment` | 16 | 16 | `disclosure-boundary.redaction-disclosure` | `none` | `none` | +| `disclosure_boundary.witness_replay_closure` | 16 | 16 | `disclosure-boundary.policy-bounded-public`, `disclosure-boundary.redaction-disclosure` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `disclosure-boundary.policy-bounded-public` | `disclosure_boundary.projection_policy_closure`, `disclosure_boundary.bounded_public_metadata_only` | `.bitcode/projection-policy.json`, `.bitcode/bounded-public-proof.json` | +| `disclosure-boundary.redaction-disclosure` | `disclosure_boundary.redaction_alignment`, `disclosure_boundary.disclosure_verdict_alignment`, `disclosure_boundary.witness_replay_closure` | `.bitcode/redaction-proof.json`, `.bitcode/disclosure-proof.json`, `.bitcode/disclosure-boundary-proof.json` | + +### proof-contract + +- proofArtifactPath: `.bitcode/proof-contract.json` +- witnessArtifactPaths: `.bitcode/proof-contract.json`, `.bitcode/system-proof-bundle.json`, `.bitcode/proof-witness-manifest.json` +- replayArtifacts: `.bitcode/proof-contract.json`, `.bitcode/system-proof-bundle.json`, `.bitcode/proof-witness-manifest.json` +- replayStepIds: `proof-contract.contract-materialization`, `proof-contract.evidence-chain`, `proof-contract.bundle-witness` + +#### Members + +| memberId | passedRuns | totalRuns | fieldShape | failingRuns | +| --- | --- | --- | --- | --- | +| `proof-contract` | 16 | 16 | `memberId`, `passed` | `none` | +| `evidence-chain` | 16 | 16 | `memberId`, `passed` | `none` | +| `theorem-checks` | 16 | 16 | `memberId`, `passed` | `none` | +| `system-proof-bundle` | 16 | 16 | `memberId`, `passed` | `none` | +| `witness-manifest-closure` | 16 | 16 | `memberId`, `passed` | `none` | + +#### Theorems + +| theoremId | passedRuns | totalRuns | replayStepIds | failureReasons | failingRuns | +| --- | --- | --- | --- | --- | --- | +| `proof_contract.contract_materialization` | 16 | 16 | `proof-contract.contract-materialization` | `none` | `none` | +| `proof_contract.evidence_chain_closure` | 16 | 16 | `proof-contract.evidence-chain` | `none` | `none` | +| `proof_contract.theorem_check_binding` | 16 | 16 | `proof-contract.evidence-chain` | `none` | `none` | +| `proof_contract.bundle_coherence` | 16 | 16 | `proof-contract.bundle-witness` | `none` | `none` | +| `proof_contract.witness_manifest_coherence` | 16 | 16 | `proof-contract.bundle-witness` | `none` | `none` | +| `proof_contract.replay_closure` | 16 | 16 | `proof-contract.bundle-witness` | `none` | `none` | + +#### Replay Steps + +| stepId | theoremIds | requiredArtifactPaths | +| --- | --- | --- | +| `proof-contract.contract-materialization` | `proof_contract.contract_materialization` | `.bitcode/proof-contract.json` | +| `proof-contract.evidence-chain` | `proof_contract.evidence_chain_closure`, `proof_contract.theorem_check_binding` | `.bitcode/proof-contract.json`, `.bitcode/system-proof-bundle.json` | +| `proof-contract.bundle-witness` | `proof_contract.bundle_coherence`, `proof_contract.witness_manifest_coherence`, `proof_contract.replay_closure` | `.bitcode/system-proof-bundle.json`, `.bitcode/proof-witness-manifest.json`, `.bitcode/proof-contract.json` | + +## Scenario and Run Matrix + +| scenarioId | branchMode | readId | branchName | assetPackId | familyCount | allFamiliesPassed | proofContractPassed | requiredArtifactPathCount | artifactDigestCount | fullyProven | +| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | +| `auth-issuer-rollback` | `patch` | `read_auth-issuer-rollback_40b4b5cc9b` | `bitcode/remediation-read_auth-issuer-rollback_40b4b5cc9b-auth-issuer-rollback` | `asset_pack_f4d2f98e2b7f` | 9 | `true` | `true` | 47 | 46 | `true` | +| `auth-issuer-rollback` | `context` | `read_auth-issuer-rollback_40b4b5cc9b` | `bitcode/remediation-read_auth-issuer-rollback_40b4b5cc9b-auth-issuer-rollback` | `asset_pack_19909dd95164` | 9 | `true` | `true` | 47 | 46 | `true` | +| `rust-validator-proof-gap` | `patch` | `read_rust-validator-proof-gap_7044fe8972` | `bitcode/remediation-read_rust-validator-proof-gap_7044fe8972-rust-validator-proof-gap` | `asset_pack_3b7a68101d23` | 9 | `true` | `true` | 47 | 46 | `true` | +| `rust-validator-proof-gap` | `context` | `read_rust-validator-proof-gap_7044fe8972` | `bitcode/remediation-read_rust-validator-proof-gap_7044fe8972-rust-validator-proof-gap` | `asset_pack_3b7a68101d23` | 9 | `true` | `true` | 47 | 46 | `true` | +| `config-policy-precedence-incident` | `patch` | `read_config-policy-precedence-incident_f39d972e54` | `bitcode/remediation-read_config-policy-precedence-incident_f39d972e54-config-policy-precedence-incident` | `asset_pack_d0c7f0b06b9a` | 9 | `true` | `true` | 47 | 46 | `true` | +| `config-policy-precedence-incident` | `context` | `read_config-policy-precedence-incident_f39d972e54` | `bitcode/remediation-read_config-policy-precedence-incident_f39d972e54-config-policy-precedence-incident` | `asset_pack_d0c7f0b06b9a` | 9 | `true` | `true` | 47 | 46 | `true` | +| `unsafe-patch-review-recovery` | `patch` | `read_unsafe-patch-review-recovery_16a56c87c5` | `bitcode/remediation-read_unsafe-patch-review-recovery_16a56c87c5-unsafe-patch-review-recovery` | `asset_pack_fd3c892c8e9e` | 9 | `true` | `true` | 47 | 46 | `true` | +| `unsafe-patch-review-recovery` | `context` | `read_unsafe-patch-review-recovery_16a56c87c5` | `bitcode/remediation-read_unsafe-patch-review-recovery_16a56c87c5-unsafe-patch-review-recovery` | `asset_pack_fd3c892c8e9e` | 9 | `true` | `true` | 47 | 46 | `true` | +| `infra-deployment-mismatch` | `patch` | `read_infra-deployment-mismatch_be8a999141` | `bitcode/remediation-read_infra-deployment-mismatch_be8a999141-infra-deployment-mismatch` | `asset_pack_9f1b844a2cdf` | 9 | `true` | `true` | 47 | 46 | `true` | +| `infra-deployment-mismatch` | `context` | `read_infra-deployment-mismatch_be8a999141` | `bitcode/remediation-read_infra-deployment-mismatch_be8a999141-infra-deployment-mismatch` | `asset_pack_9f1b844a2cdf` | 9 | `true` | `true` | 47 | 46 | `true` | +| `privacy-boundary-proof-export` | `patch` | `read_privacy-boundary-proof-export_8163942d95` | `bitcode/remediation-read_privacy-boundary-proof-export_8163942d95-privacy-boundary-proof-export` | `asset_pack_c5fef3ab17c5` | 9 | `true` | `true` | 47 | 46 | `true` | +| `privacy-boundary-proof-export` | `context` | `read_privacy-boundary-proof-export_8163942d95` | `bitcode/remediation-read_privacy-boundary-proof-export_8163942d95-privacy-boundary-proof-export` | `asset_pack_c5fef3ab17c5` | 9 | `true` | `true` | 47 | 46 | `true` | +| `polyglot-gateway-benchmark-remediation` | `patch` | `read_polyglot-gateway-benchmark-remediation_ca6f233369` | `bitcode/remediation-read_polyglot-gateway-benchmark-remediation_ca6f233369-polyglot-gateway-benchmark-remediation` | `asset_pack_654da1e46737` | 9 | `true` | `true` | 47 | 46 | `true` | +| `polyglot-gateway-benchmark-remediation` | `context` | `read_polyglot-gateway-benchmark-remediation_ca6f233369` | `bitcode/remediation-read_polyglot-gateway-benchmark-remediation_ca6f233369-polyglot-gateway-benchmark-remediation` | `asset_pack_654da1e46737` | 9 | `true` | `true` | 47 | 46 | `true` | +| `auth-many-asset-normalization` | `patch` | `read_auth-many-asset-normalization_f6dbfe951c` | `bitcode/remediation-read_auth-many-asset-normalization_f6dbfe951c-auth-many-asset-normalization` | `asset_pack_186c76eb7d2d` | 9 | `true` | `true` | 47 | 46 | `true` | +| `auth-many-asset-normalization` | `context` | `read_auth-many-asset-normalization_f6dbfe951c` | `bitcode/remediation-read_auth-many-asset-normalization_f6dbfe951c-auth-many-asset-normalization` | `asset_pack_186c76eb7d2d` | 9 | `true` | `true` | 47 | 46 | `true` | + +## Incomplete Verdicts + +- none + +## Run Details + +### auth-issuer-rollback/patch + +- branchName: `bitcode/remediation-read_auth-issuer-rollback_40b4b5cc9b-auth-issuer-rollback` +- readId: `read_auth-issuer-rollback_40b4b5cc9b` +- assetPackId: `asset_pack_f4d2f98e2b7f` +- proofContractHash: `sha256:2bc0cdb1b9c54e9b714d946f3bee408f0343a3dade3175bb2dd3e34c1ca022a9` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:256959c2fe4952b795e30622c3811861f5488c1d81c55cb836ce21d8b2813e64` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:f4595d1c00efd134c3dbaf7f5eb8a1ea6f7afb1afeaacfc52da133a9d6619393` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:9592d38f7281eafa7ac658e48cbf6e35ab44591384bf73dc11e332237160df39` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:098b3934f79eaf77bbd0f72593b3e9d35a83344894d46a09a1c84853f2bc710e` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:cfea2cc82ce182248ce41d6c0354e00c55fad05e1304ab3e37f6ee43b43b4fca` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:0896df3fcc89b27fe7ac491caad0d739503111bdce24e03e8f037937ac2790de` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:2bc0cdb1b9c54e9b714d946f3bee408f0343a3dade3175bb2dd3e34c1ca022a9` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:a08dcb38b21b853afb64378b8872b02e066da3a7a72adfa93c6abfd217c55cfc` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:1c38aa47b7361ce985b48e3da400d880f37290debf70271c34ed3b10fafe72fa` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:098b3934f79eaf77bbd0f72593b3e9d35a83344894d46a09a1c84853f2bc710e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:1acdeef8c14093b5a00c5eeb749869c45e367f0c102bec3394bd7c45ec929fa8` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:f5da41a20f3a15375abbe1fdabd2a88239a2a8f637aaf033e8018915a0e9c7eb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:054a9bd14ffbfaf41201b72cde276e6d8d81378c0b4a369360de535f7a4ecb2e` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:0896df3fcc89b27fe7ac491caad0d739503111bdce24e03e8f037937ac2790de` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:f5da41a20f3a15375abbe1fdabd2a88239a2a8f637aaf033e8018915a0e9c7eb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:616ae95dcb9636a044d72f16dede6f5fd4794de29e6377070dfe27e9698f24de` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:d25e761512f1d40adc659462dd06c03af6e25f2e48a30b5b89ae7ffc928e776d` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:4d4111ebb0cb41d0246d93e30a808c007241d27c715b491aa53e762342c8759c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:02e131ce1efdb0b3f9a621fbd2ba6a3f805b9b85b6903292117901611b0fe21d` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:9e6a10b2ec749912879e6bcd36fa1fba4ea6addfe1a37475e7a49718a154ad2d` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:256959c2fe4952b795e30622c3811861f5488c1d81c55cb836ce21d8b2813e64` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:f5f9f0d0bfcdb4e04468c26d9ad18a982d1c96bd542f748eb3e2f8895702dcb7` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:b259d0cc8915b4491f7cf220e2bba34ae95e7b68e1d30f07e3fa6ada7dfb0563` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:f377c98e7db49df061805373caca01b550d3fcadd7be710991e4c3ddf2df826d` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:a9c087535c2de8ba4550cb9ed8b7c0cb92b64dd3e9bf0eb5d8e502981602b771` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:295cf78382de6b94a028e4c61541ea0c6a57aa62ed63593efd0ba7998459a4e0` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:6dcc4f10e576cd74891519cda9354cd2b04d7a01f2a014653957f856f3eb1f6f` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:a612d67d1995853ee132d9dd21fd8c64c8f986b6c41a2b0e0d042447552f2cd6` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:bb8674abf94ae1d8ee5d5ed695258555f039326c2a75d3632dfd65271a06b1e1` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:1a33ac2be9d039f56b0448f6eb47833327f655c46770eff998d30232f759fe03` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:49a7941430fe1eccbe71c0b321955dd7790faa63c7d983123118ca94fddeb04d` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:7b3b4c552085629cbb6af1dfc705a69ada6e0f34c32365ac768407679052b24f` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:70bc3fdae9bd5f4424476c90c9272989d161c73c04c88ae96c87e8f8473a0848` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:f5da41a20f3a15375abbe1fdabd2a88239a2a8f637aaf033e8018915a0e9c7eb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:a116782f3f2d2a02acc6f45be8320e9eb265bc77de7f4b2db59a5c610a0d2e97` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:9592d38f7281eafa7ac658e48cbf6e35ab44591384bf73dc11e332237160df39` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:0458593a95733b5c411c3cbdfe188bcc394fbfe5811f5deb8e73bb3a83aca630` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:9901fc2c0ead9f1445ec4254fdc9c621f3fd92e413e815b0b8d768fb8ab30f5d` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:62e6b4c6ae434a217568f5b7b32cffae963ccdf95c479c1780ceabc2d41a9d53` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:f6e862d56ff0166f78dd46659332af9cb94f638d39c165b1573dcfb524aed357` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:dff1642ab7d6939c2263360e45775d5e737934200b4dd05740f2aa1d437b26cf` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:433796e9495bb735acb1fd1a916b3e3d212cae22a4bec0ccda69a4ba7b538620` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:cfea2cc82ce182248ce41d6c0354e00c55fad05e1304ab3e37f6ee43b43b4fca` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:83bcaaf9d2b037535e3155879f3b613e714a963aee6577de070099cba6a07e14` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:e340c4d0e1ff5493f7ac439129ba0c6bf62fb2785f602a12abe68764abf2ef15` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:f4595d1c00efd134c3dbaf7f5eb8a1ea6f7afb1afeaacfc52da133a9d6619393` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:0e40751f7e15e39c69210e9bd1abd9d12cd49bb873bde875cf3c7de9b1395bd4` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:9c85fc5bf5d52cb93b0fdaff5ad5e3d8b113a56a63666c0e8e2017eb7bf099e9` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:7e87f190df2b89b15599518728852ee63e64ffa8cd059ade8e603ca2017fbbf3` | `verification-decisions` | `verification-evidence` | `false` | + +### auth-issuer-rollback/context + +- branchName: `bitcode/remediation-read_auth-issuer-rollback_40b4b5cc9b-auth-issuer-rollback` +- readId: `read_auth-issuer-rollback_40b4b5cc9b` +- assetPackId: `asset_pack_19909dd95164` +- proofContractHash: `sha256:0800e46f246b20d88857779f128a9a59edd322529b3dc5735eba5a9710399db0` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:256959c2fe4952b795e30622c3811861f5488c1d81c55cb836ce21d8b2813e64` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:f4595d1c00efd134c3dbaf7f5eb8a1ea6f7afb1afeaacfc52da133a9d6619393` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:e5d0ddd164f244e7747c498ab9ebebd58c9bbc881a38786fc3185a6a47f27cf6` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:ff2d9cec42dd2f31397e5bc8de46cffd9f53379230391b865468c27e8354122d` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:09cd59c100db1e5a7931d10338fce407145c0d97ce0eef28a59a5a6dcd3096d3` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:ac206af0e4758da5b5b9b75d0972dee99057ce5f0694e7d84428c1e132f0d11c` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:0800e46f246b20d88857779f128a9a59edd322529b3dc5735eba5a9710399db0` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:cb89d3a06d4b07b5e70012ed8ad97838ee36e9689232913f9a86f1228dfe91cc` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:a077681f046fbb925c387550b5a8df129bfb602c74b0a482699ff28c8dcf6fac` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:ff2d9cec42dd2f31397e5bc8de46cffd9f53379230391b865468c27e8354122d` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:4585aad198e138fc78f9135fee9cfee97382e6077c47984b8c80db785172bb28` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:588c76e7d32b2409990e39ad16946c59d6cf15db87d451f043f2a194cdd56dbb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:054a9bd14ffbfaf41201b72cde276e6d8d81378c0b4a369360de535f7a4ecb2e` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:ac206af0e4758da5b5b9b75d0972dee99057ce5f0694e7d84428c1e132f0d11c` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:588c76e7d32b2409990e39ad16946c59d6cf15db87d451f043f2a194cdd56dbb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:616ae95dcb9636a044d72f16dede6f5fd4794de29e6377070dfe27e9698f24de` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:7e22edb0b2a1daf5244a70102f5b66356ceb9358a23b92c3b31cc1a0eed849a4` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:94c92e34df4f6e3a8e15ef2030bdbd36663f16419a5fc66bf3b6c3fbc19a2a2e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:02e131ce1efdb0b3f9a621fbd2ba6a3f805b9b85b6903292117901611b0fe21d` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:9e6a10b2ec749912879e6bcd36fa1fba4ea6addfe1a37475e7a49718a154ad2d` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:256959c2fe4952b795e30622c3811861f5488c1d81c55cb836ce21d8b2813e64` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:474af6929f6571b43b0bf7775885c66089db4111b9fe4862a10bc74c1453906c` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:8c167479576094e68a68e8e4041079403a22635f31826494a5a62eed0bd812d4` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:cbcae63fa8e4650193ba088f2efbe3132de023f9ad4334384d64b506d72f3db4` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:813bfe253077e589372561323feee22b8c354887d667ad66137d47b586d63f2f` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:5ea216f7a4ad931f4bb1cb10500eaffca2a183d29e828b4fbb2559239216b94e` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:6dcc4f10e576cd74891519cda9354cd2b04d7a01f2a014653957f856f3eb1f6f` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:a612d67d1995853ee132d9dd21fd8c64c8f986b6c41a2b0e0d042447552f2cd6` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:fa7522727b5f22d3920b966611ed101f0d3c28365936db8cc66fa60f84ac1a4a` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:1a33ac2be9d039f56b0448f6eb47833327f655c46770eff998d30232f759fe03` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:49a7941430fe1eccbe71c0b321955dd7790faa63c7d983123118ca94fddeb04d` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:7b3b4c552085629cbb6af1dfc705a69ada6e0f34c32365ac768407679052b24f` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:9aed3047408104cd9854d48fcc38cbd920fc4abe243ac795da4885014d9ece82` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:588c76e7d32b2409990e39ad16946c59d6cf15db87d451f043f2a194cdd56dbb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:ae941c8173e039154e73aed5639abd804c445e4a995ea70860c6a0e47f2f1c5d` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:e5d0ddd164f244e7747c498ab9ebebd58c9bbc881a38786fc3185a6a47f27cf6` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:ecbd5a7070f28dda086bce15a4dde9516694e604b5a5813f0f17e85a2adefede` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:9901fc2c0ead9f1445ec4254fdc9c621f3fd92e413e815b0b8d768fb8ab30f5d` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:fd7fbdfc94ac24665c6f9ef031aaaa4d2ce5bc2e53869c9651d037a6dddde512` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:38d3d641821f37594d0ee5dd779048826440a417be4faedfaa1c0273a9aafd83` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:bfa3f543a1f69577e855dc7432c5325b4b0be48a90890a1019559509f677af7f` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:d82bd7f5eef9645e375b456c1a159320b5b3c6d2cac1826c14e45d74098250d6` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:09cd59c100db1e5a7931d10338fce407145c0d97ce0eef28a59a5a6dcd3096d3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:83bcaaf9d2b037535e3155879f3b613e714a963aee6577de070099cba6a07e14` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:e340c4d0e1ff5493f7ac439129ba0c6bf62fb2785f602a12abe68764abf2ef15` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:f4595d1c00efd134c3dbaf7f5eb8a1ea6f7afb1afeaacfc52da133a9d6619393` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:0e40751f7e15e39c69210e9bd1abd9d12cd49bb873bde875cf3c7de9b1395bd4` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:9c85fc5bf5d52cb93b0fdaff5ad5e3d8b113a56a63666c0e8e2017eb7bf099e9` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:0e6261f6b15d8825ee3497fe0c8e1bb72519f3c04873866858eb37fe7cd80aa3` | `verification-decisions` | `verification-evidence` | `false` | + +### rust-validator-proof-gap/patch + +- branchName: `bitcode/remediation-read_rust-validator-proof-gap_7044fe8972-rust-validator-proof-gap` +- readId: `read_rust-validator-proof-gap_7044fe8972` +- assetPackId: `asset_pack_3b7a68101d23` +- proofContractHash: `sha256:34f2a976e6dc61ca978b606608d7205e2c5c0cd4ed5e8eb38fdaea91c8faa026` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:4f09eb2ae7c6db3a769ab72b39c692158c09da634ddd72b205c3d7a507783ede` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:b55a0102ac4e3332e525d2353d74b80087b1fdc6d2929fcfb9f2c8948441b92a` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:0832ded750cdd02c6465643c4472466116da0c4543272bbcad7040e9ac166dee` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:54673ee8002b9b47cdf6543c747ea377da8d7a2f4b16672a7d3f1cd01cd08acb` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:b14ee59f7d8b27885fd96e5bb0f20222825045013c5827525f291844a597c26a` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:6d730db590e80e5b9070d41dc88dfa2a83ec00050ee9bd976eb63c221fded753` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:34f2a976e6dc61ca978b606608d7205e2c5c0cd4ed5e8eb38fdaea91c8faa026` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:954f6fe05a26bb44a1f65602fb4a23d8b88571c3453cd0ed215c45963766a83b` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:f62b272e830007b203ceff28d5b8bc0fd395e9da882d1e594174a9082a434dfc` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:54673ee8002b9b47cdf6543c747ea377da8d7a2f4b16672a7d3f1cd01cd08acb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:9c7af812b1bcb7516c38c90fd583b05d5cd66d5892985f87832e940eb44368f9` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:03329a4920190ad468ca25efb3ca0848cac25529e67e23273f2b6126ea7b126d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:9be5dad921d2f261390a9b2fa5b46eb84cd82439e38cc1c3e49693d9820b0619` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:6d730db590e80e5b9070d41dc88dfa2a83ec00050ee9bd976eb63c221fded753` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:03329a4920190ad468ca25efb3ca0848cac25529e67e23273f2b6126ea7b126d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:005ee8e731b1b3e2bf9134cb4cc74dab81217681adfde3219d24f2ae78564e2d` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:2287984d304bf31068f4c3517233a3f7da5f2dc444ee5236b539bfd548e7be5a` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:6fb14d8000883576783bf728694ae38f202197fa34e056d59e4ea56e44642887` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:0ba1bdf22cb299df63508fa49e6d994d716d0a5d89e426c260c68ebccd969771` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:276a42d09d1c3507cae113787129c222569bdb7a9934d70c791715e3a490b6b1` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:4f09eb2ae7c6db3a769ab72b39c692158c09da634ddd72b205c3d7a507783ede` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:ac5961a0c7d2162c86ce74e6e50119cd020397bca3db2ea0002f908aeae4c366` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:bb6746f6788dc16b240d863028e05f3522e9fa814c21f47723e79308f5016b41` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:56f03f73459c307d37adc3b8727e831934e2a4c9f563e1d3941fa04548cfd8b0` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:b32f4eec3c3318b969c91f9e90ad70b2242d3213e970e1660463916a86a8a01f` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:4084b99de4b1408240b0538b780841a006ec33f21a4d23346035a4ea32b3e272` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:f57acf4f92feccaf527a3136e98e0c62e8793e1791777cf2810fe80d9864381c` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:75fee22c4117c5669cf0b25919bda19d9dd09d68faa223d6fc2bcf42c4b1045b` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:797e292bde61047478891c4753ee3e83d53e5adf90fac0f2870f3a5a74465909` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:81745756a07140ab4d6633127a602d24ea2e43eedbf1803eee531b391fcbd1bf` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:10c1bc687b7b161f69a70c174f548b1a6708c0e87394630574e19ddcd791c960` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:99b79e74239ef796716c5ddd713dbcf9bda1ca10c4b6368916e6736f4b290f1a` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:03329a4920190ad468ca25efb3ca0848cac25529e67e23273f2b6126ea7b126d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:06d016c0dc874b965838fcd75b9ab33f642c8dde4f995b545da8ce88506c79d0` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:0832ded750cdd02c6465643c4472466116da0c4543272bbcad7040e9ac166dee` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:3f7148afee2a0b067968500edbdc812560dbc5936fae54b6558474ac8a4687d9` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:ea8daa50baf855ebc90a9ce32cba0f9063d02f165f0badee508fb646b673e6c7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:5c60549653c64864562e650cd68bf6d8ffd188a8bed651d9a90d4fb7cc49c0ee` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:2d9c02287ce036d3f03f9a47e18c617a933e3797d06f5309431e3a4c52eb8d0e` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:56d9507dd0e963d4c9391523388f28f105c1414c49cea88e0047aade1298663d` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:7b1b9bb523ffbadf3fe64cffd26bec00e2d6fd6c17aa068d933c5371237b4e0e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:b14ee59f7d8b27885fd96e5bb0f20222825045013c5827525f291844a597c26a` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:8f009ea19064c0f16810c3751adde06a46aa57c19b400218bfc84972da0319a1` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:8c4fadc988b2622baeb59e203fea0301c5f3810988c51aa1e9ff383d9720a5af` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:b55a0102ac4e3332e525d2353d74b80087b1fdc6d2929fcfb9f2c8948441b92a` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:a44a0169819cfa3ba7f4476ec9ec1a688db2144a2938eb19d0331b0a08ec6a7c` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:e086346b0b860573717854e8324ed4d4dfba870e845c846da962de6156aeffaf` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:301c5b61cf344e119d14f4c6630a5b0fa03384bdbe65a5f54a0bc90e799a8e2e` | `verification-decisions` | `verification-evidence` | `false` | + +### rust-validator-proof-gap/context + +- branchName: `bitcode/remediation-read_rust-validator-proof-gap_7044fe8972-rust-validator-proof-gap` +- readId: `read_rust-validator-proof-gap_7044fe8972` +- assetPackId: `asset_pack_3b7a68101d23` +- proofContractHash: `sha256:34f2a976e6dc61ca978b606608d7205e2c5c0cd4ed5e8eb38fdaea91c8faa026` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:4f09eb2ae7c6db3a769ab72b39c692158c09da634ddd72b205c3d7a507783ede` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:b55a0102ac4e3332e525d2353d74b80087b1fdc6d2929fcfb9f2c8948441b92a` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:fae43adb9a288eabaf5946221c0715414693f6cf144b78fd3b6a8b43fe4b54ab` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:54673ee8002b9b47cdf6543c747ea377da8d7a2f4b16672a7d3f1cd01cd08acb` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:d5c9baa464fc2e61ec0f46da3be4a4eef78cf0ea474feb6a3198e14feb1b5e11` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:2fbb1f37244e7d0a1e313cfbe7f24e1cd88a6059bea1efe553030c45f3d31d24` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:34f2a976e6dc61ca978b606608d7205e2c5c0cd4ed5e8eb38fdaea91c8faa026` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:aa38f0352b0b25daa0bb120f6ec6bba92ad433f14fdbb522171f11e24add092d` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:10a58df1e6f48dcdf09098f83021c983c8bfe3c17173dc79b4a9e73e3fd96258` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:54673ee8002b9b47cdf6543c747ea377da8d7a2f4b16672a7d3f1cd01cd08acb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:9c7af812b1bcb7516c38c90fd583b05d5cd66d5892985f87832e940eb44368f9` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:7bd6a0865e9267411b854f91754b10dc446d1b20375009a3099e670933eab4fb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:9be5dad921d2f261390a9b2fa5b46eb84cd82439e38cc1c3e49693d9820b0619` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:2fbb1f37244e7d0a1e313cfbe7f24e1cd88a6059bea1efe553030c45f3d31d24` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:7bd6a0865e9267411b854f91754b10dc446d1b20375009a3099e670933eab4fb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:005ee8e731b1b3e2bf9134cb4cc74dab81217681adfde3219d24f2ae78564e2d` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:2287984d304bf31068f4c3517233a3f7da5f2dc444ee5236b539bfd548e7be5a` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:6fb14d8000883576783bf728694ae38f202197fa34e056d59e4ea56e44642887` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:0ba1bdf22cb299df63508fa49e6d994d716d0a5d89e426c260c68ebccd969771` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:276a42d09d1c3507cae113787129c222569bdb7a9934d70c791715e3a490b6b1` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:4f09eb2ae7c6db3a769ab72b39c692158c09da634ddd72b205c3d7a507783ede` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:5e125c7620a790c8e3fd50ad27d8602568d5d43e00b0aff8b8efa52127286d59` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:e9c4799551aa74c418c9d483f98e19bb6ba61e073607f4bb7c058805a8032d61` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:b426ce94afa920bc8d16702fd2f54da342ba198387e30b237bf9d58305153be7` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:2fc6ecb431bf4672b35049183c26ce43260e20c9a79a2cea65b089ee7820ab2a` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:4084b99de4b1408240b0538b780841a006ec33f21a4d23346035a4ea32b3e272` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:f57acf4f92feccaf527a3136e98e0c62e8793e1791777cf2810fe80d9864381c` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:75fee22c4117c5669cf0b25919bda19d9dd09d68faa223d6fc2bcf42c4b1045b` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:797e292bde61047478891c4753ee3e83d53e5adf90fac0f2870f3a5a74465909` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:81745756a07140ab4d6633127a602d24ea2e43eedbf1803eee531b391fcbd1bf` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:10c1bc687b7b161f69a70c174f548b1a6708c0e87394630574e19ddcd791c960` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:99b79e74239ef796716c5ddd713dbcf9bda1ca10c4b6368916e6736f4b290f1a` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:7bd6a0865e9267411b854f91754b10dc446d1b20375009a3099e670933eab4fb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:63ef504f3945894d77cc0974005bcce1092d5982ec3deb3ee2037d96f4aea598` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:fae43adb9a288eabaf5946221c0715414693f6cf144b78fd3b6a8b43fe4b54ab` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:3f7148afee2a0b067968500edbdc812560dbc5936fae54b6558474ac8a4687d9` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:ea8daa50baf855ebc90a9ce32cba0f9063d02f165f0badee508fb646b673e6c7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:5c60549653c64864562e650cd68bf6d8ffd188a8bed651d9a90d4fb7cc49c0ee` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:ca40d86f416da0c66700f1a3ca2dc6651a16ce69276bda6c0c081987edd67c39` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:25dca8a8160905ae58f03c40b3e12dfc364ffde6092510d80df425313a973380` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:faa095740f49cc6fcf3378253dd0e6416df8b6c3e9bb655c0acd1ac3c3ea2fd3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:d5c9baa464fc2e61ec0f46da3be4a4eef78cf0ea474feb6a3198e14feb1b5e11` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:8f009ea19064c0f16810c3751adde06a46aa57c19b400218bfc84972da0319a1` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:8c4fadc988b2622baeb59e203fea0301c5f3810988c51aa1e9ff383d9720a5af` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:b55a0102ac4e3332e525d2353d74b80087b1fdc6d2929fcfb9f2c8948441b92a` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:a44a0169819cfa3ba7f4476ec9ec1a688db2144a2938eb19d0331b0a08ec6a7c` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:e086346b0b860573717854e8324ed4d4dfba870e845c846da962de6156aeffaf` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:e1b0f6f5888d135bf3693643e4c5248d55809ecaf74e7a9bbf1533682b4fac31` | `verification-decisions` | `verification-evidence` | `false` | + +### config-policy-precedence-incident/patch + +- branchName: `bitcode/remediation-read_config-policy-precedence-incident_f39d972e54-config-policy-precedence-incident` +- readId: `read_config-policy-precedence-incident_f39d972e54` +- assetPackId: `asset_pack_d0c7f0b06b9a` +- proofContractHash: `sha256:83aa4f69425eb95cb36148bfada58f4d224013ca26a2917c9b69bd61da2a57ac` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:b128d3ebfafc59642ae7d5574f24afe8f80dae532dcf68c24cef779bce0666c0` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:adab7903446c23a53b6104c1e12fefca4bd54fe2bba624f440d3aa2e774b2068` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:cef9aa43641f124d922603a162b931dcf0c616ce487316b777cdc29b976f03ed` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:1ef6377e7a3c393fe2fc43f8a9b54f24904631c887e365200062f87c720d08d4` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:9b61e0764eaca5f2d924d2f7b7a62c993489998c320433aee84d03ed62a236bf` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:43693ee69ddeef8ddbf2fb1059065789e6112ca8afa015368d31bdd12ec08c95` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:83aa4f69425eb95cb36148bfada58f4d224013ca26a2917c9b69bd61da2a57ac` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:acd148ad1e066d9d770424e43c377e9e516aedab81942860b14da52311d0dc4e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:8b08e9c366913f1acc0fc80e40c4031756e21361ca5d502c15676c6e9aaf07f9` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:1ef6377e7a3c393fe2fc43f8a9b54f24904631c887e365200062f87c720d08d4` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:91869ba61a06e71b4a0c8b430851ec4be13b56f1a48a5b2acabceca62a690ca9` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:f4ea54ea40d36968ee1f9f3cf6938f04df6f448f98b4f5acad7a015bfed90ed8` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:46c77dccc38b3630e07c447f4b225e623dbf31b5ecc980da11f07dd8b33a975f` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:43693ee69ddeef8ddbf2fb1059065789e6112ca8afa015368d31bdd12ec08c95` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:f4ea54ea40d36968ee1f9f3cf6938f04df6f448f98b4f5acad7a015bfed90ed8` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:6b7459c00d2b7f8de4da8c1dd507ff91f04e8e3bd61f52257d59e28ae86f69d4` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:cc3c680acc654e92261f714408b1cb0f2bbdc45d5623570d4ab6deecf552705b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:2b239e284be7d4bf2a1f43342e7c5318f77e5212e06257bfe663564893ff21ae` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:3c7873de78e25bb306c492ef3018539a5a164dbc34bb957a1016351c6d445808` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:f5c66f068437c614430df435bca8880c968a92209ee38ee56c564ad60ff678f1` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:b128d3ebfafc59642ae7d5574f24afe8f80dae532dcf68c24cef779bce0666c0` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:2a6e281fcd4a3d35f937a54f6906a4f063b301ec1fa4b7bbbd734091eb60a10f` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:c60b87b9eae4982faffb851a30b8d5cae58d436d34f1a460e9e7c7c1a0ea0989` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:7ffbb056c93ce895989b51308a6c83ab5022c974f8ac26d27aa29b43011cb122` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:1c9350dc5d2544a80dde57b1b15d8075cfcea39658d105312f5bba32521f93b5` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:e71a0789bffb8fba9b03092e766d0f589299c55d14f8d61edbf4a750a6c3b1b2` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:d717a53262cb2b72f17796e62b9b37cf4e20d1e90410560ed03db9fc7051b0d3` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:5e34372dc7330b48d668a36d656c06ceda4545f5911669c8da146fb4cb9be7d6` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:e47ded65b7fa05c782049d88d0b5e48b71facde2517912023d24e7a306c364ca` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:c91b6d44013d9514498b464bc4c6dce52197bdf70121663ada56f7af3c331da4` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:3e365f6603e4066510fc07f0c16c245058c19b77e1b796ddc3e50d5ac5f2b91b` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:fe4a268e5d78b61c451ed9eabda2a6a27e2264ac39f8ec724cb2b9f82ee5272f` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:f4ea54ea40d36968ee1f9f3cf6938f04df6f448f98b4f5acad7a015bfed90ed8` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:80f8353e889bf019158f21988f781765f90b0f126df426fcfc76ded8d3e639ef` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:cef9aa43641f124d922603a162b931dcf0c616ce487316b777cdc29b976f03ed` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:501307fda8ba5ca845f985e7c2857595abc67ce54037f07ffa384080d45ca725` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:fdd7c9f7f92d31fd298f5a2259959d8f8e9b0cb1ce754e5d4a5a84aba4aa196b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:e3d46ecde5251218d94eec6efa209db2ebd7d2e1e5961b19fe07f2d1990292f7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:d4b23a10fd81910d3ec2b5a0b275f4507b4146685e3a833c94c2623970b5e49b` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:419448fbe69f2f592f7cdd64ebfb2f91d115670b389db2b0116cae60d0186036` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:b171b6c6807c2d2e6d94fd0565a9bed9c9963572c963aebe2ffc70453fcea25d` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:9b61e0764eaca5f2d924d2f7b7a62c993489998c320433aee84d03ed62a236bf` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:ba57d7503ee19baee3d14abff0c0386aa5c6cac616c94d37a6d7f94d419b3d98` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:127fb3e912d2a9f00a0c90ad1ac6daf42ed6ffe34b8d8cc210bec5ac364252cd` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:adab7903446c23a53b6104c1e12fefca4bd54fe2bba624f440d3aa2e774b2068` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:1bb54e49a9d35a309f6d4609c114a240249ed537150afec8202fe0d882fb91cf` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:a1381778eb0d0d9e70b82d62afea7706a13fac1c92463a1773ba98ede85ab24a` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:b0b2c05d233f7c7ac9f7128e3f5b2988c415ae795975afe6d79660b2e7ef8027` | `verification-decisions` | `verification-evidence` | `false` | + +### config-policy-precedence-incident/context + +- branchName: `bitcode/remediation-read_config-policy-precedence-incident_f39d972e54-config-policy-precedence-incident` +- readId: `read_config-policy-precedence-incident_f39d972e54` +- assetPackId: `asset_pack_d0c7f0b06b9a` +- proofContractHash: `sha256:83aa4f69425eb95cb36148bfada58f4d224013ca26a2917c9b69bd61da2a57ac` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:b128d3ebfafc59642ae7d5574f24afe8f80dae532dcf68c24cef779bce0666c0` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:adab7903446c23a53b6104c1e12fefca4bd54fe2bba624f440d3aa2e774b2068` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:5effc18dd1f65e1188616aa32cf8e4dc3a8a06bdd3eb95cc2e04341d166fca65` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:1ef6377e7a3c393fe2fc43f8a9b54f24904631c887e365200062f87c720d08d4` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:bb393d54832f9a216f0fe6129671c9369071e0cf78aa823ea5eae59c1d0383e1` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:5610c4975fb289b3909932d3f5b53a7032b7a2507f60ec1b69079cb50f84dbf8` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:83aa4f69425eb95cb36148bfada58f4d224013ca26a2917c9b69bd61da2a57ac` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:95b45ae9eb9536bbfee549a496b4063a1be139c0c7afb6c793c4e2cb78d94012` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:4327385821b6c9f534039e1493494702105307e978a3b06fb3403794861f541f` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:1ef6377e7a3c393fe2fc43f8a9b54f24904631c887e365200062f87c720d08d4` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:91869ba61a06e71b4a0c8b430851ec4be13b56f1a48a5b2acabceca62a690ca9` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:74c8e4cf02f637a9e6dc48854666992a91f6402dd5f80b2f31bfe483df9ef71c` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:46c77dccc38b3630e07c447f4b225e623dbf31b5ecc980da11f07dd8b33a975f` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:5610c4975fb289b3909932d3f5b53a7032b7a2507f60ec1b69079cb50f84dbf8` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:74c8e4cf02f637a9e6dc48854666992a91f6402dd5f80b2f31bfe483df9ef71c` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:6b7459c00d2b7f8de4da8c1dd507ff91f04e8e3bd61f52257d59e28ae86f69d4` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:cc3c680acc654e92261f714408b1cb0f2bbdc45d5623570d4ab6deecf552705b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:2b239e284be7d4bf2a1f43342e7c5318f77e5212e06257bfe663564893ff21ae` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:3c7873de78e25bb306c492ef3018539a5a164dbc34bb957a1016351c6d445808` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:f5c66f068437c614430df435bca8880c968a92209ee38ee56c564ad60ff678f1` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:b128d3ebfafc59642ae7d5574f24afe8f80dae532dcf68c24cef779bce0666c0` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:0309f74cd280d6f56073065c73e01a0d81a260e6dd1e7d6c10c8f27ab9eea4e1` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:255aac1f31bf9ca54f311e31ecec87028cc6fa19815508a35292c16f480881aa` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:a5170676e5a1483126e7e8ec86a8740c5a033c44bfada9f7d54cc6fc9307ba13` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:ec141f1062a9fd079135318d1407ccab9340f96c037cb5fc2de32aea4918e3d7` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:e71a0789bffb8fba9b03092e766d0f589299c55d14f8d61edbf4a750a6c3b1b2` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:d717a53262cb2b72f17796e62b9b37cf4e20d1e90410560ed03db9fc7051b0d3` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:5e34372dc7330b48d668a36d656c06ceda4545f5911669c8da146fb4cb9be7d6` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:e47ded65b7fa05c782049d88d0b5e48b71facde2517912023d24e7a306c364ca` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:c91b6d44013d9514498b464bc4c6dce52197bdf70121663ada56f7af3c331da4` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:3e365f6603e4066510fc07f0c16c245058c19b77e1b796ddc3e50d5ac5f2b91b` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:fe4a268e5d78b61c451ed9eabda2a6a27e2264ac39f8ec724cb2b9f82ee5272f` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:74c8e4cf02f637a9e6dc48854666992a91f6402dd5f80b2f31bfe483df9ef71c` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:6690719da2460798a8b855d707f9ded84fc28ce60b00aec55636e9d99e47cdd6` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:5effc18dd1f65e1188616aa32cf8e4dc3a8a06bdd3eb95cc2e04341d166fca65` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:501307fda8ba5ca845f985e7c2857595abc67ce54037f07ffa384080d45ca725` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:fdd7c9f7f92d31fd298f5a2259959d8f8e9b0cb1ce754e5d4a5a84aba4aa196b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:e3d46ecde5251218d94eec6efa209db2ebd7d2e1e5961b19fe07f2d1990292f7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:9d143e66aa4753576e168a51b6c81203c7f90154f8762c493a1d7e3e914f8c56` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:b4f48f36750bb8e789199080421c4a051dadf37bc0519ca0738c263961d0afc3` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:93619dac9545954b993d6058012a17d6b6a87d961cf68699492f29d5bfc7cb89` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:bb393d54832f9a216f0fe6129671c9369071e0cf78aa823ea5eae59c1d0383e1` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:ba57d7503ee19baee3d14abff0c0386aa5c6cac616c94d37a6d7f94d419b3d98` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:127fb3e912d2a9f00a0c90ad1ac6daf42ed6ffe34b8d8cc210bec5ac364252cd` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:adab7903446c23a53b6104c1e12fefca4bd54fe2bba624f440d3aa2e774b2068` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:1bb54e49a9d35a309f6d4609c114a240249ed537150afec8202fe0d882fb91cf` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:a1381778eb0d0d9e70b82d62afea7706a13fac1c92463a1773ba98ede85ab24a` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:f542f2e9b69d290ed2e76869aa62bb244e070c10a3ffea8551c4d6e0aa225e27` | `verification-decisions` | `verification-evidence` | `false` | + +### unsafe-patch-review-recovery/patch + +- branchName: `bitcode/remediation-read_unsafe-patch-review-recovery_16a56c87c5-unsafe-patch-review-recovery` +- readId: `read_unsafe-patch-review-recovery_16a56c87c5` +- assetPackId: `asset_pack_fd3c892c8e9e` +- proofContractHash: `sha256:081e1b7dde51ffe365b65b8a69d22bef36b87ec49e90d3c5bc81f1d731ba23eb` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:1d10c217eace8afce8408b11245435b2e9081835c29f5f2da5f29c59e41b7cc5` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:f4fba9666f284d709559ee6516ee9563926a367b8f7c6351fca108f319f1b4b6` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:fcc2ca2a8cb1a47c046d4cb66e6cce5bda0205778c6ab6e262d3be2cf5871816` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:2260487892adf8f4485b3d2e93477abe006715da4c6b703f30d76a57e028a12c` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:a7bd13bcc1b386278afc294cdf8a4b9461667919c53fdac7649ad8a9c5950f68` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:45acb0a245c588240d0e9198a27e3ffa3a65362869d56727eb807343e4e36413` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:081e1b7dde51ffe365b65b8a69d22bef36b87ec49e90d3c5bc81f1d731ba23eb` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:211dcb4811d83b8ebc24e5c11af5fc09afb3c84e51c7d19b9f991fb7e7c81cdc` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:cdf13e57999ee55469779a4e1e2872709b99b67bf725465dc7a70ced3651cb4a` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:2260487892adf8f4485b3d2e93477abe006715da4c6b703f30d76a57e028a12c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:861d18b39f610b546a4844c2088add0be5d7ff4c72eece611e1535da52eb3d0b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:4c34cfb8e09abc3fea234130d5e22306e4384e7e02b72d10c38ed4e6a48f9ed6` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:fcf95143cf39d8b2e5adc6b3946dfecebfad11037cf136640f4ec5bc790ebf1c` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:45acb0a245c588240d0e9198a27e3ffa3a65362869d56727eb807343e4e36413` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:4c34cfb8e09abc3fea234130d5e22306e4384e7e02b72d10c38ed4e6a48f9ed6` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:5af4d72a61647343007d1e8d6be32522fe282588168586acd533564ae2cfc5bc` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:1c9b1263bb7b7369c5198c518dfabccd135d3bb66f52807b99022037b205f034` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:d0debea21fc12d3c1b01fe923ed58a92b5f9188074c7f35bf138cc5cdbedcc89` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:0b81c774979bc960c5470c092f9d0f240bf9cbec0454b4f6e9a6afa595589607` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:c1cea028a02c09bf4071337f6971368a1ca149b1172b7cc0e251b9d3794e4245` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:1d10c217eace8afce8408b11245435b2e9081835c29f5f2da5f29c59e41b7cc5` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:b49a12e17932a30da0273d11cf9a47d7b2d43f51739526eacd600f272f2e1133` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:ce56c4fb5c0c3de094741a30c5a6e220192bb8b911ab4d9c0a172ef6b57180f0` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:1497918b2148fb9bad562416b2d46b90b85eeb988c3ea355e9aad5d38ea36547` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:ba634a091705d48920bbde42a75e0dc700bb1697c8b33feb68367b356814adf5` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:d27e089bde28105989dbbf6ec9bafe5da53f3c72ae8533e605b7c9f4ca12ff95` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:8af4e3ce8938d57e58bc1282d863cbfd15f15d6ba99c4972ab17d5bf1a571957` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:95ceba55806dcbebce98645a62a55e31b48767f7e5c1aa2fb5fd2d3a1ba512fa` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:139369067a8d2d1ec94ed67bb51ba0b2ad74e92af71a988fda83113eb9edba14` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:566ba4e640705978e4064fa1c9c8d55b77f0fe7cfde0d4b112d006edc0ca63f2` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:927b1a4ce68b0ccc92e9e85c605b2e2f2d2ff0011b39b46c2ea31c4e2de6712b` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:a42c8c346a20e5c82f84941bf3245ab46a5d9a111ffb073398a5e51e3eda7cab` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:4c34cfb8e09abc3fea234130d5e22306e4384e7e02b72d10c38ed4e6a48f9ed6` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:241a88c2df2623a0f2fda365a4b56fbd0b87396d61b13975bd92331c85d16f22` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:fcc2ca2a8cb1a47c046d4cb66e6cce5bda0205778c6ab6e262d3be2cf5871816` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:6d85aaed7d0cf7270dc0b1a3f44b04df5487492cb02b8165e63c08e7efc38a7e` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:5cf464309b76a143cbf7a6aa7809b3ba933be40f9d5f216b525853ab6cfc675b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:eac0966d247f59693d31f91541d7f2874f5189ca831591199aedbd9b83af9fed` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:02cc19fd505fa15604a7ef08ef0c8ec020ffab6bb6dd32482e70392023aae9c9` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:19433854367ec23425e38e1b53936787abe6160b52cd15ee32bb7e9c42ebad69` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:1e847396743898e5595e7e509eec458e430bedb888294df628c18ced2ed39ec5` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:a7bd13bcc1b386278afc294cdf8a4b9461667919c53fdac7649ad8a9c5950f68` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:2cfd1ebd2206bd145f3eb79ca92d6692b40f55283c973459914e90dcaa1a6786` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:7f74d3f672716b233b03ebcb59b539cb47a10b112acf59c72b921045a902f8c5` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:f4fba9666f284d709559ee6516ee9563926a367b8f7c6351fca108f319f1b4b6` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:49801567def5c6832d2e1fad1c1ba1f3a03dbf85a224802074b5d0dd777bbe2b` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:1f8cfc578c11877161af68cfc1d58f850f8396dfa98db01b914a69f69bc5f991` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:413f02b330e067566024cf79bd561e81f9f975ca2d9eec2c7bfb29e6c472964e` | `verification-decisions` | `verification-evidence` | `false` | + +### unsafe-patch-review-recovery/context + +- branchName: `bitcode/remediation-read_unsafe-patch-review-recovery_16a56c87c5-unsafe-patch-review-recovery` +- readId: `read_unsafe-patch-review-recovery_16a56c87c5` +- assetPackId: `asset_pack_fd3c892c8e9e` +- proofContractHash: `sha256:081e1b7dde51ffe365b65b8a69d22bef36b87ec49e90d3c5bc81f1d731ba23eb` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:1d10c217eace8afce8408b11245435b2e9081835c29f5f2da5f29c59e41b7cc5` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:f4fba9666f284d709559ee6516ee9563926a367b8f7c6351fca108f319f1b4b6` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:f6abbdaf4249320486a9fd70d316ab1edda52b764cc4242f0136c40efa30ef27` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:2260487892adf8f4485b3d2e93477abe006715da4c6b703f30d76a57e028a12c` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:d0e3bad9478b45ec41131e9b79f625426f75e870265f91104f859ac8cbe7b7c6` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:1821843556aeb7ea7924f52129b0e00e9e7c35a7795f842947bde87b9120b743` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:081e1b7dde51ffe365b65b8a69d22bef36b87ec49e90d3c5bc81f1d731ba23eb` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:aedd512b38435c2c8788db85a80e13b2b3fc29417c12b244ad61101af9ba8b60` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:10fb949ac86f2c3234beeb4453c01b73de4a46c1413ccc83edcb9dff1074df5a` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:2260487892adf8f4485b3d2e93477abe006715da4c6b703f30d76a57e028a12c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:861d18b39f610b546a4844c2088add0be5d7ff4c72eece611e1535da52eb3d0b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:3920104b24531e329948f80b2d900fc98cfc42698d4ac1fa0e7286df74a5e01d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:fcf95143cf39d8b2e5adc6b3946dfecebfad11037cf136640f4ec5bc790ebf1c` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:1821843556aeb7ea7924f52129b0e00e9e7c35a7795f842947bde87b9120b743` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:3920104b24531e329948f80b2d900fc98cfc42698d4ac1fa0e7286df74a5e01d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:5af4d72a61647343007d1e8d6be32522fe282588168586acd533564ae2cfc5bc` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:1c9b1263bb7b7369c5198c518dfabccd135d3bb66f52807b99022037b205f034` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:d0debea21fc12d3c1b01fe923ed58a92b5f9188074c7f35bf138cc5cdbedcc89` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:0b81c774979bc960c5470c092f9d0f240bf9cbec0454b4f6e9a6afa595589607` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:c1cea028a02c09bf4071337f6971368a1ca149b1172b7cc0e251b9d3794e4245` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:1d10c217eace8afce8408b11245435b2e9081835c29f5f2da5f29c59e41b7cc5` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:7c1ebcb79090dd09243552478df9b9eb637bedbd91044dda36836887a4f4332d` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:bbaff4c9e409f03b11defdf0c152826374fde34f79b7a07be8b38471ee547e36` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:0979d8fece848a46034cff3b7439c73928e4490316688e0a5458a29d4251c34f` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:c106e15b75acfbdfe03de98f435b1e8c8c8ebb59867e0e6a1341a810935cb245` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:d27e089bde28105989dbbf6ec9bafe5da53f3c72ae8533e605b7c9f4ca12ff95` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:8af4e3ce8938d57e58bc1282d863cbfd15f15d6ba99c4972ab17d5bf1a571957` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:95ceba55806dcbebce98645a62a55e31b48767f7e5c1aa2fb5fd2d3a1ba512fa` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:139369067a8d2d1ec94ed67bb51ba0b2ad74e92af71a988fda83113eb9edba14` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:566ba4e640705978e4064fa1c9c8d55b77f0fe7cfde0d4b112d006edc0ca63f2` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:927b1a4ce68b0ccc92e9e85c605b2e2f2d2ff0011b39b46c2ea31c4e2de6712b` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:a42c8c346a20e5c82f84941bf3245ab46a5d9a111ffb073398a5e51e3eda7cab` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:3920104b24531e329948f80b2d900fc98cfc42698d4ac1fa0e7286df74a5e01d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:9885cb919e9f819c193899633241241f3217d2583aa76d8719a6f5fcc5308e0c` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:f6abbdaf4249320486a9fd70d316ab1edda52b764cc4242f0136c40efa30ef27` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:6d85aaed7d0cf7270dc0b1a3f44b04df5487492cb02b8165e63c08e7efc38a7e` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:5cf464309b76a143cbf7a6aa7809b3ba933be40f9d5f216b525853ab6cfc675b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:eac0966d247f59693d31f91541d7f2874f5189ca831591199aedbd9b83af9fed` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:5ce74f215f9d60e8005345240f4ece14b01bf4d68cca0e452e66f69fea4a77c9` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:6ca0519ff7c12cc846645d1b0340688b7cd5391f185dfc67584a325f853cfc01` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:5aaca53542865b3794065212b504d1c0901e2b805b44aed4934c50a66b7e6a2d` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:d0e3bad9478b45ec41131e9b79f625426f75e870265f91104f859ac8cbe7b7c6` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:2cfd1ebd2206bd145f3eb79ca92d6692b40f55283c973459914e90dcaa1a6786` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:7f74d3f672716b233b03ebcb59b539cb47a10b112acf59c72b921045a902f8c5` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:f4fba9666f284d709559ee6516ee9563926a367b8f7c6351fca108f319f1b4b6` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:49801567def5c6832d2e1fad1c1ba1f3a03dbf85a224802074b5d0dd777bbe2b` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:1f8cfc578c11877161af68cfc1d58f850f8396dfa98db01b914a69f69bc5f991` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:c21060722cded736cd426fea75d1310b1458fc6d3366e55d6b39576890499366` | `verification-decisions` | `verification-evidence` | `false` | + +### infra-deployment-mismatch/patch + +- branchName: `bitcode/remediation-read_infra-deployment-mismatch_be8a999141-infra-deployment-mismatch` +- readId: `read_infra-deployment-mismatch_be8a999141` +- assetPackId: `asset_pack_9f1b844a2cdf` +- proofContractHash: `sha256:7170c26e2b0d89451f79fe30b5e96f548a4f0c5e45f1947ee0fcefb109f93ca6` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:6a44eb26908aadf6943c6411c6e798675331f88d6e670690ac29f72f2df2d971` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:de13e187f609cf5b5a4f7462d404f3e5b6a9ec6a1b5409af0a41d54be89c7637` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:a8f038138ceed6859020675d71736cdba5a587e6b48ddb29133db3011ef74d52` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:2c1624cf684ae0a83834d9c7a28789d966ff776e1c61c5fbb611b5d73392547c` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:53e4472e0cf10ebdeddb6ae3b5e212f910a837ed1115dcd4175fc6f46f737650` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:5bde14deb75ac18013f2f69e21112f774c1d4322a93489e95c3919c7a967f7d5` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:7170c26e2b0d89451f79fe30b5e96f548a4f0c5e45f1947ee0fcefb109f93ca6` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:e6eb896b77c9fb159e64a9e29533a7c305055e01a579aeae6efbbb42bef72b77` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:d4d3e9495263cb92a69fddd0f7edb72c63c7c303c4cb5535f352ec51604959e8` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:2c1624cf684ae0a83834d9c7a28789d966ff776e1c61c5fbb611b5d73392547c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:7b13703fa960cd2cf144e019b6e8cd541fcb82971617d39a5efa55ce5fee4a48` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:af3e0c2cb3148443ca9f967906fa079cade336b39bbd36b05e6f031353dc0715` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:40ae2a0b1f3a8f3370377819b744468030b79949a618759e65ece60795cead87` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:5bde14deb75ac18013f2f69e21112f774c1d4322a93489e95c3919c7a967f7d5` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:af3e0c2cb3148443ca9f967906fa079cade336b39bbd36b05e6f031353dc0715` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:a8eaafd9cce896dcd701c46d7b069314d5230252e5ed2f10fd99e594409d0bee` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:965ba1aff4604765638f5f2fba6721007f57f6d4fa553938df7397fa460ad8d1` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:980c3e9afa612cfbdae5fee2668cea479236ea1ed699ed688ed553f8d960a054` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:a1e7ba65e662bebe0b9babb6067655b7cdcbaa5876d82140a3e84ecd8a892726` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:a7f910211080b140df9104153bc1ee2ca4e79cc014b42d89ee687e24278319c6` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:6a44eb26908aadf6943c6411c6e798675331f88d6e670690ac29f72f2df2d971` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:a7ca588dddbfafce36107d95c7d237b46c644c0122614e4967656c308fb38365` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:a726a4c350631cdff6d4f512a3b6cd30f7cf26b33077ba1049b66c54cf229fae` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:cbacb2561b13b5e8480a7fbc23488dfd87df92f9c07098d4bba449941109b45a` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:f27a92cfffb61f084e63838cda18b35ebd4b118170f88b06e427f9c8844464bf` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:598b7bb92d2791407ac01d15fe35c2b46f729c30534b819dff177672e9c44166` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:9c29647f452b16962ba7c3046d365f04e63e667df669fdcb4d0f16322c3de76e` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:adfd68a5c9458827e53484abc4f4b7c24320972545e0f5becd4c3443d1b828fd` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:ebcb977eb8b8ad5a9fcb3d6640307ad033c642f08fab42326f1a2e7844752525` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:c3732845741f36061ac1103c9b2485c814592989e3402bc91a38f7a8541b38af` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:469e541169edd2d2bde8ff4ff540b41b3e2ad528438a1f425a644a9aabd2018c` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:e178cb17a881d2d0de927141ac19877252fc1f4c09d4788e2209b7b2b738914d` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:af3e0c2cb3148443ca9f967906fa079cade336b39bbd36b05e6f031353dc0715` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:e1818adb231f247cfcf9d54189d132f7c6d27020d5af67ab2c8d5ed3a3117aeb` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:a8f038138ceed6859020675d71736cdba5a587e6b48ddb29133db3011ef74d52` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:b0acbf48dbd4c5a4202a8683fc011822c96f6d7c566fd287412d544f7de1b4be` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:8f1970d50b815044e763d8f192ab7269689ea0b3916334f534df680e4b3eed57` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:7ecd2a609dd792ae261d77cb4700c2651625b713f8f9591bddb655cdf4c46d41` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:aef45c4332d64546c4ae0c94af83be2384f25ba49770b025c5bf85e40b82d71f` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:7cafe2b41af74f6a20eb15346a5100fcdb9026530df8386fc049bb792c3e9030` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:30518f8d5444b646771c961b268999103b5bd54a9a1438ff50d1813931edad56` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:53e4472e0cf10ebdeddb6ae3b5e212f910a837ed1115dcd4175fc6f46f737650` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:81cb9d04a88483e9a534ebb47a3c9dba1ca3ccdbfe7dd6b363516979753c0a6c` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:83a7bab745ba09dfc97ccf73bcd18da3eb142a2fa54c5658fa3b4148abe8d95e` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:de13e187f609cf5b5a4f7462d404f3e5b6a9ec6a1b5409af0a41d54be89c7637` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:cef9d5e516f74689f3dc7315086660e2dd6d1385337367ac0038bb3681c53fe9` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:f3c07955bda1811b7befeb99a29ab2fbb34cf03b5205acaffae2666ded0e3101` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:9ad8913a7164bd62626a4027a290acb2c365da1091098ca0bd8a88621f13dcbf` | `verification-decisions` | `verification-evidence` | `false` | + +### infra-deployment-mismatch/context + +- branchName: `bitcode/remediation-read_infra-deployment-mismatch_be8a999141-infra-deployment-mismatch` +- readId: `read_infra-deployment-mismatch_be8a999141` +- assetPackId: `asset_pack_9f1b844a2cdf` +- proofContractHash: `sha256:7170c26e2b0d89451f79fe30b5e96f548a4f0c5e45f1947ee0fcefb109f93ca6` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:6a44eb26908aadf6943c6411c6e798675331f88d6e670690ac29f72f2df2d971` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:de13e187f609cf5b5a4f7462d404f3e5b6a9ec6a1b5409af0a41d54be89c7637` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:4ed2198c3827ebb995f8a02e140884f55fc4af51746f586804533a0bcc7f6904` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:2c1624cf684ae0a83834d9c7a28789d966ff776e1c61c5fbb611b5d73392547c` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:df2768d346405d0277894299351973b730a660e7f710af0b6f30f210d699c1af` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:7f7de72b8b776f3b6b5250fb88ebb9efff0c3c67ba93043fc3efc63d507ea0a6` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:7170c26e2b0d89451f79fe30b5e96f548a4f0c5e45f1947ee0fcefb109f93ca6` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:7d34b19c9298cfe043e5ab0096e5766e839444a3027c806efd64f115e98a38b9` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:8c81abd46de1f27dccd1607ef96d0fdd79f0f64d6436918478e6872d010660f1` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:2c1624cf684ae0a83834d9c7a28789d966ff776e1c61c5fbb611b5d73392547c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:7b13703fa960cd2cf144e019b6e8cd541fcb82971617d39a5efa55ce5fee4a48` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:0ee4bbf7e89b96f7249da804ad174d47b8ed2133ca5ee6d533b080eafdeca75d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:40ae2a0b1f3a8f3370377819b744468030b79949a618759e65ece60795cead87` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:7f7de72b8b776f3b6b5250fb88ebb9efff0c3c67ba93043fc3efc63d507ea0a6` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:0ee4bbf7e89b96f7249da804ad174d47b8ed2133ca5ee6d533b080eafdeca75d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:a8eaafd9cce896dcd701c46d7b069314d5230252e5ed2f10fd99e594409d0bee` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:965ba1aff4604765638f5f2fba6721007f57f6d4fa553938df7397fa460ad8d1` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:980c3e9afa612cfbdae5fee2668cea479236ea1ed699ed688ed553f8d960a054` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:a1e7ba65e662bebe0b9babb6067655b7cdcbaa5876d82140a3e84ecd8a892726` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:a7f910211080b140df9104153bc1ee2ca4e79cc014b42d89ee687e24278319c6` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:6a44eb26908aadf6943c6411c6e798675331f88d6e670690ac29f72f2df2d971` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:3dc46c757b0617248af558fcd07a9e7e1a76281804749174d8e8100cf3fe24c5` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:7779bde5b2647f3de068b07f9d17fcfeceeea06564c801e6da94240cbe6ff0d9` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:53ce7e742f5a762e92a11728f0fbcd2785f87f4c4fd1564256a6948601932e03` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:3f3fe6bf4ec60092b5dd255619c6f5938268123cead2ce104e6a2ed9c5ede4b9` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:598b7bb92d2791407ac01d15fe35c2b46f729c30534b819dff177672e9c44166` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:9c29647f452b16962ba7c3046d365f04e63e667df669fdcb4d0f16322c3de76e` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:adfd68a5c9458827e53484abc4f4b7c24320972545e0f5becd4c3443d1b828fd` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:ebcb977eb8b8ad5a9fcb3d6640307ad033c642f08fab42326f1a2e7844752525` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:c3732845741f36061ac1103c9b2485c814592989e3402bc91a38f7a8541b38af` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:469e541169edd2d2bde8ff4ff540b41b3e2ad528438a1f425a644a9aabd2018c` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:e178cb17a881d2d0de927141ac19877252fc1f4c09d4788e2209b7b2b738914d` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:0ee4bbf7e89b96f7249da804ad174d47b8ed2133ca5ee6d533b080eafdeca75d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:93d3913609ce424a9e1fa849345755f1447e5d1da6b3df68afc118c72332155c` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:4ed2198c3827ebb995f8a02e140884f55fc4af51746f586804533a0bcc7f6904` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:b0acbf48dbd4c5a4202a8683fc011822c96f6d7c566fd287412d544f7de1b4be` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:8f1970d50b815044e763d8f192ab7269689ea0b3916334f534df680e4b3eed57` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:7ecd2a609dd792ae261d77cb4700c2651625b713f8f9591bddb655cdf4c46d41` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:7ad6bd3fd130367f088328db7f66846195082ec030bda9f4a9b5efa3ab04c7d2` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:0a31a8bd83ab1d4b208f31790940e2fed1c7ecedda8e3b904fb25b0824fdbbb5` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:e5fdec8d3f9cc0ae660fede823a31ffdddab96b3b2fdb808738bc2385ba59d0a` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:df2768d346405d0277894299351973b730a660e7f710af0b6f30f210d699c1af` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:81cb9d04a88483e9a534ebb47a3c9dba1ca3ccdbfe7dd6b363516979753c0a6c` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:83a7bab745ba09dfc97ccf73bcd18da3eb142a2fa54c5658fa3b4148abe8d95e` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:de13e187f609cf5b5a4f7462d404f3e5b6a9ec6a1b5409af0a41d54be89c7637` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:cef9d5e516f74689f3dc7315086660e2dd6d1385337367ac0038bb3681c53fe9` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:f3c07955bda1811b7befeb99a29ab2fbb34cf03b5205acaffae2666ded0e3101` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:ec573f60d7da9ee38a61fec3d878f0a510ab8ceb82fef3d44eb61406c40d1979` | `verification-decisions` | `verification-evidence` | `false` | + +### privacy-boundary-proof-export/patch + +- branchName: `bitcode/remediation-read_privacy-boundary-proof-export_8163942d95-privacy-boundary-proof-export` +- readId: `read_privacy-boundary-proof-export_8163942d95` +- assetPackId: `asset_pack_c5fef3ab17c5` +- proofContractHash: `sha256:94214cf13298a6992d32afa5572d4359fc9c21a74ab86c4625e2b03d3a1a6d6c` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:af111ab74d6aa230fc1ae3a12a02592d15e6476d692beb927a2480c2033c8b60` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:dde5e174eddf0911801b1eb8845991d70f97df445d99c45e1002e24c80ab721c` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:9c75d8e790d30a067d1eebbd604bacf8be0ddab8a1b121e9b71f7e4fd1871ec3` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:d0a68ad68adbab5b801152274edbd5e7914f9172858603b62f2b16ba47c23c8b` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:79f9ea2fd8b58ef8177936d2819e6c1d135693c93aec5c3365d5893ef535a83e` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:f19ba812efd8d9010544988cbf24396d069b1996f6e96d3414278422ca581d3f` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:94214cf13298a6992d32afa5572d4359fc9c21a74ab86c4625e2b03d3a1a6d6c` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:880417de4a0cbaa4d2f42bc0b11ab35ae6f10df26bf243dd13eaac365485aacf` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:e37a1973ff0ecb2bfff26028905d753286e6ce17c636cc944775ed6628a1bec2` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:d0a68ad68adbab5b801152274edbd5e7914f9172858603b62f2b16ba47c23c8b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:c7d8fb99bff075054c3d7512abc6b7e4302655afeaf8591f8f1702c2cf50eb7e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:f7c3eaa6764f14eeee4e24e7692dfa16936c6051f3fb3f30a3464aad5ddaeca8` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:2e3fe016971d44f9df40986e81e57c0d8aabfd3e4d7c1fb71a8b91883a0af3a6` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:f19ba812efd8d9010544988cbf24396d069b1996f6e96d3414278422ca581d3f` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:f7c3eaa6764f14eeee4e24e7692dfa16936c6051f3fb3f30a3464aad5ddaeca8` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:d71dc63384a2d1a9ccbfa840033d51f2006ff37bb49c2921c673ba2e3da00f28` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:204f4d39d06860e0b3d61d3ff23546c5d9e82ef0aa2ef829c3f8a612255bdf32` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:8a90b3cdf83cdf0ddd801342dfa9de3fc5036568d4e052f5334c6ca47b3a8175` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:7951f9416b5cc1a695aff3680f06573ce1ac52d185354df683cfdbda5c5a2e51` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:33ff45151baa265773582247cbe9d91529ee60888a2cdfb0de8a859b7e944470` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:af111ab74d6aa230fc1ae3a12a02592d15e6476d692beb927a2480c2033c8b60` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:a141b4bdf8c4659b8673034b87b34dd0a9db5b92993e2daa53a43a9ef375b402` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:b8c45aab1fc6181e6c20e2ce44ce3b56f455214c84d06e723873f1eaa7d37db8` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:77d34bf29812acc7deb933efef36044d638745e819ca34c195b2a83ca8472b8a` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:5c1db48989b73dd62e014886879996570d643fdb279adb9b9e5e3b3c1e207c40` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:176d7d498737532e79fdfa67a5a8cdfb7a8957f9cf5763970fbbd329c90bc9ab` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:17c95fe334d9af77142728c4bf8b16bd6ac399b57dcd9372325dd7702ea18a23` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:063a855154f438e9d4b9db49bfa62c06014135b8433e4add2db9d253483e9f3d` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:df0ea68f7f27865bff6d69e5443d7f6599cb4e6bffab89a158e8f70be15087db` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:8eecc81dd8c33aef035eebf6fc194b04434593c743fdb2741a0f04fa116c8b11` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:30faae37b6da6cd4ab8be205941828d1ec4b5f247557ad7048be4c9924227ae4` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:dc2616c0590a0848aab9e9c8ebc8e2a9618e16c7a1f807a93d9f5f6e08a3b219` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:f7c3eaa6764f14eeee4e24e7692dfa16936c6051f3fb3f30a3464aad5ddaeca8` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:34a0bf4054fa32b67637643a3f479b80e393bc8aece3ab00bd5bdc3cc5af026c` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:9c75d8e790d30a067d1eebbd604bacf8be0ddab8a1b121e9b71f7e4fd1871ec3` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:d2bb74466474b95020ef27ac13ab2978c4b4fe1d19cb41146414f38dfca8200b` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:51a841a7255f59929dbd350752437fd41a64b9fd512ffb10dbdf090b0652ab6a` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:3bf3098a83de9331a2e8dbcb5679f27fb61438e6d30a71b94d490680074196a3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:a5c163e62bec0a1d0942a3cc1e1ee9fa69810e3a443ae937b2148f65b0b957c9` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:d7ccac088cc1d6f442e6c2643b56b1f3a4116c4ecee5bb0d5b5cd3d813d08f5b` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:2de06d0d907c63f24a43fa2c28e1e12c5ab2a83003ced5b4db19f49743aa0787` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:79f9ea2fd8b58ef8177936d2819e6c1d135693c93aec5c3365d5893ef535a83e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:521a6dc55ecc831891cc7751754790b1c9e63a8019266e9955e60f7a4adbece3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:20d5b71da2a5646c6e867013d2a5a0b9994f53914d979b190ef754c5311b4ef2` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:dde5e174eddf0911801b1eb8845991d70f97df445d99c45e1002e24c80ab721c` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:3ddb6480ee510888e48cf1b9d97a62056c2d45daae10325dc890f80a58f14794` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:69f9a2300d1a4f35006ccb6ac402c798de8ff418f47b48cb69c5883e88db0853` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:34bea3c4557780e0b51ae4ceee9bf64ff156a480f01eb5b810bcffe2672d09eb` | `verification-decisions` | `verification-evidence` | `false` | + +### privacy-boundary-proof-export/context + +- branchName: `bitcode/remediation-read_privacy-boundary-proof-export_8163942d95-privacy-boundary-proof-export` +- readId: `read_privacy-boundary-proof-export_8163942d95` +- assetPackId: `asset_pack_c5fef3ab17c5` +- proofContractHash: `sha256:94214cf13298a6992d32afa5572d4359fc9c21a74ab86c4625e2b03d3a1a6d6c` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:af111ab74d6aa230fc1ae3a12a02592d15e6476d692beb927a2480c2033c8b60` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:dde5e174eddf0911801b1eb8845991d70f97df445d99c45e1002e24c80ab721c` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:62345c3c0528519a4ba2ee002df3c4e5a5c37895bfb80dcf9e20b064f6a5d6aa` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:d0a68ad68adbab5b801152274edbd5e7914f9172858603b62f2b16ba47c23c8b` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:7a5f4ed6447e7eb2a4bd65dba164f8a090ab31d9fe741a8bb78ad68fea244d5a` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:25b1de6de0319574567b9345d304adc2bbf7626fd606391213062744b1690f8f` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:94214cf13298a6992d32afa5572d4359fc9c21a74ab86c4625e2b03d3a1a6d6c` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:04ba8c7c86a5d011ed124447ba82e47b05c3eedc12dfcc68371b1da4158857b9` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:8b16f037f1078be1cef6650dac42752e414afc52f680fa3e5fd0ebd603cbc054` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:d0a68ad68adbab5b801152274edbd5e7914f9172858603b62f2b16ba47c23c8b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:c7d8fb99bff075054c3d7512abc6b7e4302655afeaf8591f8f1702c2cf50eb7e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:49f8db175b8e0b080dbf8b99c35eab571742c0cd9047e213bfc29195d006ed34` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:2e3fe016971d44f9df40986e81e57c0d8aabfd3e4d7c1fb71a8b91883a0af3a6` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:25b1de6de0319574567b9345d304adc2bbf7626fd606391213062744b1690f8f` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:49f8db175b8e0b080dbf8b99c35eab571742c0cd9047e213bfc29195d006ed34` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:d71dc63384a2d1a9ccbfa840033d51f2006ff37bb49c2921c673ba2e3da00f28` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:204f4d39d06860e0b3d61d3ff23546c5d9e82ef0aa2ef829c3f8a612255bdf32` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:8a90b3cdf83cdf0ddd801342dfa9de3fc5036568d4e052f5334c6ca47b3a8175` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:7951f9416b5cc1a695aff3680f06573ce1ac52d185354df683cfdbda5c5a2e51` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:33ff45151baa265773582247cbe9d91529ee60888a2cdfb0de8a859b7e944470` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:af111ab74d6aa230fc1ae3a12a02592d15e6476d692beb927a2480c2033c8b60` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:87776778ee2357eb269dfb6ee9978c21d4dd2d70d9c7f874b37de502e8100970` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:91b709761e65f51447f25399a5a419b27d351c985fbd05569d3d6ce1272e4015` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:b5d167c7f2d2b4b7a024fced17a93f00ef6de0764b7ac76c09fe5cf365b8dab5` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:c17f205b4e3b9a75e4bb141648d46f69b5a7ef60c06916aa26509d69a73abd87` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:176d7d498737532e79fdfa67a5a8cdfb7a8957f9cf5763970fbbd329c90bc9ab` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:17c95fe334d9af77142728c4bf8b16bd6ac399b57dcd9372325dd7702ea18a23` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:063a855154f438e9d4b9db49bfa62c06014135b8433e4add2db9d253483e9f3d` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:df0ea68f7f27865bff6d69e5443d7f6599cb4e6bffab89a158e8f70be15087db` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:8eecc81dd8c33aef035eebf6fc194b04434593c743fdb2741a0f04fa116c8b11` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:30faae37b6da6cd4ab8be205941828d1ec4b5f247557ad7048be4c9924227ae4` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:dc2616c0590a0848aab9e9c8ebc8e2a9618e16c7a1f807a93d9f5f6e08a3b219` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:49f8db175b8e0b080dbf8b99c35eab571742c0cd9047e213bfc29195d006ed34` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:fc0ecbd01376203a64dfdca51241ccab04bceee2b9577295637193cc9525537a` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:62345c3c0528519a4ba2ee002df3c4e5a5c37895bfb80dcf9e20b064f6a5d6aa` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:d2bb74466474b95020ef27ac13ab2978c4b4fe1d19cb41146414f38dfca8200b` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:51a841a7255f59929dbd350752437fd41a64b9fd512ffb10dbdf090b0652ab6a` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:3bf3098a83de9331a2e8dbcb5679f27fb61438e6d30a71b94d490680074196a3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:6a812e4e668d8ef1fc28ad2f8d8ee77da8bafdd71c54845f8d702891f283bc40` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:926c1aab017318fa8511f4790233f5658cf37dfa6455266d42aac2bb2867205e` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:712dae63457f735eb11c24d036d7a93c3e8c93ec20a7e0d686ec4391979889d3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:7a5f4ed6447e7eb2a4bd65dba164f8a090ab31d9fe741a8bb78ad68fea244d5a` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:521a6dc55ecc831891cc7751754790b1c9e63a8019266e9955e60f7a4adbece3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:20d5b71da2a5646c6e867013d2a5a0b9994f53914d979b190ef754c5311b4ef2` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:dde5e174eddf0911801b1eb8845991d70f97df445d99c45e1002e24c80ab721c` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:3ddb6480ee510888e48cf1b9d97a62056c2d45daae10325dc890f80a58f14794` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:69f9a2300d1a4f35006ccb6ac402c798de8ff418f47b48cb69c5883e88db0853` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:146250a5ba23f3b56f0bb5cb340d35685934dfcdcbf07339929f7e36c3d8f242` | `verification-decisions` | `verification-evidence` | `false` | + +### polyglot-gateway-benchmark-remediation/patch + +- branchName: `bitcode/remediation-read_polyglot-gateway-benchmark-remediation_ca6f233369-polyglot-gateway-benchmark-remediation` +- readId: `read_polyglot-gateway-benchmark-remediation_ca6f233369` +- assetPackId: `asset_pack_654da1e46737` +- proofContractHash: `sha256:22639f352c74be4b4f1c33522cbea29687fbe5455521c9aed0d64103a90f5426` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:8ab3e39c78bd87bf4c686eb3b3a3cfa9ace4af2b6a0665a2726e455b86c3b5b2` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:0a196b14d27f8f17eb9952cf2c568764983f22d2efb6411f42d9e4cb227fda48` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:c08c6baf9c335ea6d9f771efde006ff8577953196a2bab6b9acace0521350189` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:8c6a898ee8e19a41a8f8399f98c61b80362ac20513ecd53dae26950fcae6e772` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:4d5c56e3b4786a2e26d5631d1137183e88802278f9c443ecb198819c8e8dbc08` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:46424cedd179cc2e3248e7a9360316513092e0223703b917fdbaae180a9badb0` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:22639f352c74be4b4f1c33522cbea29687fbe5455521c9aed0d64103a90f5426` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:8d90f117e89ca5fd018f3ceb01de869a40618cc0676cbe6b7f7b8b60f514bb66` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:6870d6756abb2632fa4d124c1d23d46c54fd59f1f06b9a0c9bf92d9d2ad7d794` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:8c6a898ee8e19a41a8f8399f98c61b80362ac20513ecd53dae26950fcae6e772` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:49e433b9666092c67dad59625bb8fcfed68c299d2b355308b23177ec05ff8709` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:15f24a288cbf0de131137d9d96db7322a1e08fbd1a97bb987d5b63e8589693eb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:36ecea7e7c6932111c192bc6f0843164d0209d691ac3423c98c6b66d033472b4` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:46424cedd179cc2e3248e7a9360316513092e0223703b917fdbaae180a9badb0` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:15f24a288cbf0de131137d9d96db7322a1e08fbd1a97bb987d5b63e8589693eb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:1225e3488b121d9a52b359fa1aa310a6878f66c3d5723dab4efbcd895cdb2862` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:9e17674ef60968c65af2f5e1c75a4d708ef2c603bfb0773362a384feabf93efb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:f9bb5020368bc879a8463c16f39d410417d782cbad6414fe385e98e19e0a1377` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:9a947a33796d73ef1411053e0bce2b3bf269565e2d203ab6367dc6d1dacfe307` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:a334f0e7a5667f10b9c70831920b1ea755383f680661768745ee7403026d3520` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:8ab3e39c78bd87bf4c686eb3b3a3cfa9ace4af2b6a0665a2726e455b86c3b5b2` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:58c42eb9f8ba892bb071b8ad41905cf51ba215330e3659ca7039ac6583929d2b` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:1ee5dee8a724aade1fb69c47806cf2ebc8d2aa159340a5002e98068c9e493191` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:7840b9fec52f2ca8b3320cf239fe7388ee444621133bb04b0c855bfb68214bda` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:9f2b9eafe157c6224500eaa4935f6b063f46aee795639246df58765d3875bb42` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:dbb3ac97b571dbc90d9cd8482bf9535a14608b8bfcf2cd196b9facd52ba5453d` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:86fe9486c43f5878a655acd61ec83330ff8197114de70be6b5dfe3e7dff7a918` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:bba36f476eee16207d7ebdd896e4ba21836dcbda21ca4b2b0d68e8d38b7de713` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:620e667076d4e955a26712e5aa2af0e52005f6f52829183d4e45467166a92d39` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:c921d4fc1c2722ebaaa7dee8dd7b44c6db3a8dfc739ab7cf3ffafbe1e5a97d0e` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:7699508f4e5564064848f7abcf4b2efbdb1a52e400a742d4017e6b28aa57047c` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:a6d6f5e1bd226a087aae8bd89116b417f2b2b49f93abbf1f70477b20b3114e26` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:15f24a288cbf0de131137d9d96db7322a1e08fbd1a97bb987d5b63e8589693eb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:79f3761e05a1511827f8929493f3eb32dce2e1497c6a1a19b31475173631bc7c` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:c08c6baf9c335ea6d9f771efde006ff8577953196a2bab6b9acace0521350189` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:c1e577b132475f4b327b593f0ec0052f8bb6668c7efad0693bfdc79debd96f2c` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:7cd7e52ebfbe66f7b7fedc9100e7803f6823a28488837f408ce98b076987d75b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:b2cd7f6fa99d77557dee345e686958fd0d52ee5e82e4549c241e4ec91fe0fcea` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:16d764b15028c1c70d2b1b023f0007ae9082c9673a8f2d606a58b2d5c9cf313e` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:bb7194024cad19cc03abf7ef89fe672a990be8dd6a25b8e34ce3fc8830958a7e` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:623ae942a593bb129e3c864ca3d1a4975290493197f6c86cc86d69c80a45fb0e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:4d5c56e3b4786a2e26d5631d1137183e88802278f9c443ecb198819c8e8dbc08` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:70876006dc0c82da94e83a2b5faaff421960021e01454778c6c8dbbfb7d0c510` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:79392d40cf4cdce80e4ac80376150201cb9bacc5b3c4f510ade3435025af86e7` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:0a196b14d27f8f17eb9952cf2c568764983f22d2efb6411f42d9e4cb227fda48` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:6a5638b93a2bea9e4945c0be2501e582dcf4cd1b992b178c5e0fb3a8a2d8dd35` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:6f79885aedb8b5669ddafde66c9ce13eb12ffd0e3203b73ea7772f48ad183a38` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:2138225520399ad88fd2f818b3ea6e429c17a9c6769302f946d5dc3d69094f17` | `verification-decisions` | `verification-evidence` | `false` | + +### polyglot-gateway-benchmark-remediation/context + +- branchName: `bitcode/remediation-read_polyglot-gateway-benchmark-remediation_ca6f233369-polyglot-gateway-benchmark-remediation` +- readId: `read_polyglot-gateway-benchmark-remediation_ca6f233369` +- assetPackId: `asset_pack_654da1e46737` +- proofContractHash: `sha256:22639f352c74be4b4f1c33522cbea29687fbe5455521c9aed0d64103a90f5426` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:8ab3e39c78bd87bf4c686eb3b3a3cfa9ace4af2b6a0665a2726e455b86c3b5b2` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:0a196b14d27f8f17eb9952cf2c568764983f22d2efb6411f42d9e4cb227fda48` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:64713d43c3cf4ffe06599dd9a3571e5ba55636fd3a2fca591dc507c476edf424` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:8c6a898ee8e19a41a8f8399f98c61b80362ac20513ecd53dae26950fcae6e772` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:5947d74600886a598b53dd562efda22bfa373be7ce1a46fe0e0d0613660014bf` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:e47ecbea6d5fe25f3bcb908905403927e553c9c4c01063b58a2a4cf7b5e154ac` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:22639f352c74be4b4f1c33522cbea29687fbe5455521c9aed0d64103a90f5426` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:a3cbf9297ffd5abaf253fc9ab4f7ebcb5f7d21f0ae8077d66292de6c59773528` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:e3118a3a34b3348834b504893014d99748974a6498b9bb6a3ef439f294aa7e9b` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:8c6a898ee8e19a41a8f8399f98c61b80362ac20513ecd53dae26950fcae6e772` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:49e433b9666092c67dad59625bb8fcfed68c299d2b355308b23177ec05ff8709` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:f96900f0e7fee9f34ff255f1bd686f4d0332e055bb170604c4da7eaf9ff45130` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:36ecea7e7c6932111c192bc6f0843164d0209d691ac3423c98c6b66d033472b4` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:e47ecbea6d5fe25f3bcb908905403927e553c9c4c01063b58a2a4cf7b5e154ac` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:f96900f0e7fee9f34ff255f1bd686f4d0332e055bb170604c4da7eaf9ff45130` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:1225e3488b121d9a52b359fa1aa310a6878f66c3d5723dab4efbcd895cdb2862` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:9e17674ef60968c65af2f5e1c75a4d708ef2c603bfb0773362a384feabf93efb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:f9bb5020368bc879a8463c16f39d410417d782cbad6414fe385e98e19e0a1377` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:9a947a33796d73ef1411053e0bce2b3bf269565e2d203ab6367dc6d1dacfe307` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:a334f0e7a5667f10b9c70831920b1ea755383f680661768745ee7403026d3520` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:8ab3e39c78bd87bf4c686eb3b3a3cfa9ace4af2b6a0665a2726e455b86c3b5b2` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:85b9e0e294968560055014dcd2a989cad5b13bc80500d77d874aa7be4c5ac558` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:9f9acd2e42dd074bee49110bc22c450d0324e5ccb0183e3a2fcbf7cd18f6a6c7` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:7099e3048552085f0e49254ef7289bc9779aed170bdd285f0a741dada43b9da7` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:e94250d47636bfd2849803b0e765656b23dfe35be771fdee5aa556f131f76c35` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:dbb3ac97b571dbc90d9cd8482bf9535a14608b8bfcf2cd196b9facd52ba5453d` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:86fe9486c43f5878a655acd61ec83330ff8197114de70be6b5dfe3e7dff7a918` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:bba36f476eee16207d7ebdd896e4ba21836dcbda21ca4b2b0d68e8d38b7de713` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:12f98ec39b4b52000dd7c1a8cc86eb1deb8ba614dabdb5591dd02b54b8b4cb48` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:620e667076d4e955a26712e5aa2af0e52005f6f52829183d4e45467166a92d39` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:c921d4fc1c2722ebaaa7dee8dd7b44c6db3a8dfc739ab7cf3ffafbe1e5a97d0e` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:7699508f4e5564064848f7abcf4b2efbdb1a52e400a742d4017e6b28aa57047c` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:a6d6f5e1bd226a087aae8bd89116b417f2b2b49f93abbf1f70477b20b3114e26` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:f96900f0e7fee9f34ff255f1bd686f4d0332e055bb170604c4da7eaf9ff45130` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:18b721ef22d8b28c8016d53dd7a5c1eeeaccb31defb64bb52d116c98c7900d7f` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:64713d43c3cf4ffe06599dd9a3571e5ba55636fd3a2fca591dc507c476edf424` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:c1e577b132475f4b327b593f0ec0052f8bb6668c7efad0693bfdc79debd96f2c` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:7cd7e52ebfbe66f7b7fedc9100e7803f6823a28488837f408ce98b076987d75b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:b2cd7f6fa99d77557dee345e686958fd0d52ee5e82e4549c241e4ec91fe0fcea` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:8be23f5f1875a101ba6de6aa6ef5beaf82b2d5b88eb2ef06f2a6dff714a3e6bf` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:0dfd94e5a9e486386b9fb81e4973951b070993b66a3cdd7a2b8631899a569454` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:638d67a9b5409f737dc0070b57ea7070006e49afbc17020f515f5093ae37b27e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:5947d74600886a598b53dd562efda22bfa373be7ce1a46fe0e0d0613660014bf` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:70876006dc0c82da94e83a2b5faaff421960021e01454778c6c8dbbfb7d0c510` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:79392d40cf4cdce80e4ac80376150201cb9bacc5b3c4f510ade3435025af86e7` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:0a196b14d27f8f17eb9952cf2c568764983f22d2efb6411f42d9e4cb227fda48` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:6a5638b93a2bea9e4945c0be2501e582dcf4cd1b992b178c5e0fb3a8a2d8dd35` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:6f79885aedb8b5669ddafde66c9ce13eb12ffd0e3203b73ea7772f48ad183a38` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:55bf3fdfc83278bda6302e72a8aaf2f45d64ffec1c31d39d4c819461359b3183` | `verification-decisions` | `verification-evidence` | `false` | + +### auth-many-asset-normalization/patch + +- branchName: `bitcode/remediation-read_auth-many-asset-normalization_f6dbfe951c-auth-many-asset-normalization` +- readId: `read_auth-many-asset-normalization_f6dbfe951c` +- assetPackId: `asset_pack_186c76eb7d2d` +- proofContractHash: `sha256:07e9dde9b1decdd69ab9f3287b1158f89b3d3badb085d8f55489f6339b296f43` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:7021f326f42f8a44233fe094d79ada504e346a9f58b95f63ae28b60780d5d7a5` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:43d0c993cc81696809f32616c596372a95d41980c77a4477c880fe68f8463739` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:93443b0becdeebae98f5e288352518435faff73ab467b341fad0bd038eceefbc` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:9958392c28c4be80006c2bb33b353601ac820b5b635544a0ecdfb672629535e1` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:15beb995e962657b3fb02214f4afe13fbe89a111bfbfab3e1cb9715712838c6a` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:93a6ae4d4886dea6ad89f294965b4980be1e971839a80510bf75c669a86f207e` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:07e9dde9b1decdd69ab9f3287b1158f89b3d3badb085d8f55489f6339b296f43` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:c487b54c19633f825bba257c5fbc803c2411cb9826ba760fc721436fc8c1ac99` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:213eb10dd78b5eda96564d25f7f2e66519a5f2deaf3956328d370c3f53607a7b` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:9958392c28c4be80006c2bb33b353601ac820b5b635544a0ecdfb672629535e1` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:5752b43201ea449f504a9f7d64dcd38aa83c897b15be57b3e533cc1e2aad66ff` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:e74ce71b622f8a4351bf789598fb2422993e0f52d8cb57b7ec3857c841f461ec` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:59707e32027d24dc82bb1e3c6a16ceef0cd84fd3471c9fa2c37a6d090b13de7b` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:93a6ae4d4886dea6ad89f294965b4980be1e971839a80510bf75c669a86f207e` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:e74ce71b622f8a4351bf789598fb2422993e0f52d8cb57b7ec3857c841f461ec` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:4f93be105ef85bc23255edff7c639b4abf93af4b64a108d5e2c797fa5b6c935c` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:d32d2d442f872b5e5b4e1822631c6a4e55119476bd366aaa873a85b747c79aac` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:266980ddc09575e6b26a343be37671d921651aee24825537291cd68715853f53` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:f8d7a53bb5f56c87074b7b5e2aefd4e582278b9d737e1ddb647f51dc1c987f00` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:83b1f7096042f13d63d72e42e6188565208bd8e2bcacd74105a5547d9e73c7fd` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:7021f326f42f8a44233fe094d79ada504e346a9f58b95f63ae28b60780d5d7a5` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:c2c97292448cc0e0f3979d510f284cdef3f9d404cbf6b39eb639a6c6c214486d` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:f3ebf01987d5b184b19c7d02d3c196a848fa9b4eef79a99f7063d7b4794f3c27` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:d94851d00d025a78f73546c90077ee7dbbb35ada30b531745a094eea0fb9f5f0` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:d592858705dec7131279c0a523123d86107e9875111420fe703ee9172be6dda2` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:bf3148690787d7fe41f97061bdff0977f410b941b443ccaa4cc27976d18ef101` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:f7cdf9cd6177b5aa71578adffc7a985144bb3cc4343e15c66bd3a508a94643a4` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:cb6b93a204a1b42acc7c426b702bb4d317f4cae5bc4f9c297f66727d3dd795fc` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:bb8674abf94ae1d8ee5d5ed695258555f039326c2a75d3632dfd65271a06b1e1` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:ff9bb2fb885bff4335f776405fb197df7e5a3e1e7addb97b506b3f2060d200c9` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:2b167bf2a71100c16c5218af06210aad08f889af7c2ceeec5aef3a9d0c6bb38e` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:88d8d904ea7059636eddcf4ccc60796e32e48986f64743380167b007b5ac880b` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:3027b1bd2e77c3bc6dc73616bd7a4f02934389726d6ca569f5503543ada9d96d` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:e74ce71b622f8a4351bf789598fb2422993e0f52d8cb57b7ec3857c841f461ec` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:e51ecbf057c3863e2f20cea5414ee9f6f0783e4e964f671eb01c94968e805015` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:93443b0becdeebae98f5e288352518435faff73ab467b341fad0bd038eceefbc` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:3bfc16906769f2d1c0ed837a29f95a1b94589171a4aa0fed584ce85434742659` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:8e6cb9e1a5f53b05188964fc477ed3dc9cb246a3bfbaa57690cd38ad833b4dcb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:05d019692f2686ea0f5baa78bcc2c1ff4a466c28885b88332a9fb09f9fe004d3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:85562bd4e401bc83d714a4da40234b3b03e6fc34157cb4f2ba4185646febcf6f` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:e0331346702d3904ffafc0e1f0d82d7ef6c7afec8dc415f92d553729d68a02e8` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:dece620c1dd99b204862c8372a376e01fb46c9da7c988732582c2bb1ed0b7e32` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:15beb995e962657b3fb02214f4afe13fbe89a111bfbfab3e1cb9715712838c6a` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:45beb6ee9be4ba5f94fb02b8f61427db470435df7219f2cd7eee33339fc831f3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:6bbff6b551d6af59af5ded37ca778c2ecd545431b3b2c7582d70a010dbb2aef9` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:43d0c993cc81696809f32616c596372a95d41980c77a4477c880fe68f8463739` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:02b5cdc5a05c89652a579902133e8333659c9496bbc08a993b828a6a6231d952` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:8feb20c6058ca553918b5fc829b83c0bb40e5798380594dc834dbba15f7cd709` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:31d6631d4d6a64e5d54eb5d3cc90003360dd5246f023de5ad0a927e7cc1c3112` | `verification-decisions` | `verification-evidence` | `false` | + +### auth-many-asset-normalization/context + +- branchName: `bitcode/remediation-read_auth-many-asset-normalization_f6dbfe951c-auth-many-asset-normalization` +- readId: `read_auth-many-asset-normalization_f6dbfe951c` +- assetPackId: `asset_pack_186c76eb7d2d` +- proofContractHash: `sha256:07e9dde9b1decdd69ab9f3287b1158f89b3d3badb085d8f55489f6339b296f43` +- allFamiliesPassed: `true` +- proofContractPassed: `true` + +#### Family Proof Hashes + +| proofFamily | proofHash | proofArtifactPath | +| --- | --- | --- | +| `inference-synthesis` | `sha256:7021f326f42f8a44233fe094d79ada504e346a9f58b95f63ae28b60780d5d7a5` | `.bitcode/inference-synthesis-proof.json` | +| `prompt-completeness` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `.bitcode/prompt-completeness-proof.json` | +| `static-code-analysis` | `sha256:43d0c993cc81696809f32616c596372a95d41980c77a4477c880fe68f8463739` | `.bitcode/static-measurement-proof.json` | +| `verification-decisions` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `.bitcode/verification-decisions-proof.json` | +| `selection-and-materialization` | `sha256:44178db54efb33b972cd2e6cff2159b7d6c03cfc69901fa81a47ade8ef1b3e9b` | `.bitcode/selection-and-materialization-proof.json` | +| `authorization-and-sensitive-flow` | `sha256:9958392c28c4be80006c2bb33b353601ac820b5b635544a0ecdfb672629535e1` | `.bitcode/authorization-and-sensitive-flow-proof.json` | +| `settlement-source-to-shares` | `sha256:03b769f4dd08d73838c93f2c639f3e98e7b7f65efe6b7b09f15b264d653f5df2` | `.bitcode/settlement-source-to-shares-proof.json` | +| `disclosure-boundary` | `sha256:d4ecd4fa6a549fec13e5514cc6960b24afaaf385e312f2c6ae3c2280e5417584` | `.bitcode/disclosure-boundary-proof.json` | +| `proof-contract` | `sha256:07e9dde9b1decdd69ab9f3287b1158f89b3d3badb085d8f55489f6339b296f43` | `.bitcode/proof-contract.json` | + +#### Proof Artifact Disclosure Classification + +| path | sensitiveDataClass | disclosable | assetPackEvidenceConfidentiality | potentiallyDisclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/identity-authorization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/proof-witness-manifest.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `licensed-source-material` | `false` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `settlement-preview` | `false` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `bounded-public-proof-metadata` | `true` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/system-proof-bundle.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-decisions-proof.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `private-proof-artifact` | `false` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `verification-evidence` | `false` | `verification-evidence` | `false` | + +#### Witness Artifact Digest Inventory + +| path | digest | proofFamilies | sensitiveDataClass | disclosable | +| --- | --- | --- | --- | --- | +| `.bitcode/accounting-precision-report.json` | `sha256:9c0f5287e2cc4af88889d02d72d1d34a127745dfbfc02c47d59bd55a37478e11` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/asset-pack.lock.json` | `sha256:967d39cbb5233e24d1e4ced45f3ad715d396afc47ea21cc06f0eee81df1996d2` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:9958392c28c4be80006c2bb33b353601ac820b5b635544a0ecdfb672629535e1` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:5752b43201ea449f504a9f7d64dcd38aa83c897b15be57b3e533cc1e2aad66ff` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/bounded-public-proof.json` | `sha256:faa5bed0f9cd0e812aee5a69e3f21ac975f21e29e57eca1200f53636b2d20093` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/code-analysis-fact-registry.json` | `sha256:59707e32027d24dc82bb1e3c6a16ceef0cd84fd3471c9fa2c37a6d090b13de7b` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/disclosure-boundary-proof.json` | `sha256:d4ecd4fa6a549fec13e5514cc6960b24afaaf385e312f2c6ae3c2280e5417584` | `disclosure-boundary` | `private-proof-artifact` | `false` | +| `.bitcode/disclosure-proof.json` | `sha256:faa5bed0f9cd0e812aee5a69e3f21ac975f21e29e57eca1200f53636b2d20093` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/eval-manifest.json` | `sha256:4f93be105ef85bc23255edff7c639b4abf93af4b64a108d5e2c797fa5b6c935c` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/external-boundary-manifest.json` | `sha256:44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a` | `bitcoin-settlement-interface` | `private-proof-artifact` | `false` | +| `.bitcode/identity-authorization-proof.json` | `sha256:d32d2d442f872b5e5b4e1822631c6a4e55119476bd366aaa873a85b747c79aac` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/identity-bindings.json` | `sha256:266980ddc09575e6b26a343be37671d921651aee24825537291cd68715853f53` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/inference-moment-contracts.json` | `sha256:f8d7a53bb5f56c87074b7b5e2aefd4e582278b9d737e1ddb647f51dc1c987f00` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-proofs.json` | `sha256:83b1f7096042f13d63d72e42e6188565208bd8e2bcacd74105a5547d9e73c7fd` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/inference-synthesis-proof.json` | `sha256:7021f326f42f8a44233fe094d79ada504e346a9f58b95f63ae28b60780d5d7a5` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/journal-completeness-proof.json` | `sha256:4b7ef245c2ccfe1cfaeaab022153ec9c9b8f99b617f4bb2a9a1d551db2de5c55` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/journal-diff.json` | `sha256:25862851c298858a3f7cb68e4d49383ffe6d6c03afd4a0d18f9a048ceaf6be9c` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-exclusions.json` | `sha256:b0c51aa9b75ae8f2f042d7d75121acda8a74d3a34fffd3c21bae43059440047a` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/materialization-proof.json` | `sha256:aae1b1470954e15061ea1345cd1d5074e8d598f923ad0ee31bcb188a03e76ec2` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/materialization-visibility-proof.json` | `sha256:bf3148690787d7fe41f97061bdff0977f410b941b443ccaa4cc27976d18ef101` | `selection-and-materialization` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/measurement-receipts.json` | `sha256:f7cdf9cd6177b5aa71578adffc7a985144bb3cc4343e15c66bd3a508a94643a4` | `static-code-analysis` | `private-proof-artifact` | `false` | +| `.bitcode/parsed-completion-envelopes.json` | `sha256:cb6b93a204a1b42acc7c426b702bb4d317f4cae5bc4f9c297f66727d3dd795fc` | `inference-synthesis`, `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/projection-policy.json` | `sha256:bb8674abf94ae1d8ee5d5ed695258555f039326c2a75d3632dfd65271a06b1e1` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-completeness-proof.json` | `sha256:9746305d06e0b55e0d7fe59a9ebddcd8d321d4de6e9c26b067aaa74e4842b018` | `prompt-completeness` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/prompt-contracts.json` | `sha256:ff9bb2fb885bff4335f776405fb197df7e5a3e1e7addb97b506b3f2060d200c9` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-family-registry.json` | `sha256:ab753a9f2a8152aff00bb63282d32a3cd518e38ab37d28372237ea049242cf59` | `prompt-completeness` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-implementation-surface.json` | `sha256:2b167bf2a71100c16c5218af06210aad08f889af7c2ceeec5aef3a9d0c6bb38e` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/prompt-surfaces.json` | `sha256:88d8d904ea7059636eddcf4ccc60796e32e48986f64743380167b007b5ac880b` | `inference-synthesis` | `private-proof-artifact` | `false` | +| `.bitcode/proof-contract.json` | `sha256:3027b1bd2e77c3bc6dc73616bd7a4f02934389726d6ca569f5503543ada9d96d` | `proof-contract` | `private-proof-artifact` | `false` | +| `.bitcode/redaction-proof.json` | `sha256:faa5bed0f9cd0e812aee5a69e3f21ac975f21e29e57eca1200f53636b2d20093` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/selected-source-material.json` | `sha256:1de88ee5d506a61af4e096e89edb43a83742b3f8b69bbac2066d4c7820d027b9` | `selection-and-materialization` | `licensed-source-material` | `false` | +| `.bitcode/selection-and-materialization-proof.json` | `sha256:44178db54efb33b972cd2e6cff2159b7d6c03cfc69901fa81a47ade8ef1b3e9b` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/selection-consistency-proof.json` | `sha256:3bfc16906769f2d1c0ed837a29f95a1b94589171a4aa0fed584ce85434742659` | `selection-and-materialization` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow-proof.json` | `sha256:8e6cb9e1a5f53b05188964fc477ed3dc9cb246a3bfbaa57690cd38ad833b4dcb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:05d019692f2686ea0f5baa78bcc2c1ff4a466c28885b88332a9fb09f9fe004d3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-participation.json` | `sha256:b23dd79a34d7fb37ff0884e0d475413c5760303d27525501c00069415a280588` | `settlement-source-to-shares` | `settlement-preview` | `false` | +| `.bitcode/settlement-preview.json` | `sha256:a9f661b49799f2c6bf9a3460452a72681d8bf9c899de68b97f1cff085b355f3d` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | +| `.bitcode/settlement-proof.json` | `sha256:afa5aa92da369956610e7ffd1a0e01aa7bba9732775d56a65f4cdfcef41e1ce9` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/settlement-source-to-shares-proof.json` | `sha256:03b769f4dd08d73838c93f2c639f3e98e7b7f65efe6b7b09f15b264d653f5df2` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/source-to-shares.json` | `sha256:45beb6ee9be4ba5f94fb02b8f61427db470435df7219f2cd7eee33339fc831f3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | +| `.bitcode/static-heuristics-registry.json` | `sha256:6bbff6b551d6af59af5ded37ca778c2ecd545431b3b2c7582d70a010dbb2aef9` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-proof.json` | `sha256:43d0c993cc81696809f32616c596372a95d41980c77a4477c880fe68f8463739` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/static-measurement-report.json` | `sha256:02b5cdc5a05c89652a579902133e8333659c9496bbc08a993b828a6a6231d952` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | +| `.bitcode/verification-decisions-proof.json` | `sha256:608f4210eb9b498b765f65b1d7a8c67edddf9bc3d5ff1fd6a0c7c3aeb7c5859f` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-receipts.json` | `sha256:8feb20c6058ca553918b5fc829b83c0bb40e5798380594dc834dbba15f7cd709` | `verification-decisions` | `private-proof-artifact` | `false` | +| `.bitcode/verification-report.json` | `sha256:3921d3aadbc23183b573cb647d26b09177c5f7a3b1dcd049c056e666b62f9f07` | `verification-decisions` | `verification-evidence` | `false` | diff --git a/BITCODE_V30_QA.md b/BITCODE_V30_QA.md new file mode 100644 index 000000000..b38cced16 --- /dev/null +++ b/BITCODE_V30_QA.md @@ -0,0 +1,44 @@ +# Bitcode V30 QA Ledger + +## Status + +- Version: `V30` +- Current canonical/latest target: `V29` +- Draft target: `V30` +- Purpose: source-safe QA ledger for V30 Protocol/BTD hardening and promotion readiness. + +## Gate 10 Promotion Readiness QA + +V30 Gate 10 closes when the version branch can be promoted without operator memory: + +- every V30 gate checker is wired into the gate workflow and the V30 promotion workflow; +- `promote-bitcode-canon.mjs` accepts `--version V30`, plans every V30 proof command, rewrites `BITCODE_SPEC.txt` only at the generation boundary, and produces the V30 generated appendix; +- generated `.bitcode/v30-*` artifacts exist for spec-family shape, canonical inputs, canon-posture drift, and Protocol telemetry/proof hooks; +- `BITCODE_SPEC_V30_PROVEN.md` is generated by the promotion command and regenerated by the promotion workflow; +- local proof includes Protocol package typecheck/tests, BTD typecheck/tests, pipeline package checks, UAPI route/Terminal tests, browser cockpit proof, pipeline readback, and protocol demonstration QA; +- staging-testnet evidence remains source-safe and names only readiness/readback posture, not secrets or protected source; +- post-promotion runtime posture is V30 active with V31 as the next draft target. + +## Source-Safe Staging Evidence + +V30 promotion does not commit environment values, service credentials, private keys, protected AssetPack source, or live customer data. +Staging-testnet validation evidence for Gate 10 is admissible when it records: + +- environment lane readiness without secret values; +- Terminal transaction cockpit readback over source-safe rows; +- ledger/database/object-storage reconciliation posture; +- protocol package generated-artifact posture; +- promotion dry-run command plan and local proof status. + +## Local Proof Commands + +The local Gate 10 proof surface is: + +```bash +pnpm run check:v30-gate10 +node scripts/promote-bitcode-canon.mjs --version V30 --commit HEAD --dry-run +node scripts/generate-bitcode-proven.mjs --version V30 --commit HEAD --worktree-state dirty-preview --output BITCODE_SPEC_V30_PROVEN.md --allow-dirty +node scripts/generate-bitcode-proven.mjs --version V30 --commit HEAD --worktree-state dirty-preview --output BITCODE_SPEC_V30_PROVEN.md --check --allow-dirty +``` + +Promotion workflow validation repeats this proof from a clean `version/v30` branch and commits the clean generated canon artifacts. diff --git a/README.md b/README.md index 235a12f5e..31a6d8aea 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,11 @@ Protocol/BTD hardening proof posture, generate `BITCODE_SPEC_V30_PROVEN.md`, and commit promotion artifacts plus the `BITCODE_SPEC.txt` pointer change from `V29` to `V30` on the version branch. Gate 10 is the local/staging promotion-readiness gate; run the V30 Gate 10 -checker before opening the final gate PR. V30 Gate 1 wires the first checker as -`pnpm run check:v30-gate1`. V30 Gate 2 wires the Protocol/BTD package boundary -checker as `pnpm run check:v30-gate2`; shared BTD objects consumed by API, +checker with `pnpm run check:v30-gate10` before opening the final gate PR. +The V30 version-promotion workflow is +[v30-canon-promotion.yml](.github/workflows/v30-canon-promotion.yml). V30 Gate 1 +wires the first checker as `pnpm run check:v30-gate1`. V30 Gate 2 wires the +Protocol/BTD package boundary checker as `pnpm run check:v30-gate2`; shared BTD objects consumed by API, Terminal, MCP, ChatGPT App, Auxillaries, or Exchange must be built, parsed, validated, and JSON-serialized by package owners before route or interface code uses them. diff --git a/SPECIFICATIONS_ROADMAP.md b/SPECIFICATIONS_ROADMAP.md index 0444ffb8f..1c46ac423 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -5,6 +5,7 @@ - Current active canonical pointer: `BITCODE_SPEC.txt` -> `V29` - Current active canon: `BITCODE_SPEC_V29.md` - Current draft target: `BITCODE_SPEC_V30.md` +- Current working gate: V30 Gate 10 promotion readiness, which prepares V30 generated artifacts, promotion workflow, and post-promotion V30 active / V31 draft posture. - Purpose: concise running index of Bitcode/ENGI specification history, current work, and planned work. This roadmap is not an active system specification. @@ -55,7 +56,7 @@ They are referenced here for specification history only; active implementation w | V28 | `BITCODE_SPEC_V28.md` | promoted historical Bitcode canon | Commercial Protocol implementation and Terminal MVP: Depositing, Read Request, Read-Need Comprehension, Finding Fits, source-safe AssetPack preview, settlement posture, BTD range/read-right state, PR delivery, streaming pipeline telemetry, staging-testnet harnesses, MCP/ChatGPT App MVP, demonstration boundary cleanup, and unversioned route discipline. | | V29 | `BITCODE_SPEC_V29.md` | active canon | Deeper Terminal transaction cockpit: route-owned transaction state, Wallet/BTC operation depth, Reading pipeline observability, AssetPack disclosure rights, settlement reconciliation/repair, organization permission authority, browser-proven Terminal UX, local/staging promotion readiness, and V29 canonical promotion. | | V30 | `BITCODE_SPEC_V30.md` | active draft target | Protocol/BTD hardening after V28/V29: package API boundaries, Bitcoin/Taproot/PSBT rigor, BTD-AssetPack mint/read/right-transfer receipts, testnet ledger/database/object-storage projection hardening, source-to-shares proof cleanup, bridge-readiness research boundaries, Protocol/BTD telemetry/proof hooks, interface regression proof, and V30 promotion readiness. Exchange is not V30. | -| V31 | `BITCODE_SPEC_V31_NOTES.md` | future notes | Deeper Auxillaries after Protocol/BTD rails stabilize: profile, connects, interfaces, BTD panes, provider readiness, account state, team/org/wallet/multi-sig/role/policy controls, readiness diagnostics, recovery flows, responsive/accessibility QA, and Auxillaries-specific tests/proofs. | +| V31 | `BITCODE_SPEC_V31_NOTES.md` | next draft notes after V30 promotion | Deeper Auxillaries after Protocol/BTD rails stabilize: profile, connects, interfaces, BTD panes, provider readiness, account state, team/org/wallet/multi-sig/role/policy controls, readiness diagnostics, recovery flows, responsive/accessibility QA, and Auxillaries-specific tests/proofs. V31 Gate 1 must open the full V31 SPEC/DELTA/PARITY family from these notes. | | V32 | `BITCODE_SPEC_V32_NOTES.md` | future notes | Deeper provation and testing over stable Terminal and Protocol/BTD rails: proof-family replay across Terminal, Exchange placeholders, Auxillaries, BTD registry, and protocol-demonstration; E2E/failure-state breadth, regression suites, promotion-proof generation hardening, scenario expansion, visual/accessibility/responsive tests, and testnet/mainnet-readiness rehearsal. | | V33 | `BITCODE_SPEC_V33_NOTES.md` | future notes | Deeper Interfaces beyond the V28 MVP: mature MCP API, ChatGPT App, API packaging, schemas, examples, contract tests, interface auth, policy checks, fail-closed read/license behavior, and commercial non-Auxillaries non-website application interfaces using package-owned Protocol/BTD objects. | | V34 | `BITCODE_SPEC_V34_NOTES.md` | future notes | Deeper Deployment: host capabilities, real executions, distributed compute aligned with provations, runtime/storage expectations, ledger/database/object-storage/proof-artifact posture, CI/CD for canonical promotions, environment lanes, deployment approvals, rollback, upgrades, secret rotation, and repair playbooks. | diff --git a/package.json b/package.json index 8bb9bfddd..b945e74b6 100644 --- a/package.json +++ b/package.json @@ -63,6 +63,7 @@ "check:v30-gate7": "node scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs", "check:v30-gate8": "node scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs", "check:v30-gate9": "node scripts/check-v30-gate9-interface-integration-regression-proof.mjs", + "check:v30-gate10": "node scripts/check-v30-gate10-promotion-readiness.mjs", "check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic", "check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title", "check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24", diff --git a/packages/protocol/README.md b/packages/protocol/README.md index 40d84ff19..b1ce61b71 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -26,6 +26,9 @@ V29 Gate 10. V30 Gate 1 treats this package as promotion-critical runtime posture. `packages/protocol/src/canon-posture.js` and `packages/protocol/data/state.json` must remain aligned to `V29` active, `V30` draft until V30 promotion. +V30 Gate 10 promotes this package posture by rewriting those same runtime +carriers to `V30` active, `V31` draft and regenerating the V30 generated +appendix plus `.bitcode/v30-*` promotion artifacts. The package boundary is enforced by `packages/protocol` tests, the UAPI commercial protocol boundary test, and V30 gate checks. diff --git a/packages/protocol/src/canonical/proven-generator.js b/packages/protocol/src/canonical/proven-generator.js index ddafabe1e..5712de336 100644 --- a/packages/protocol/src/canonical/proven-generator.js +++ b/packages/protocol/src/canonical/proven-generator.js @@ -23,6 +23,8 @@ import { buildV21SpecFamilyReport } from './v21-specifying.js'; import { + buildCanonPostureDriftReport, + buildCanonPostureGeneratedArtifactContents, buildV25CanonPostureDriftReport, buildV24CanonPostureDriftReport, buildV23CanonPostureDriftReport, @@ -8116,6 +8118,204 @@ function buildV26ProvenPackage(baseData, { }; } +/** + * @param {{ + * generatedAt: string, + * baseData: ReturnType + * }} input + */ +function buildV30ProtocolTelemetryProofHooks({ generatedAt, baseData }) { + const requiredFiles = [ + 'packages/btd/src/telemetry.ts', + 'packages/btd/src/api-boundaries.ts', + 'packages/btd/__tests__/telemetry.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'uapi/app/api/btd/protocol-telemetry/route.ts', + 'packages/btd/README.md', + 'uapi/app/terminal/README.md', + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md' + ]; + const telemetryPrimitiveTokens = [ + 'BtdProtocolTelemetryEnvelope', + 'BtdProtocolTelemetryRecord', + 'BtdProtocolProofHook', + 'buildBtdProtocolTelemetryEnvelope', + 'buildBtdProtocolProofHook', + 'sourceSafety', + 'containsProtectedSource: false', + ]; + const failures = []; + const checkedFiles = []; + /** @type {Record} */ + const sourceByPath = {}; + for (const relativePath of requiredFiles) { + const absolutePath = path.join(REPO_ROOT, relativePath); + if (!existsSync(absolutePath)) { + failures.push(`missing required telemetry proof-hook source ${relativePath}`); + continue; + } + checkedFiles.push(relativePath); + const content = readFileSync(absolutePath, 'utf8'); + sourceByPath[relativePath] = content; + for (const token of telemetryPrimitiveTokens) { + if (!content.includes(token) && relativePath === 'packages/btd/src/telemetry.ts') { + failures.push(`telemetry primitive is missing ${token}`); + } + } + } + const routeContent = sourceByPath['packages/api/src/routes/btd-crypto.ts'] || ''; + const nextRouteContent = sourceByPath['uapi/app/api/btd/protocol-telemetry/route.ts'] || ''; + const testContent = sourceByPath['packages/btd/__tests__/telemetry.test.ts'] || ''; + const specContent = sourceByPath['BITCODE_SPEC_V30.md'] || ''; + const routeReady = routeContent.includes('buildPostBtdProtocolTelemetryRoute') + && routeContent.includes('postBtdProtocolTelemetry') + && nextRouteContent.includes('postBtdProtocolTelemetry'); + const testsReady = [ + 'receipts, fees, projections, shares, and bridges', + 'secret-looking or protected-source telemetry metadata', + 'replayable theorem and witness facts' + ].every((token) => testContent.includes(token)); + const specReady = specContent.includes('Gate 8 Protocol telemetry proof hooks') + && specContent.includes('BtdProtocolTelemetryEnvelope'); + if (!routeReady) failures.push('Protocol telemetry API route is not wired.'); + if (!testsReady) failures.push('Protocol telemetry tests do not cover source safety and proof-hook replay.'); + if (!specReady) failures.push('V30 spec does not bind Protocol telemetry proof hooks.'); + + return { + reportId: 'v30-protocol-telemetry-proof-hooks', + version: 'V30', + proofSourceCommit: baseData.canonicalCommit, + generatedAt, + generatorId: baseData.generatorId, + worktreeState: baseData.worktreeState, + passed: failures.length === 0, + sourceSafe: true, + checkedFileCount: checkedFiles.length, + checkedFiles, + requiredTelemetryFamilies: [ + 'btd_receipt', + 'btc_fee_state', + 'ledger_projection', + 'source_to_shares_proof', + 'bridge_readiness_posture' + ], + proofHookCoverage: [ + 'theorem ids', + 'replay step ids', + 'witness artifact paths', + 'generated artifact paths', + 'evidence roots', + 'telemetry roots' + ], + compatibleWith: ['V32', 'V35'], + failures + }; +} + +/** + * @param {any} baseData + * @param {{ + * generatedAt: string, + * inheritedV19: any, + * inheritedV20: any + * }} input + */ +function buildV30ProvenPackage(baseData, { + generatedAt, + inheritedV19, + inheritedV20 +}) { + const draftPreview = ACTIVE_CANON_VERSION !== 'V30'; + const specFamilyReport = buildV21SpecFamilyReport({ + version: 'V30', + mode: draftPreview ? 'draft' : 'promoted', + ...(draftPreview ? { currentTarget: ACTIVE_CANON_VERSION } : { currentTarget: 'V30' }) + }); + const assumedArtifactPaths = [ + 'BITCODE_SPEC_V30_PROVEN.md', + '.bitcode/v30-spec-family-report.json', + '.bitcode/v30-canonical-input-report.json', + '.bitcode/v30-canon-posture-drift-report.json', + '.bitcode/v30-protocol-telemetry-proof-hooks.json' + ]; + const canonicalInputReport = buildV21CanonicalInputReport({ + currentTarget: 'V30', + reportVersion: 'V30', + ...(draftPreview + ? { + skipPointerCheck: true, + assumeExistingRelativePaths: assumedArtifactPaths + } + : { assumeExistingRelativePaths: assumedArtifactPaths }) + }); + const canonPostureDriftReport = buildCanonPostureDriftReport({ + version: 'V30', + activeCanonVersion: 'V30', + draftTargetVersion: 'V31', + proofSourceCommit: baseData.canonicalCommit, + generatedAt, + generatorId: baseData.generatorId, + worktreeState: baseData.worktreeState + }); + const protocolTelemetryProofHooks = buildV30ProtocolTelemetryProofHooks({ + generatedAt, + baseData + }); + const artifacts = { + ...buildCanonPostureGeneratedArtifactContents({ + version: 'V30', + proofSourceCommit: baseData.canonicalCommit, + generatedAt, + generatorId: baseData.generatorId, + worktreeState: baseData.worktreeState, + specFamilyReport, + canonicalInputReport, + canonPostureDriftReport + }), + '.bitcode/v30-protocol-telemetry-proof-hooks.json': `${JSON.stringify(protocolTelemetryProofHooks, null, 2)}\n` + }; + const artifactSummaries = summarizeArtifactContents(artifacts); + const promotionReady = specFamilyReport.passed === true + && canonicalInputReport.passed === true + && canonPostureDriftReport.passed === true + && protocolTelemetryProofHooks.passed === true; + const data = { + ...baseData, + v19: inheritedV19, + v20: inheritedV20, + v30: { + specFamilyReport, + canonicalInputReport, + canonPostureDriftReport, + protocolTelemetryProofHooks, + artifactSummaries, + draftPreview, + promotionReady, + activeCanonicalTarget: ACTIVE_CANON_VERSION, + nextDraftTarget: 'V31' + }, + aggregate: { + ...baseData.aggregate, + fullyProven: baseData.aggregate.fullyProven + && inheritedV19?.deterministicReplayReport?.passed === true + && inheritedV19?.volatilityInventory?.passed === true + && inheritedV19?.contractChangeLedger?.passed === true + && inheritedV20?.qualitySummary?.passed === true + && promotionReady + && specFamilyReport.mode === 'promoted' + } + }; + return { + data, + markdown: renderCanonicalProvenMarkdown(data), + artifacts + }; +} + /** * @param {{ * version: string, @@ -8532,6 +8732,58 @@ export function generateCanonicalProvenMarkdown({ finishGenerateProfile(); return v26Package; } + if (version === 'V30') { + const inheritedV19BaseData = buildBaseCanonicalProvenData({ + version: 'V19', + canonicalCommit, + canonicalCommitRecordedAt, + generatedAt, + worktreeState, + generatorId, + branchModes, + buildInitialStateFn, + runMakeBitcodeBranchFn, + ...(scenarioIds ? { scenarioIds } : {}) + }); + const inheritedV19Package = buildV19DeterministicProvenPackage(inheritedV19BaseData, { + version: 'V19', + canonicalCommit, + canonicalCommitRecordedAt, + generatedAt, + worktreeState, + generatorId, + branchModes, + buildInitialStateFn, + runMakeBitcodeBranchFn, + renderMarkdown: false, + ...(scenarioIds ? { scenarioIds } : {}) + }); + const inheritedV20BaseData = buildBaseCanonicalProvenData({ + version: 'V20', + canonicalCommit, + canonicalCommitRecordedAt, + generatedAt, + worktreeState, + generatorId, + branchModes, + buildInitialStateFn, + runMakeBitcodeBranchFn, + ...(scenarioIds ? { scenarioIds } : {}) + }); + const inheritedV20Package = buildV20ProvenPackage(inheritedV20BaseData, { + version: 'V20', + generatedAt, + inheritedV19: inheritedV19Package.data.v19, + renderMarkdown: false + }); + const v30Package = buildV30ProvenPackage(baseData, { + generatedAt, + inheritedV19: inheritedV19Package.data.v19, + inheritedV20: inheritedV20Package.data.v20 + }); + finishGenerateProfile(); + return v30Package; + } const v18Matrices = version === 'V18' ? buildV18Matrices(baseData, { version, diff --git a/packages/protocol/src/canonical/v21-specifying.js b/packages/protocol/src/canonical/v21-specifying.js index 80878fbd3..62f29ddf0 100644 --- a/packages/protocol/src/canonical/v21-specifying.js +++ b/packages/protocol/src/canonical/v21-specifying.js @@ -331,6 +331,12 @@ function buildV21LikeProfile(version) { requiredGeneratedArtifactPaths: [ `.bitcode/${versionLower}-spec-family-report.json`, `.bitcode/${versionLower}-canonical-input-report.json`, + ...(version === 'V30' + ? [ + '.bitcode/v30-canon-posture-drift-report.json', + '.bitcode/v30-protocol-telemetry-proof-hooks.json' + ] + : []), ...(version === 'V26' ? [ '.bitcode/terminal-composition-proof.json', @@ -1399,6 +1405,9 @@ function buildRequiredCanonicalArtifacts(repoRoot, currentTarget) { if (currentTarget === 'V26') { artifacts.push(...buildV21LikeProfile('V26').requiredGeneratedArtifactPaths); } + if (currentTarget === 'V30') { + artifacts.push(...buildV21LikeProfile('V30').requiredGeneratedArtifactPaths); + } return artifacts.map((relativePath) => path.join(repoRoot, relativePath)); } diff --git a/scripts/check-v30-gate10-promotion-readiness.mjs b/scripts/check-v30-gate10-promotion-readiness.mjs new file mode 100644 index 000000000..06671bfb2 --- /dev/null +++ b/scripts/check-v30-gate10-promotion-readiness.mjs @@ -0,0 +1,292 @@ +#!/usr/bin/env node + +import { execFileSync } from 'node:child_process'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function fileExists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + promotionMode: false, + skipBranchCheck: false, + repoRoot, + }; + + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--promotion-mode') args.promotionMode = true; + else if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v30-gate10-promotion-readiness.mjs [--promotion-mode] [--skip-branch-check] [--repo-root ]', + '', + 'Checks V30 Gate 10 generated artifacts, promotion workflow, local/staging proof posture, and post-promotion V30/V31 readiness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function assertJsonArtifact(failures, root, relativePath, requiredStrings) { + assertCheck(failures, fileExists(root, relativePath), `Missing generated V30 artifact: ${relativePath}`); + if (!fileExists(root, relativePath)) return; + + const content = read(root, relativePath); + try { + JSON.parse(content); + } catch (error) { + failures.push(`${relativePath} must be valid JSON: ${error instanceof Error ? error.message : String(error)}`); + return; + } + + for (const requiredString of requiredStrings) { + assertCheck(failures, content.includes(requiredString), `${relativePath} must include ${requiredString}.`); + } + + const forbiddenSecretShapes = [ + ['sb', 'secret__'].join('_'), + ['sk', 'proj'].join('-'), + ['bitcode', 'database', 'password'].join(''), + ]; + for (const forbidden of forbiddenSecretShapes) { + assertCheck(failures, !content.includes(forbidden), `${relativePath} must not contain secret-shaped value ${forbidden}.`); + } +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck( + failures, + args.promotionMode ? ['V29', 'V30'].includes(pointer) : pointer === 'V29', + args.promotionMode + ? `BITCODE_SPEC.txt must be V29 before V30 promotion or V30 after promotion. Observed ${pointer || 'empty'}.` + : `BITCODE_SPEC.txt must remain V29 during V30 Gate 10 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v30' || /^v30\/gate-10-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V30 Gate 10 work must occur on version/v30 or v30/gate-10-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V30.md', + 'BITCODE_SPEC_V30_DELTA.md', + 'BITCODE_SPEC_V30_NOTES.md', + 'BITCODE_SPEC_V30_PARITY_MATRIX.md', + 'BITCODE_V30_QA.md', + 'scripts/check-v30-gate10-promotion-readiness.mjs', + 'scripts/promote-bitcode-canon.mjs', + 'scripts/prepare-bitcode-spec-family-promotion.mjs', + 'scripts/prepare-bitcode-runtime-canon-promotion.mjs', + 'scripts/generate-bitcode-proven.mjs', + '.github/workflows/bitcode-gate-quality.yml', + '.github/workflows/bitcode-canon-quality.yml', + '.github/workflows/v30-canon-promotion.yml', + 'packages/protocol/src/canon-posture.js', + 'packages/protocol/data/state.json', + 'packages/protocol/README.md', + 'packages/protocol/src/canonical/proven-generator.js', + 'packages/protocol/src/canonical/v21-specifying.js', + 'protocol-demonstration/src/canon-posture.js', + 'protocol-demonstration/README.md', + 'package.json', + 'README.md', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 10 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V30.md'); + const delta = read(root, 'BITCODE_SPEC_V30_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V30_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V30_PARITY_MATRIX.md'); + const qa = read(root, 'BITCODE_V30_QA.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + const canonWorkflow = read(root, '.github/workflows/bitcode-canon-quality.yml'); + const promotionWorkflow = read(root, '.github/workflows/v30-canon-promotion.yml'); + const promoteScript = read(root, 'scripts/promote-bitcode-canon.mjs'); + const prepareSpecScript = read(root, 'scripts/prepare-bitcode-spec-family-promotion.mjs'); + const prepareRuntimeScript = read(root, 'scripts/prepare-bitcode-runtime-canon-promotion.mjs'); + const provenGenerator = read(root, 'packages/protocol/src/canonical/proven-generator.js'); + const v21Specifying = read(root, 'packages/protocol/src/canonical/v21-specifying.js'); + const packageCanonPosture = read(root, 'packages/protocol/src/canon-posture.js'); + const packageState = read(root, 'packages/protocol/data/state.json'); + const protocolReadme = read(root, 'packages/protocol/README.md'); + const rootReadme = read(root, 'README.md'); + + assertCheck(failures, spec.includes('V30 local and staging promotion readiness canon'), 'V30 SPEC must define local/staging promotion readiness canon.'); + assertCheck(failures, delta.includes('Gate 10: V30 Promotion Readiness') && delta.includes('Closure acceptance'), 'V30 DELTA must define Gate 10 closure acceptance.'); + assertCheck(failures, notes.includes('Gate 10 promotion-readiness notes') && notes.includes('staging-testnet readback'), 'V30 NOTES must carry Gate 10 promotion-readiness notes.'); + assertCheck(failures, parity.includes('## Gate 10 Parity') && parity.includes('Gate 10 completion condition'), 'V30 PARITY must include Gate 10 parity and completion condition.'); + assertCheck(failures, qa.includes('Bitcode V30 QA Ledger') && qa.includes('Gate 10 Promotion Readiness QA'), 'V30 QA ledger must record Gate 10 promotion readiness.'); + + assertCheck( + failures, + packageJson.includes('"check:v30-gate10"') && gateWorkflow.includes('check-v30-gate10-promotion-readiness.mjs'), + 'package.json and gate-quality workflow must run the Gate 10 checker.', + ); + assertCheck( + failures, + gateWorkflow.includes('if [ "$POINTER" = "V29" ]') && + gateWorkflow.includes('elif [ "$POINTER" = "V30" ]') && + gateWorkflow.includes('--version V30 --mode promoted') && + gateWorkflow.includes('check-v30-gate10-promotion-readiness.mjs --promotion-mode --skip-branch-check'), + 'Gate-quality workflow must tolerate both V29-draft and V30-promoted branch states.', + ); + assertCheck( + failures, + canonWorkflow.includes('elif [ "$POINTER" = "V30" ]') && + canonWorkflow.includes('--active-canon V30 --draft-target V31'), + 'Canon-quality workflow must validate V30/V31 promoted posture.', + ); + assertCheck( + failures, + promotionWorkflow.includes("head.ref == 'version/v30'") && + promotionWorkflow.includes('npm run promote:canon -- --version V30') && + promotionWorkflow.includes('BITCODE_SPEC_V30_PROVEN.md') && + promotionWorkflow.includes('.bitcode') && + promotionWorkflow.includes('Promote V30 canon files'), + 'V30 promotion workflow must validate version/v30 and commit V30 promotion artifacts.', + ); + + for (const gateCheck of [ + 'check-v30-gate1-roadmap-and-gating.mjs', + 'check-v30-gate2-protocol-package-api-boundaries.mjs', + 'check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs', + 'check-v30-gate4-btd-assetpack-mint-read-receipts.mjs', + 'check-v30-gate5-testnet-ledger-projection-hardening.mjs', + 'check-v30-gate6-source-to-shares-proof-cleanup.mjs', + 'check-v30-gate7-bridge-readiness-research-boundaries.mjs', + 'check-v30-gate8-protocol-telemetry-proof-hooks.mjs', + 'check-v30-gate9-interface-integration-regression-proof.mjs', + 'check-v30-gate10-promotion-readiness.mjs', + ]) { + assertCheck(failures, promoteScript.includes(gateCheck), `Promotion script must run ${gateCheck}.`); + assertCheck(failures, promotionWorkflow.includes(gateCheck), `V30 promotion workflow must run ${gateCheck}.`); + } + + assertCheck( + failures, + promoteScript.includes("const v30DraftSpecCheckCommand") && + promoteScript.includes("const v30Gate10Command") && + promoteScript.includes("if (version === 'V30')") && + promoteScript.includes('buildDerivedV30CommitMessageBody') && + promoteScript.includes("scripts/check-v30-gate10-promotion-readiness.mjs"), + 'Canonical promotion script must support V30 command planning and commit body generation.', + ); + assertCheck( + failures, + prepareSpecScript.includes("if (version === 'V30')") && + prepareSpecScript.includes('V30 canonical system specification for Protocol/BTD') && + prepareSpecScript.includes('BITCODE_SPEC_V30_PROVEN.md') && + prepareSpecScript.includes('v30-protocol-telemetry-proof-hooks.json') && + prepareSpecScript.includes('rewritePromotedParityJudgments'), + 'Spec-family promotion preparation must rewrite V30 hand-authored status truth and promoted parity judgments.', + ); + assertCheck( + failures, + prepareRuntimeScript.includes("'packages', 'protocol', 'src', 'canon-posture.js'") && + prepareRuntimeScript.includes("'packages', 'protocol', 'data', 'state.json'") && + prepareRuntimeScript.includes('rewriteRuntimeDataState'), + 'Runtime promotion preparation must update commercial package posture and package data.', + ); + assertCheck( + failures, + provenGenerator.includes('buildV30ProvenPackage') && + provenGenerator.includes('v30-protocol-telemetry-proof-hooks') && + v21Specifying.includes('.bitcode/v30-canon-posture-drift-report.json') && + v21Specifying.includes('.bitcode/v30-protocol-telemetry-proof-hooks.json'), + 'Generated appendix support must include V30 proof artifacts.', + ); + + const expectedActiveCanon = pointer === 'V30' ? 'V30' : 'V29'; + const expectedDraftTarget = pointer === 'V30' ? 'V31' : 'V30'; + const expectedProtocolReadmePosture = + pointer === 'V30' ? 'V30` active, `V31` draft after V30 promotion' : 'V29` active, `V30` draft'; + + assertCheck( + failures, + packageCanonPosture.includes(`ACTIVE_CANON_VERSION = '${expectedActiveCanon}'`) && + packageCanonPosture.includes(`DRAFT_TARGET_VERSION = '${expectedDraftTarget}'`) && + packageState.includes(`"activeCanonVersion": "${expectedActiveCanon}"`) && + packageState.includes(`"draftTargetVersion": "${expectedDraftTarget}"`) && + packageState.includes(`"activeProvenAppendixPath": "BITCODE_SPEC_${expectedActiveCanon}_PROVEN.md"`) && + packageState.includes(`"draftSpecPath": "BITCODE_SPEC_${expectedDraftTarget}.md"`), + `Protocol package posture and seed state must be aligned to ${expectedActiveCanon} active / ${expectedDraftTarget} draft.`, + ); + assertCheck( + failures, + protocolReadme.includes(expectedProtocolReadmePosture) && protocolReadme.includes('Gate 10'), + `Protocol package README must name the ${expectedActiveCanon}/${expectedDraftTarget} posture and Gate 10 promotion boundary.`, + ); + assertCheck( + failures, + rootReadme.includes('check:v30-gate10') && rootReadme.includes('v30-canon-promotion.yml'), + 'README must document the Gate 10 command and V30 promotion workflow.', + ); + + assertJsonArtifact(failures, root, '.bitcode/v30-spec-family-report.json', ['"version": "V30"', '"reportId": "v30-spec-family-report"']); + assertJsonArtifact(failures, root, '.bitcode/v30-canonical-input-report.json', ['"checkedTargetVersion": "V30"', 'v30-protocol-telemetry-proof-hooks.json']); + assertJsonArtifact(failures, root, '.bitcode/v30-canon-posture-drift-report.json', ['"checkedActiveCanonVersion": "V30"', '"checkedDraftTargetVersion": "V31"']); + assertJsonArtifact(failures, root, '.bitcode/v30-protocol-telemetry-proof-hooks.json', ['"reportId": "v30-protocol-telemetry-proof-hooks"', '"sourceSafe": true']); + + if (fileExists(root, 'BITCODE_SPEC_V30_PROVEN.md')) { + const proven = read(root, 'BITCODE_SPEC_V30_PROVEN.md'); + assertCheck(failures, proven.includes('Bitcode Spec V30') || proven.includes('V30'), 'BITCODE_SPEC_V30_PROVEN.md must render V30 proof content.'); + } + + if (failures.length) { + process.stderr.write('V30 Gate 10 promotion readiness check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write( + `V30 Gate 10 promotion readiness check passed promotionMode=${args.promotionMode ? 'true' : 'false'} pointer=${pointer}\n`, + ); +} + +main(); diff --git a/scripts/prepare-bitcode-runtime-canon-promotion.mjs b/scripts/prepare-bitcode-runtime-canon-promotion.mjs index 63f7fb573..ea1a29161 100644 --- a/scripts/prepare-bitcode-runtime-canon-promotion.mjs +++ b/scripts/prepare-bitcode-runtime-canon-promotion.mjs @@ -137,6 +137,9 @@ function rewritePackageReadme(content, version, nextDraft) { ).replace( /must remain aligned to `V\d+` active, `V\d+` draft during gate work, then be\s+rewritten by promotion automation to `V\d+` active, `V\d+` draft\./m, `must remain aligned to \`${version}\` active, \`${nextDraft}\` draft after promotion.` + ).replace( + /must remain aligned to `V\d+` active, `V\d+` draft until V\d+ promotion\./m, + `must remain aligned to \`${version}\` active, \`${nextDraft}\` draft after promotion.` ); } diff --git a/scripts/prepare-bitcode-spec-family-promotion.mjs b/scripts/prepare-bitcode-spec-family-promotion.mjs index 634ccbb3e..bf115e032 100644 --- a/scripts/prepare-bitcode-spec-family-promotion.mjs +++ b/scripts/prepare-bitcode-spec-family-promotion.mjs @@ -31,7 +31,7 @@ function printHelp() { 'Usage: node scripts/prepare-bitcode-spec-family-promotion.mjs --version V29 --commit [--repo-root ]', '', 'Rewrites the hand-authored spec family status truth for canonical promotion.', - 'Currently implemented for V21, V22, V23, V24, V25, V28, and V29.' + 'Currently implemented for V21, V22, V23, V24, V25, V28, V29, and V30.' ].join('\n') ); } @@ -209,8 +209,37 @@ function rewritePromotionStatus(version, commit, content, kind) { return kind === 'parity' ? rewritePromotedParityJudgments(rewritten, version) : rewritten; } + if (version === 'V30') { + const sharedInventory = 'active canonical `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, V30 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V30_PROVEN.md` as the generated proof appendix for V30 promotion'; + const scopeByKind = { + spec: 'V30 canonical system specification for Protocol/BTD package API boundaries, Bitcoin/Taproot/PSBT rigor, BTD AssetPack mint/read receipts, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness research boundaries, Protocol telemetry/proof hooks, interface regression, and promotion-ready workflow proof over V29', + delta: 'V30 canonical delta for Protocol/BTD package API boundaries, Bitcoin/Taproot/PSBT rigor, BTD AssetPack mint/read receipts, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness research boundaries, Protocol telemetry/proof hooks, interface regression, and promotion-ready workflow proof over V29', + notes: 'V30 canonical notes for Protocol/BTD hardening, local/staging readiness, and promotion automation over V29', + parity: 'V30 canonical parity ledger for Protocol/BTD hardening, local/staging readiness, and promotion automation over V29' + }; + const stateByKind = { + spec: 'canonical promotion complete; V30 is the active Protocol/BTD hardening canon and the V30 hand-authored plus generated canon are aligned', + delta: 'canonical promotion complete; this delta records the promoted V29-to-V30 Protocol/BTD hardening and promotion-readiness closure set', + notes: 'canonical promotion complete; V30 notes record the accepted Protocol/BTD hardening, local/staging, and promotion-readiness evidence', + parity: 'canonical promotion complete; V30 parity truth, Protocol/BTD gate closure, generated proof, and promotion automation are aligned' + }; + const rewritten = rewriteStatusValues(content, { + Scope: scopeByKind[kind], + ...(kind !== 'delta' + ? { 'Last fully realized canonical target preserved in source': '`V30`' } + : {}), + 'Current canonical/latest target': '`V30`', + 'Canonical proof-source commit': `\`${commit}\``, + 'Generated structured artifact inventory': sharedInventory, + 'Source parity state': + 'V30 source-side Protocol/BTD package APIs, Bitcoin/PSBT, receipts, ledger projection, source-to-shares, bridge-readiness, telemetry/proof hooks, interface regression, workflow, and promotion surfaces are canonicalized in the promoted V30 file family', + 'V30 state': stateByKind[kind] + }); + return kind === 'parity' ? rewritePromotedParityJudgments(rewritten, version) : rewritten; + } + if (!['V21', 'V22', 'V23', 'V24', 'V25'].includes(version)) { - throw new Error(`Promotion hand-authored family rewriting is currently implemented for V21, V22, V23, V24, V25, V28, and V29. Received ${version}.`); + throw new Error(`Promotion hand-authored family rewriting is currently implemented for V21, V22, V23, V24, V25, V28, V29, and V30. Received ${version}.`); } const sharedInventory = version === 'V21' ? 'active canonical `.bitcode/v19-*` reproducible reports, `.bitcode/v20-*` operator-quality reports, `.bitcode/v21-spec-family-report.json`, and `.bitcode/v21-canonical-input-report.json`; `ENGI_SPEC_V21_PROVEN.md` is the active generated proof appendix for V21' diff --git a/scripts/promote-bitcode-canon.mjs b/scripts/promote-bitcode-canon.mjs index 05613d043..a3ebe0232 100644 --- a/scripts/promote-bitcode-canon.mjs +++ b/scripts/promote-bitcode-canon.mjs @@ -47,7 +47,7 @@ function printHelp() { 'Usage: npm run promote:canon -- --version V20 --commit [--dry-run]', '', 'Options:', - ' --version Canonical version to promote. Accepted targets: V19, V20, V21, V22, V23, V24, V25, V28, V29.', + ' --version Canonical version to promote. Accepted targets: V19, V20, V21, V22, V23, V24, V25, V28, V29, V30.', ' --commit Proof-source commit to render into the generated appendix.', ' --dry-run Print the promotion plan without executing commands or writing files.', ' --allow-dirty-start Permit a dirty worktree before promotion. Not for canonical use.', @@ -216,7 +216,7 @@ function parseMarkdownTable(section) { */ function deriveScopeFocus(scope) { const stripped = stripMarkdown(scope || ''); - const match = stripped.match(/^V\d+\s+draft\s+specification\s+for\s+(.+?)(?:\s+after\s+.+)?$/i); + const match = stripped.match(/^V\d+\s+draft\s+(?:system\s+)?specification\s+for\s+(.+?)(?:\s+after\s+.+)?$/i); if (match) return trimTrailingPeriod(match[1]); const canonicalDraftMatch = stripped.match(/^V\d+\s+canonical\s+(?:system\s+)?(?:specification|delta|parity ledger)\s+draft\s+for\s+(.+?)(?:\s+after\s+.+)?$/i); if (canonicalDraftMatch) return trimTrailingPeriod(canonicalDraftMatch[1]); @@ -341,6 +341,24 @@ function buildCommandPlan(version, commit) { const v29PromotedCanonicalInputCheckCommand = ['node', ['scripts/check-bitcode-canonical-inputs.mjs', '--current-target', 'V29']]; const v29PromotedSpecCheckCommand = ['node', ['scripts/check-bitcode-spec-family.mjs', '--version', 'V29', '--mode', 'promoted']]; const v29PromotedCanonPostureDriftCommand = ['node', ['scripts/check-bitcode-canon-posture-drift.mjs', '--active-canon', 'V29', '--draft-target', 'V30']]; + const v30DraftSpecCheckCommand = ['node', ['scripts/check-bitcode-spec-family.mjs', '--version', 'V30', '--mode', 'draft', '--current-target', 'V29']]; + const v30CanonicalInputCheckCommand = ['node', ['scripts/check-bitcode-canonical-inputs.mjs', '--current-target', 'V29']]; + const v30DraftCanonPostureDriftCommand = ['node', ['scripts/check-bitcode-canon-posture-drift.mjs', '--active-canon', 'V29', '--draft-target', 'V30']]; + const v30Gate1Command = ['node', ['scripts/check-v30-gate1-roadmap-and-gating.mjs', '--skip-branch-check']]; + const v30Gate2Command = ['node', ['scripts/check-v30-gate2-protocol-package-api-boundaries.mjs', '--skip-branch-check']]; + const v30Gate3Command = ['node', ['scripts/check-v30-gate3-bitcoin-taproot-psbt-fee-rigor.mjs', '--skip-branch-check']]; + const v30Gate4Command = ['node', ['scripts/check-v30-gate4-btd-assetpack-mint-read-receipts.mjs', '--skip-branch-check']]; + const v30Gate5Command = ['node', ['scripts/check-v30-gate5-testnet-ledger-projection-hardening.mjs', '--skip-branch-check']]; + const v30Gate6Command = ['node', ['scripts/check-v30-gate6-source-to-shares-proof-cleanup.mjs', '--skip-branch-check']]; + const v30Gate7Command = ['node', ['scripts/check-v30-gate7-bridge-readiness-research-boundaries.mjs', '--skip-branch-check']]; + const v30Gate8Command = ['node', ['scripts/check-v30-gate8-protocol-telemetry-proof-hooks.mjs', '--skip-branch-check']]; + const v30Gate9Command = ['node', ['scripts/check-v30-gate9-interface-integration-regression-proof.mjs', '--skip-branch-check']]; + const v30Gate10Command = ['node', ['scripts/check-v30-gate10-promotion-readiness.mjs', '--promotion-mode', '--skip-branch-check']]; + const v30PreparePromotionSpecFamilyCommand = ['node', ['scripts/prepare-bitcode-spec-family-promotion.mjs', '--version', 'V30', '--commit', commit]]; + const v30PrepareRuntimePromotionCommand = ['node', ['scripts/prepare-bitcode-runtime-canon-promotion.mjs', '--version', 'V30', '--next-draft', 'V31']]; + const v30PromotedCanonicalInputCheckCommand = ['node', ['scripts/check-bitcode-canonical-inputs.mjs', '--current-target', 'V30']]; + const v30PromotedSpecCheckCommand = ['node', ['scripts/check-bitcode-spec-family.mjs', '--version', 'V30', '--mode', 'promoted']]; + const v30PromotedCanonPostureDriftCommand = ['node', ['scripts/check-bitcode-canon-posture-drift.mjs', '--active-canon', 'V30', '--draft-target', 'V31']]; const inheritedProofCommands = [ ['npm', ['--prefix', 'protocol-demonstration', 'run', 'typecheck']], ['npm', ['--prefix', 'protocol-demonstration', 'run', 'test:unit']], @@ -539,7 +557,46 @@ function buildCommandPlan(version, commit) { ['git', ['diff', '--check']] ]; } - throw new Error(`Unsupported promotion target ${version}. Expected V19, V20, V21, V22, V23, V24, V25, V28, or V29.`); + if (version === 'V30') { + return [ + v30DraftSpecCheckCommand, + v30CanonicalInputCheckCommand, + v30DraftCanonPostureDriftCommand, + v30Gate1Command, + v30Gate2Command, + v30Gate3Command, + v30Gate4Command, + v30Gate5Command, + v30Gate6Command, + v30Gate7Command, + v30Gate8Command, + v30Gate9Command, + v30Gate10Command, + ['pnpm', ['test:qa:v28:pipeline-readback']], + ['pnpm', ['--filter', '@bitcode/protocol', 'typecheck']], + ['pnpm', ['--filter', '@bitcode/protocol', 'test']], + ['pnpm', ['--filter', '@bitcode/btd', 'typecheck']], + ['pnpm', ['--filter', '@bitcode/btd', 'test']], + ['npm', ['--prefix', 'protocol-demonstration', 'test']], + ['npm', ['--prefix', 'protocol-demonstration', 'run', 'test:v28-mvp-qa']], + ['pnpm', ['--filter', '@bitcode/pipeline-asset-pack', 'typecheck']], + ['pnpm', ['--filter', '@bitcode/pipeline-hosts', 'typecheck']], + ['pnpm', ['--filter', '@bitcode/pipeline-asset-pack', 'exec', 'jest', '--config', 'jest.config.cjs', '--passWithNoTests', '--forceExit']], + ['pnpm', ['--filter', '@bitcode/pipeline-hosts', 'exec', 'jest', '--config', 'jest.config.cjs', '--passWithNoTests', '--forceExit']], + ['pnpm', ['--dir', 'uapi', 'exec', 'jest', '--runTestsByPath', 'tests/api/readReviewRoute.test.ts', 'tests/api/pipelineHarnessRoute.test.ts', 'tests/terminalPipelineHarnessClient.test.ts', 'tests/terminalDepositReadWorkbench.test.ts', 'tests/terminalTransactionQuery.test.ts', 'tests/terminalTransactionReadModel.test.ts', 'tests/terminalProtocolProjection.test.ts', 'tests/terminalInterfaceIntegrationRegression.test.ts', 'tests/terminalWalletBtcOperation.test.ts', 'tests/terminalJournalReconciliation.test.ts', 'tests/terminalOrganizationAuthority.test.ts', 'tests/protocolCommercialBoundary.test.ts', 'tests/terminalTransactionDetailCards.test.tsx', 'tests/terminalTransactionDetailSnapshot.test.ts', 'tests/terminalUxBrowserProof.test.tsx', 'tests/pipelineExecutionLogHeader.test.tsx', '--runInBand']], + ['pnpm', ['--dir', 'uapi', 'exec', 'playwright', 'install', 'chromium', '--with-deps']], + ['pnpm', ['--dir', 'uapi', 'run', 'test:e2e:terminal-ux']], + v30PreparePromotionSpecFamilyCommand, + v30PrepareRuntimePromotionCommand, + ['node', ['scripts/generate-bitcode-proven.mjs', '--version', version, '--commit', commit, '--worktree-state', 'clean', '--output', archivedProvenOutput(version), '--allow-dirty']], + ['node', ['scripts/generate-bitcode-proven.mjs', '--version', version, '--commit', commit, '--worktree-state', 'clean', '--output', archivedProvenOutput(version), '--check', '--allow-dirty']], + v30PromotedCanonicalInputCheckCommand, + v30PromotedSpecCheckCommand, + v30PromotedCanonPostureDriftCommand, + ['git', ['diff', '--check']] + ]; + } + throw new Error(`Unsupported promotion target ${version}. Expected V19, V20, V21, V22, V23, V24, V25, V28, V29, or V30.`); } /** @@ -928,6 +985,59 @@ async function buildDerivedV29CommitMessageBody(commit) { ].join('\n'); } +/** + * @param {string} commit + * @returns {Promise} + */ +async function buildDerivedV30CommitMessageBody(commit) { + const { spec, delta, parity } = await readSpecFamily('V30'); + const scope = extractStatusValue(spec, 'Scope') || 'V30 canonical system specification for Protocol/BTD hardening'; + const focus = deriveScopeFocus(scope); + const decisionSection = extractSection(delta, 'Accepted V30 decisions'); + const acceptedDecisions = extractOrderedItems(decisionSection).map(stripMarkdown); + const parityRows = [ + ...parseMarkdownTable(extractSection(parity, 'V30 implementation matrix')), + ...parseMarkdownTable(extractSection(parity, 'V30 implementation checklist')) + ]; + + /** @type {string[]} */ + const bullets = []; + for (const decision of acceptedDecisions.slice(0, 4)) { + bullets.push(trimTrailingPeriod(decision)); + } + + const prioritizedAreas = [ + 'Protocol package API boundaries', + 'Bitcoin Taproot PSBT fee rigor', + 'BTD AssetPack mint/read receipts', + 'Testnet ledger projection hardening', + 'Source-to-shares proof cleanup', + 'Bridge-readiness research boundaries', + 'Protocol telemetry/proof hooks', + 'Interface integration regression', + 'Promotion readiness' + ]; + for (const area of prioritizedAreas) { + const row = findParityRow(parityRows, area); + if (!row) continue; + const closureSignal = trimTrailingPeriod( + stripMarkdown(row['Required V30 result'] || row['Closure signal'] || row['Source evidence'] || '') + .replace('.bitcode/v30-,', '.bitcode/v30-*,') + ); + if (!closureSignal) continue; + bullets.push(`${stripMarkdown(area)}: ${closureSignal}`); + } + + return [ + `Promotes V30 as ${focus} for Bitcode.`, + '', + `Proof-source commit: ${commit}`, + '', + 'The promotion carries:', + ...bullets.slice(0, 14).map((bullet) => `- ${bullet}`) + ].join('\n'); +} + /** * @param {string} version * @param {string} commit @@ -988,7 +1098,10 @@ async function buildCommitMessageBody(version, commit) { if (version === 'V29') { return buildDerivedV29CommitMessageBody(commit); } - throw new Error(`Unsupported promotion target ${version}. Expected V19, V20, V21, V22, V23, V24, V25, V28, or V29.`); + if (version === 'V30') { + return buildDerivedV30CommitMessageBody(commit); + } + throw new Error(`Unsupported promotion target ${version}. Expected V19, V20, V21, V22, V23, V24, V25, V28, V29, or V30.`); } async function main() { @@ -999,8 +1112,8 @@ async function main() { } const version = args.version || ''; - if (!['V19', 'V20', 'V21', 'V22', 'V23', 'V24', 'V25', 'V28', 'V29'].includes(version)) { - throw new Error(`Canonical promotion accepts --version V19, V20, V21, V22, V23, V24, V25, V28, or V29. Received ${version || 'none'}.`); + if (!['V19', 'V20', 'V21', 'V22', 'V23', 'V24', 'V25', 'V28', 'V29', 'V30'].includes(version)) { + throw new Error(`Canonical promotion accepts --version V19, V20, V21, V22, V23, V24, V25, V28, V29, or V30. Received ${version || 'none'}.`); } const commit = args.commit || ''; if (!commit) { From bc68d2edf7cc8ba5a50d6d0e9ea23d26b39c042a Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 21:22:52 -0300 Subject: [PATCH 12/15] V30: Fix promotion README posture rewrite Broaden the runtime canon promotion README rewrite so promoted V30 demonstration docs move from draft-target wording to V30 active/V31 draft posture before drift validation. Add fixture coverage for the V30 Protocol/BTD hardening README shape.\n\nProof: npm --prefix protocol-demonstration run test:v22-canon-drift; git diff --check; git diff --cached --check. --- .../test/v22-canon-drift.test.js | 30 ++++++++++--------- ...repare-bitcode-runtime-canon-promotion.mjs | 4 +-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/protocol-demonstration/test/v22-canon-drift.test.js b/protocol-demonstration/test/v22-canon-drift.test.js index 6a85b1ede..266cef2aa 100644 --- a/protocol-demonstration/test/v22-canon-drift.test.js +++ b/protocol-demonstration/test/v22-canon-drift.test.js @@ -102,20 +102,21 @@ test('runtime promotion preparation rewrites current inline demonstration README path.join(fixtureRoot, 'protocol-demonstration', 'src', 'canon-posture.js'), [ "// @ts-check", - "export const ACTIVE_CANON_VERSION = 'V27';", - "export const DRAFT_TARGET_VERSION = 'V28';" + "export const ACTIVE_CANON_VERSION = 'V29';", + "export const DRAFT_TARGET_VERSION = 'V30';" ].join('\n'), 'utf8' ); await fs.writeFile( path.join(fixtureRoot, 'protocol-demonstration', 'README.md'), [ - '# Bitcode Protocol Demonstration - V27 canonical deterministic local prototype', + '# Bitcode Protocol Demonstration - V29 canonical deterministic local prototype', '', '`BITCODE_SPEC.txt` is the canonical pointer for active-system work. It currently', - 'resolves to `V27`; V28 is the active draft target for MVP QA.', - '`BITCODE_SPEC.txt -> V27`. This demo is governed by the active V27 canonical', - 'spec and `BITCODE_SPEC_V27_PROVEN.md` as the current generated appendix.' + 'resolves to `V29`; V30 is the active draft target for Protocol/BTD hardening.', + '`BITCODE_SPEC.txt -> V29`. This demo is governed by the active V29 canonical', + 'spec and `BITCODE_SPEC_V29_PROVEN.md` as the current generated appendix while V30 draft', + 'work proceeds outside the demonstration runtime boundary.' ].join('\n'), 'utf8' ); @@ -123,9 +124,9 @@ test('runtime promotion preparation rewrites current inline demonstration README execFileSync(process.execPath, [ prepareRuntimeScriptPath, '--version', - 'V28', + 'V30', '--next-draft', - 'V29', + 'V31', '--repo-root', fixtureRoot ], { @@ -135,12 +136,13 @@ test('runtime promotion preparation rewrites current inline demonstration README const rewrittenReadme = await fs.readFile(path.join(fixtureRoot, 'protocol-demonstration', 'README.md'), 'utf8'); - assert.match(rewrittenReadme, /# Bitcode Protocol Demonstration - V28 canonical deterministic local prototype/); - assert.match(rewrittenReadme, /resolves to `V28`; V29 is the next draft target after this promotion\./); - assert.match(rewrittenReadme, /BITCODE_SPEC\.txt -> V28/); - assert.match(rewrittenReadme, /active V28 canonical\s+spec/); - assert.match(rewrittenReadme, /BITCODE_SPEC_V28_PROVEN\.md/); - assert.doesNotMatch(rewrittenReadme, /active draft target for MVP QA/); + assert.match(rewrittenReadme, /# Bitcode Protocol Demonstration - V30 canonical deterministic local prototype/); + assert.match(rewrittenReadme, /resolves to `V30`; V31 is the next draft target after this promotion\./); + assert.match(rewrittenReadme, /BITCODE_SPEC\.txt -> V30/); + assert.match(rewrittenReadme, /active V30 canonical\s+spec/); + assert.match(rewrittenReadme, /BITCODE_SPEC_V30_PROVEN\.md/); + assert.doesNotMatch(rewrittenReadme, /active draft target/); + assert.doesNotMatch(rewrittenReadme, /draft work proceeds outside/); }); test('V23 spec-family promotion preparation rewrites hand-authored status truth', async () => { diff --git a/scripts/prepare-bitcode-runtime-canon-promotion.mjs b/scripts/prepare-bitcode-runtime-canon-promotion.mjs index ea1a29161..ba8349acd 100644 --- a/scripts/prepare-bitcode-runtime-canon-promotion.mjs +++ b/scripts/prepare-bitcode-runtime-canon-promotion.mjs @@ -107,11 +107,11 @@ function rewriteReadme(content, version, nextDraft) { `- current generated appendix: \`${promotedProvenPath(version)}\`` ); rewritten = rewritten.replace( - /resolves to `V\d+`; V\d+ is the active draft target for MVP QA\./m, + /resolves to `V\d+`; V\d+ is the active draft target[^.]*\./m, `resolves to \`${version}\`; ${nextDraft} is the next draft target after this promotion.` ); rewritten = rewritten.replace( - /`BITCODE_SPEC\.txt -> V\d+`\.\s+This demo is governed by the active V\d+ canonical\s+spec and `(?:BITCODE_SPEC_V\d+_PROVEN\.md|_legacy\/ENGI_SPEC_V\d+_PROVEN\.md)` as the current generated appendix\./m, + /`BITCODE_SPEC\.txt -> V\d+`\.\s+This demo is governed by the active V\d+ canonical\s+spec and `(?:BITCODE_SPEC_V\d+_PROVEN\.md|_legacy\/ENGI_SPEC_V\d+_PROVEN\.md)` as the current generated appendix(?:\s+while V\d+ draft\s+work proceeds outside the demonstration runtime boundary)?\./m, `\`BITCODE_SPEC.txt -> ${version}\`. This demo is governed by the active ${version} canonical\nspec and \`${promotedProvenPath(version)}\` as the current generated appendix.` ); rewritten = rewritten.replace( From 9d0adf73158583884de48bde92e57abb56b72a34 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 21:49:10 -0300 Subject: [PATCH 13/15] V30: Fix wrapped demonstration promotion posture Broaden the runtime promotion README rewrite so it handles the real demonstration paragraph when the generated appendix path is wrapped onto the next line. Proof: npm --prefix protocol-demonstration run test:v22-canon-drift; node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V29 --draft-target V30; copied promotion repro with V30/V31 drift check. --- protocol-demonstration/test/v22-canon-drift.test.js | 5 +++-- scripts/prepare-bitcode-runtime-canon-promotion.mjs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/protocol-demonstration/test/v22-canon-drift.test.js b/protocol-demonstration/test/v22-canon-drift.test.js index 266cef2aa..890b75c1a 100644 --- a/protocol-demonstration/test/v22-canon-drift.test.js +++ b/protocol-demonstration/test/v22-canon-drift.test.js @@ -114,8 +114,9 @@ test('runtime promotion preparation rewrites current inline demonstration README '', '`BITCODE_SPEC.txt` is the canonical pointer for active-system work. It currently', 'resolves to `V29`; V30 is the active draft target for Protocol/BTD hardening.', - '`BITCODE_SPEC.txt -> V29`. This demo is governed by the active V29 canonical', - 'spec and `BITCODE_SPEC_V29_PROVEN.md` as the current generated appendix while V30 draft', + '`BITCODE_SPEC.txt -> V29`.', + 'This demo is governed by the active V29 canonical spec and', + '`BITCODE_SPEC_V29_PROVEN.md` as the current generated appendix while V30 draft', 'work proceeds outside the demonstration runtime boundary.' ].join('\n'), 'utf8' diff --git a/scripts/prepare-bitcode-runtime-canon-promotion.mjs b/scripts/prepare-bitcode-runtime-canon-promotion.mjs index ba8349acd..161e7b8d1 100644 --- a/scripts/prepare-bitcode-runtime-canon-promotion.mjs +++ b/scripts/prepare-bitcode-runtime-canon-promotion.mjs @@ -111,7 +111,7 @@ function rewriteReadme(content, version, nextDraft) { `resolves to \`${version}\`; ${nextDraft} is the next draft target after this promotion.` ); rewritten = rewritten.replace( - /`BITCODE_SPEC\.txt -> V\d+`\.\s+This demo is governed by the active V\d+ canonical\s+spec and `(?:BITCODE_SPEC_V\d+_PROVEN\.md|_legacy\/ENGI_SPEC_V\d+_PROVEN\.md)` as the current generated appendix(?:\s+while V\d+ draft\s+work proceeds outside the demonstration runtime boundary)?\./m, + /`BITCODE_SPEC\.txt -> V\d+`\.\s+This demo is governed by the active V\d+ canonical\s+spec and\s+`(?:BITCODE_SPEC_V\d+_PROVEN\.md|_legacy\/ENGI_SPEC_V\d+_PROVEN\.md)` as the current generated appendix(?:\s+while V\d+ draft\s+work proceeds outside the demonstration runtime boundary)?\./m, `\`BITCODE_SPEC.txt -> ${version}\`. This demo is governed by the active ${version} canonical\nspec and \`${promotedProvenPath(version)}\` as the current generated appendix.` ); rewritten = rewritten.replace( From c5b238b9958430c4611ef396ac8cea248c1aecf4 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 22:17:29 -0300 Subject: [PATCH 14/15] V30: Trim generated proven appendix EOF Normalize the canonical proven appendix renderer so promotion-generated markdown ends with exactly one trailing newline and no blank EOF line. Apply the same behavior to the demonstration renderer and cover it with the proven generator test. Proof: - node --test --test-force-exit protocol-demonstration/test/proven-generator.test.js - git diff --check - node scripts/generate-bitcode-proven.mjs --version V30 --commit 9d0adf73158583884de48bde92e57abb56b72a34 --worktree-state clean --allow-dirty --stdout > /tmp/BITCODE_SPEC_V30_PROVEN.md && node -e "const fs=require('fs'); const s=fs.readFileSync('/tmp/BITCODE_SPEC_V30_PROVEN.md','utf8'); if(!s.endsWith('\n')||s.endsWith('\n\n')) process.exit(1);" --- packages/protocol/src/canonical/proven-generator.js | 4 +++- protocol-demonstration/src/canonical/proven-generator.js | 4 +++- protocol-demonstration/test/proven-generator.test.js | 2 ++ 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/protocol/src/canonical/proven-generator.js b/packages/protocol/src/canonical/proven-generator.js index 5712de336..1eb5d48f7 100644 --- a/packages/protocol/src/canonical/proven-generator.js +++ b/packages/protocol/src/canonical/proven-generator.js @@ -7126,7 +7126,9 @@ export function renderCanonicalProvenMarkdown(data) { ]) )); } - lines.push(''); + while (lines[lines.length - 1] === '') { + lines.pop(); + } return `${lines.join('\n')}\n`; } diff --git a/protocol-demonstration/src/canonical/proven-generator.js b/protocol-demonstration/src/canonical/proven-generator.js index 3a5075004..258ffcb92 100644 --- a/protocol-demonstration/src/canonical/proven-generator.js +++ b/protocol-demonstration/src/canonical/proven-generator.js @@ -7124,7 +7124,9 @@ export function renderCanonicalProvenMarkdown(data) { ]) )); } - lines.push(''); + while (lines[lines.length - 1] === '') { + lines.pop(); + } return `${lines.join('\n')}\n`; } diff --git a/protocol-demonstration/test/proven-generator.test.js b/protocol-demonstration/test/proven-generator.test.js index 66fb18ebb..5e9749cac 100644 --- a/protocol-demonstration/test/proven-generator.test.js +++ b/protocol-demonstration/test/proven-generator.test.js @@ -48,6 +48,8 @@ test('canonical proven generator renders a stable appendix from seeded proof run assert.ok(markdown.includes('## Run Details')); assert.ok(markdown.includes('`prompt-completeness`')); assert.ok(markdown.includes('_legacy/ENGI_SPEC_V15_PROVEN.md')); + assert.match(markdown, /\n$/); + assert.doesNotMatch(markdown, /\n\n$/); }); test('canonical proven generator fails closed on proof-family catalog drift across runs', () => { From d17b3069f08b11de22c74c298c2a5221f6f58d36 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 01:39:54 +0000 Subject: [PATCH 15/15] Promote Bitcode canon to V30 --- .bitcode/v30-canon-posture-drift-report.json | 58 ++++----- .bitcode/v30-canonical-input-report.json | 8 +- .../v30-protocol-telemetry-proof-hooks.json | 6 +- .bitcode/v30-spec-family-report.json | 12 +- BITCODE_SPEC.txt | 2 +- BITCODE_SPEC_V30.md | 13 +- BITCODE_SPEC_V30_DELTA.md | 11 +- BITCODE_SPEC_V30_NOTES.md | 12 +- BITCODE_SPEC_V30_PARITY_MATRIX.md | 47 ++++---- BITCODE_SPEC_V30_PROVEN.md | 114 +++++++++--------- packages/protocol/README.md | 4 +- packages/protocol/data/state.json | 22 ++-- packages/protocol/src/canon-posture.js | 6 +- protocol-demonstration/README.md | 10 +- protocol-demonstration/src/canon-posture.js | 6 +- 15 files changed, 163 insertions(+), 168 deletions(-) diff --git a/.bitcode/v30-canon-posture-drift-report.json b/.bitcode/v30-canon-posture-drift-report.json index fd89863d4..aebeeadbe 100644 --- a/.bitcode/v30-canon-posture-drift-report.json +++ b/.bitcode/v30-canon-posture-drift-report.json @@ -3,27 +3,19 @@ "version": "V30", "checkedActiveCanonVersion": "V30", "checkedDraftTargetVersion": "V31", - "pointerVersion": "V29", - "proofSourceCommit": "f1771573c885652055c86ced1b43ba06a3ba7706", - "generatedAt": "2026-05-21T20:27:10-03:00", + "pointerVersion": "V30", + "proofSourceCommit": "c5b238b9958430c4611ef396ac8cea248c1aecf4", + "generatedAt": "2026-05-21T22:17:44-03:00", "generatorId": "bitcode.proven-generator.v1", - "worktreeState": "dirty-preview", - "passed": false, + "worktreeState": "clean", + "passed": true, "checkCount": 10, - "blockingFailureCount": 7, - "blockingFailures": [ - "pointer-active-canon-alignment: BITCODE_SPEC.txt points to V29 while runtime expects V30.", - "canon-posture-constant-alignment: canon-posture constants resolve V29/V30 with operator label V29 active canon / V30 system draft.", - "proven-appendix-alignment: active generated appendix path is BITCODE_SPEC_V29_PROVEN.md.", - "policy-ref-alignment: policy reference is policy://bitcode/spec-v29-active-v30-system-draft/current.", - "runtime-state-alignment: buildInitialState() reports Bitcode Spec V29 active canon / V30 system draft with canon posture V29/V30.", - "public-state-alignment: publicState() reports Bitcode Spec V29 active canon / V30 system draft with canon posture V29/V30.", - "readme-alignment: README states V30 active canon and BITCODE_SPEC_V29_PROVEN.md as the current generated appendix." - ], - "runtimeSpecVersion": "Bitcode Spec V29 active canon / V30 system draft", - "publicSpecVersion": "Bitcode Spec V29 active canon / V30 system draft", - "activeProvenAppendixPath": "BITCODE_SPEC_V29_PROVEN.md", - "policyRef": "policy://bitcode/spec-v29-active-v30-system-draft/current", + "blockingFailureCount": 0, + "blockingFailures": [], + "runtimeSpecVersion": "Bitcode Spec V30 active canon / V31 system draft", + "publicSpecVersion": "Bitcode Spec V30 active canon / V31 system draft", + "activeProvenAppendixPath": "BITCODE_SPEC_V30_PROVEN.md", + "policyRef": "policy://bitcode/spec-v30-active-v31-system-draft/current", "checkedFiles": [ "protocol-demonstration/README.md", "protocol-demonstration/public/index.html", @@ -33,33 +25,33 @@ "checks": [ { "checkId": "pointer-active-canon-alignment", - "passed": false, - "detail": "BITCODE_SPEC.txt points to V29 while runtime expects V30." + "passed": true, + "detail": "BITCODE_SPEC.txt points to V30 while runtime expects V30." }, { "checkId": "canon-posture-constant-alignment", - "passed": false, - "detail": "canon-posture constants resolve V29/V30 with operator label V29 active canon / V30 system draft." + "passed": true, + "detail": "canon-posture constants resolve V30/V31 with operator label V30 active canon / V31 system draft." }, { "checkId": "proven-appendix-alignment", - "passed": false, - "detail": "active generated appendix path is BITCODE_SPEC_V29_PROVEN.md." + "passed": true, + "detail": "active generated appendix path is BITCODE_SPEC_V30_PROVEN.md." }, { "checkId": "policy-ref-alignment", - "passed": false, - "detail": "policy reference is policy://bitcode/spec-v29-active-v30-system-draft/current." + "passed": true, + "detail": "policy reference is policy://bitcode/spec-v30-active-v31-system-draft/current." }, { "checkId": "runtime-state-alignment", - "passed": false, - "detail": "buildInitialState() reports Bitcode Spec V29 active canon / V30 system draft with canon posture V29/V30." + "passed": true, + "detail": "buildInitialState() reports Bitcode Spec V30 active canon / V31 system draft with canon posture V30/V31." }, { "checkId": "public-state-alignment", - "passed": false, - "detail": "publicState() reports Bitcode Spec V29 active canon / V30 system draft with canon posture V29/V30." + "passed": true, + "detail": "publicState() reports Bitcode Spec V30 active canon / V31 system draft with canon posture V30/V31." }, { "checkId": "server-api-alignment", @@ -78,8 +70,8 @@ }, { "checkId": "readme-alignment", - "passed": false, - "detail": "README states V30 active canon and BITCODE_SPEC_V29_PROVEN.md as the current generated appendix." + "passed": true, + "detail": "README states V30 active canon and BITCODE_SPEC_V30_PROVEN.md as the current generated appendix." } ] } diff --git a/.bitcode/v30-canonical-input-report.json b/.bitcode/v30-canonical-input-report.json index a83923e32..0143d32e5 100644 --- a/.bitcode/v30-canonical-input-report.json +++ b/.bitcode/v30-canonical-input-report.json @@ -1,12 +1,12 @@ { "reportId": "v30-canonical-input-report", "version": "V30", - "proofSourceCommit": "f1771573c885652055c86ced1b43ba06a3ba7706", - "generatedAt": "2026-05-21T20:27:10-03:00", + "proofSourceCommit": "c5b238b9958430c4611ef396ac8cea248c1aecf4", + "generatedAt": "2026-05-21T22:17:44-03:00", "generatorId": "bitcode.proven-generator.v1", - "worktreeState": "dirty-preview", + "worktreeState": "clean", "checkedTargetVersion": "V30", - "pointerVersion": "V29", + "pointerVersion": "V30", "passed": true, "failureCount": 0, "failures": [], diff --git a/.bitcode/v30-protocol-telemetry-proof-hooks.json b/.bitcode/v30-protocol-telemetry-proof-hooks.json index c1bef9d70..21d64ee93 100644 --- a/.bitcode/v30-protocol-telemetry-proof-hooks.json +++ b/.bitcode/v30-protocol-telemetry-proof-hooks.json @@ -1,10 +1,10 @@ { "reportId": "v30-protocol-telemetry-proof-hooks", "version": "V30", - "proofSourceCommit": "f1771573c885652055c86ced1b43ba06a3ba7706", - "generatedAt": "2026-05-21T20:27:10-03:00", + "proofSourceCommit": "c5b238b9958430c4611ef396ac8cea248c1aecf4", + "generatedAt": "2026-05-21T22:17:44-03:00", "generatorId": "bitcode.proven-generator.v1", - "worktreeState": "dirty-preview", + "worktreeState": "clean", "passed": true, "sourceSafe": true, "checkedFileCount": 12, diff --git a/.bitcode/v30-spec-family-report.json b/.bitcode/v30-spec-family-report.json index 1b66e90a1..ea0999796 100644 --- a/.bitcode/v30-spec-family-report.json +++ b/.bitcode/v30-spec-family-report.json @@ -1,14 +1,14 @@ { "reportId": "v30-spec-family-report", "version": "V30", - "proofSourceCommit": "f1771573c885652055c86ced1b43ba06a3ba7706", - "generatedAt": "2026-05-21T20:27:10-03:00", + "proofSourceCommit": "c5b238b9958430c4611ef396ac8cea248c1aecf4", + "generatedAt": "2026-05-21T22:17:44-03:00", "generatorId": "bitcode.proven-generator.v1", - "worktreeState": "dirty-preview", + "worktreeState": "clean", "checkedVersion": "V30", - "mode": "draft", - "currentTarget": "V29", - "pointerVersion": "V29", + "mode": "promoted", + "currentTarget": "V30", + "pointerVersion": "V30", "passed": true, "failureCount": 0, "failures": [], diff --git a/BITCODE_SPEC.txt b/BITCODE_SPEC.txt index b3ce294a8..656cad4ae 100644 --- a/BITCODE_SPEC.txt +++ b/BITCODE_SPEC.txt @@ -1 +1 @@ -V29 +V30 diff --git a/BITCODE_SPEC_V30.md b/BITCODE_SPEC_V30.md index 823bea409..40b0a8d16 100644 --- a/BITCODE_SPEC_V30.md +++ b/BITCODE_SPEC_V30.md @@ -3,12 +3,13 @@ ## Status - Version: `V30` -- V30 state: draft target opened; V30 owns Protocol/BTD hardening over the promoted V29 Terminal transaction-depth canon -- Current canonical/latest target: `V29` +- V30 state: canonical promotion complete; V30 is the active Protocol/BTD hardening canon and the V30 hand-authored plus generated canon are aligned +- Current canonical/latest target: `V30` +- Canonical proof-source commit: `c5b238b9958430c4611ef396ac8cea248c1aecf4` - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` -- Generated structured artifact inventory: V30 Gate 10 generates `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and `BITCODE_SPEC_V30_PROVEN.md` as promotion evidence -- Source parity state: V30 source parity is draft-opened for Protocol/BTD package hardening, Bitcoin/PSBT rigor, BTD receipt boundaries, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness boundaries, telemetry hooks, interface regression, and promotion automation +- Generated structured artifact inventory: active canonical `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, V30 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V30_PROVEN.md` as the generated proof appendix for V30 promotion +- Source parity state: V30 source-side Protocol/BTD package APIs, Bitcoin/PSBT, receipts, ledger projection, source-to-shares, bridge-readiness, telemetry/proof hooks, interface regression, workflow, and promotion surfaces are canonicalized in the promoted V30 file family - State: draft target opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` - Draft target source: `protocol-demonstration/src/canon-posture.js` declares `DRAFT_TARGET_VERSION = 'V30'` @@ -18,8 +19,8 @@ - Delta companion: `BITCODE_SPEC_V30_DELTA.md` - Parity companion: `BITCODE_SPEC_V30_PARITY_MATRIX.md` - Generated proof appendix: none until V30 promotion -- Scope: V30 draft system specification for Protocol/BTD hardening after V29, including package API extraction, Bitcoin/Taproot/PSBT rigor, BTD-AssetPack mint/read receipts, testnet ledger/database projection hardening, source-to-shares proof cleanup, bridge-readiness research boundaries, telemetry/proof hooks, and promotion readiness -- Last fully realized canonical target preserved in source: `V29` +- Scope: V30 canonical system specification for Protocol/BTD package API boundaries, Bitcoin/Taproot/PSBT rigor, BTD AssetPack mint/read receipts, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness research boundaries, Protocol telemetry/proof hooks, interface regression, and promotion-ready workflow proof over V29 +- Last fully realized canonical target preserved in source: `V30` V30 begins from promoted V29. V29 made the Terminal transaction cockpit deep enough for operators to follow Reading, Finding Fits, AssetPack preview, settlement, rights transfer, delivery, repair, authority, and promotion readiness. diff --git a/BITCODE_SPEC_V30_DELTA.md b/BITCODE_SPEC_V30_DELTA.md index cb3f0a385..12afb7de8 100644 --- a/BITCODE_SPEC_V30_DELTA.md +++ b/BITCODE_SPEC_V30_DELTA.md @@ -3,15 +3,16 @@ ## Status - Version: `V30` -- V30 state: draft target delta opened for Protocol/BTD hardening -- Current canonical/latest target: `V29` +- V30 state: canonical promotion complete; this delta records the promoted V29-to-V30 Protocol/BTD hardening and promotion-readiness closure set +- Current canonical/latest target: `V30` +- Canonical proof-source commit: `c5b238b9958430c4611ef396ac8cea248c1aecf4` - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` -- Generated structured artifact inventory: V30 Gate 10 generates `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and `BITCODE_SPEC_V30_PROVEN.md` as promotion evidence -- Source parity state: V30 source parity is draft-opened for Protocol/BTD package APIs, Bitcoin/Taproot/PSBT rigor, BTD receipts, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness boundaries, telemetry hooks, and promotion automation +- Generated structured artifact inventory: active canonical `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, V30 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V30_PROVEN.md` as the generated proof appendix for V30 promotion +- Source parity state: V30 source-side Protocol/BTD package APIs, Bitcoin/PSBT, receipts, ledger projection, source-to-shares, bridge-readiness, telemetry/proof hooks, interface regression, workflow, and promotion surfaces are canonicalized in the promoted V30 file family - State: draft target delta opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` -- Scope: V30 draft delta for Protocol/BTD hardening over promoted V29 +- Scope: V30 canonical delta for Protocol/BTD package API boundaries, Bitcoin/Taproot/PSBT rigor, BTD AssetPack mint/read receipts, testnet ledger projection, source-to-shares proof cleanup, bridge-readiness research boundaries, Protocol telemetry/proof hooks, interface regression, and promotion-ready workflow proof over V29 - Spec companion: `BITCODE_SPEC_V30.md` - Notes companion: `BITCODE_SPEC_V30_NOTES.md` - Parity companion: `BITCODE_SPEC_V30_PARITY_MATRIX.md` diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index 074636aa7..4e5a35a21 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -3,17 +3,19 @@ ## Status - Version: `V30` -- V30 state: draft target opened; Gate 1 converts this file from planning memory into the V30 notes companion -- Current canonical/latest target: `V29` +- V30 state: canonical promotion complete; V30 notes record the accepted Protocol/BTD hardening, local/staging, and promotion-readiness evidence +- Current canonical/latest target: `V30` +- Canonical proof-source commit: `c5b238b9958430c4611ef396ac8cea248c1aecf4` - Current active draft target: `V30` - Canonical pointer: `BITCODE_SPEC.txt` -> `V29` - Active canonical anchor: `BITCODE_SPEC_V29.md` - Active generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` -- Generated structured artifact inventory: V30 Gate 10 generates `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and `BITCODE_SPEC_V30_PROVEN.md` -- Source parity state: V30 source parity begins with Gate 1 roadmap/gating and then closes through Protocol/BTD package API, Bitcoin/PSBT, BTD receipt, ledger projection, source-to-shares, bridge-readiness, telemetry/proof, interface-regression, and promotion-readiness gates -- Scope: future notes for Protocol/BTD hardening after V28 commercial Protocol/Terminal MVP and V29 deeper Terminal work. Exchange is deferred beyond V35. +- Generated structured artifact inventory: active canonical `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, V30 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V30_PROVEN.md` as the generated proof appendix for V30 promotion +- Source parity state: V30 source-side Protocol/BTD package APIs, Bitcoin/PSBT, receipts, ledger projection, source-to-shares, bridge-readiness, telemetry/proof hooks, interface regression, workflow, and promotion surfaces are canonicalized in the promoted V30 file family +- Scope: V30 canonical notes for Protocol/BTD hardening, local/staging readiness, and promotion automation over V29 +- Last fully realized canonical target preserved in source: `V30` This NOTES file does not promote V30. Gate 1 opens V30 implementation discipline from promoted V29 without rediscovering deferred Protocol/BTD hardening pressure. diff --git a/BITCODE_SPEC_V30_PARITY_MATRIX.md b/BITCODE_SPEC_V30_PARITY_MATRIX.md index 384ece4db..600f47539 100644 --- a/BITCODE_SPEC_V30_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V30_PARITY_MATRIX.md @@ -3,20 +3,21 @@ ## Status - Version: `V30` -- V30 state: draft target parity matrix opened for Protocol/BTD hardening -- Current canonical/latest target: `V29` +- V30 state: canonical promotion complete; V30 parity truth, Protocol/BTD gate closure, generated proof, and promotion automation are aligned +- Current canonical/latest target: `V30` +- Canonical proof-source commit: `c5b238b9958430c4611ef396ac8cea248c1aecf4` - Prior canonical anchor: `BITCODE_SPEC_V29.md` - Prior generated proof appendix: `BITCODE_SPEC_V29_PROVEN.md` -- Generated structured artifact inventory: V30 Gate 10 generates `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, and `BITCODE_SPEC_V30_PROVEN.md` -- Source parity state: V30 parity begins with roadmap/gating, then hardens package APIs, Bitcoin/PSBT, BTD receipts, ledger projection, source-to-shares proof, bridge-readiness boundaries, telemetry/proof hooks, interface regression, and promotion readiness +- Generated structured artifact inventory: active canonical `.bitcode/v30-spec-family-report.json`, `.bitcode/v30-canonical-input-report.json`, `.bitcode/v30-canon-posture-drift-report.json`, `.bitcode/v30-protocol-telemetry-proof-hooks.json`, V30 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V30_PROVEN.md` as the generated proof appendix for V30 promotion +- Source parity state: V30 source-side Protocol/BTD package APIs, Bitcoin/PSBT, receipts, ledger projection, source-to-shares, bridge-readiness, telemetry/proof hooks, interface regression, workflow, and promotion surfaces are canonicalized in the promoted V30 file family - State: draft target parity matrix opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V29` -- Scope: V30 parity ledger for Protocol/BTD hardening over promoted V29 +- Scope: V30 canonical parity ledger for Protocol/BTD hardening, local/staging readiness, and promotion automation over V29 - Spec companion: `BITCODE_SPEC_V30.md` - Notes companion: `BITCODE_SPEC_V30_NOTES.md` - Delta companion: `BITCODE_SPEC_V30_DELTA.md` - Generated proof appendix: none until V30 promotion -- Last fully realized canonical target preserved in source: `V29` +- Last fully realized canonical target preserved in source: `V30` ## Purpose @@ -53,28 +54,28 @@ No `_legacy/` source is active source truth. | Area | Gate | Source evidence | Judgment | Closure requirement | | --- | --- | --- | --- | --- | -| Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V30.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v30/gate-1-roadmap-and-gating` | drafted | V30 family validates in draft mode over active V29 and `check:v30-gate1` passes. | -| Roadmap truth | Gate 1 | `SPECIFICATIONS_ROADMAP.md`, README, PR template, workflow posture | drafted | Roadmap states V29 active, V30 draft, and coherent V31-V37 responsibilities. | -| Protocol package API boundaries | Gate 2 | `packages/btd/src/api-boundaries.ts`, `packages/api/src/routes/btd-crypto.ts`, package READMEs/tests | drafted | Shared Protocol/BTD objects have package-owned builders, parsers, validators, JSON-safe serializers, and tests. | -| Bitcoin Taproot PSBT fee rigor | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, `packages/btd/src/bitcoin-fees.ts`, BTD/API tests, gate checker | drafted | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, Taproot/PSBT aware, and proof-rooted. | -| BTD AssetPack mint/read receipts | Gate 4 | `packages/btd/src/receipts.ts`, `packages/btd/src/api-boundaries.ts`, asset-pack harness evidence, Terminal detail snapshot/read model tests, gate checker | drafted | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | -| Testnet ledger projection hardening | Gate 5 | `packages/btd/src/reconciliation.ts`, API route tests, asset-pack harness evidence, Terminal journal reconciliation UI/tests, gate checker | drafted | Ledger/database/object-storage/private facts are distinct; staging-testnet readback is secret-free; drift, quarantine, retry, and unlock blocking are tested. | -| Source-to-shares proof cleanup | Gate 6 | `packages/btd/src/source-to-shares.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Measurement contribution, fee allocation, zero-cell/refit tail, ancestry evidence, and conservation invariants are testable. | -| Bridge-readiness research boundaries | Gate 7 | `packages/btd/src/bridge-readiness.ts`, BTD/API tests, route boundary, docs, gate checker | drafted | Bridge paths are typed research-only records until admitted by explicit future proof and policy. | -| Protocol telemetry/proof hooks | Gate 8 | `packages/btd/src/telemetry.ts`, API route boundary, focused BTD/API tests, gate checker | drafted | Receipts, fee states, projections, source-to-shares proofs, and bridge-readiness posture emit source-safe telemetry and proof hooks. | -| Interface integration regression | Gate 9 | `packages/btd/src/interface-integration.ts`, `packages/api/src/routes/btd-crypto.ts`, Terminal/MCP/ChatGPT adapters and tests, gate checker | drafted | Existing interfaces consume package-owned objects without regressing V29 behavior. | -| Promotion readiness | Gate 10 | V30 promotion workflow, generated `.bitcode/v30-*`, `BITCODE_SPEC_V30_PROVEN.md` | drafted | `version/v30` can promote to `main` only after all V30 checks pass and promotion automation can commit generated canon. | +| Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V30.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v30/gate-1-roadmap-and-gating` | closed | V30 family validates in draft mode over active V29 and `check:v30-gate1` passes. | +| Roadmap truth | Gate 1 | `SPECIFICATIONS_ROADMAP.md`, README, PR template, workflow posture | closed | Roadmap states V29 active, V30 draft, and coherent V31-V37 responsibilities. | +| Protocol package API boundaries | Gate 2 | `packages/btd/src/api-boundaries.ts`, `packages/api/src/routes/btd-crypto.ts`, package READMEs/tests | closed | Shared Protocol/BTD objects have package-owned builders, parsers, validators, JSON-safe serializers, and tests. | +| Bitcoin Taproot PSBT fee rigor | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, `packages/btd/src/bitcoin-fees.ts`, BTD/API tests, gate checker | closed | BTC fee and signer states are typed, testnet/mainnet-safe, no-custody, Taproot/PSBT aware, and proof-rooted. | +| BTD AssetPack mint/read receipts | Gate 4 | `packages/btd/src/receipts.ts`, `packages/btd/src/api-boundaries.ts`, asset-pack harness evidence, Terminal detail snapshot/read model tests, gate checker | closed | Mint, read, and rights-transfer receipts bind BTD range, preview, paid unlock, delivery, and ledger projection. | +| Testnet ledger projection hardening | Gate 5 | `packages/btd/src/reconciliation.ts`, API route tests, asset-pack harness evidence, Terminal journal reconciliation UI/tests, gate checker | closed | Ledger/database/object-storage/private facts are distinct; staging-testnet readback is secret-free; drift, quarantine, retry, and unlock blocking are tested. | +| Source-to-shares proof cleanup | Gate 6 | `packages/btd/src/source-to-shares.ts`, API route boundary, focused BTD/API tests, gate checker | closed | Measurement contribution, fee allocation, zero-cell/refit tail, ancestry evidence, and conservation invariants are testable. | +| Bridge-readiness research boundaries | Gate 7 | `packages/btd/src/bridge-readiness.ts`, BTD/API tests, route boundary, docs, gate checker | closed | Bridge paths are typed research-only records until admitted by explicit future proof and policy. | +| Protocol telemetry/proof hooks | Gate 8 | `packages/btd/src/telemetry.ts`, API route boundary, focused BTD/API tests, gate checker | closed | Receipts, fee states, projections, source-to-shares proofs, and bridge-readiness posture emit source-safe telemetry and proof hooks. | +| Interface integration regression | Gate 9 | `packages/btd/src/interface-integration.ts`, `packages/api/src/routes/btd-crypto.ts`, Terminal/MCP/ChatGPT adapters and tests, gate checker | closed | Existing interfaces consume package-owned objects without regressing V29 behavior. | +| Promotion readiness | Gate 10 | V30 promotion workflow, generated `.bitcode/v30-*`, `BITCODE_SPEC_V30_PROVEN.md` | closed | `version/v30` can promote to `main` only after all V30 checks pass and promotion automation can commit generated canon. | ## V30 implementation checklist | Area | Required V30 result | Judgment | | --- | --- | --- | -| Active canon pointer | `BITCODE_SPEC.txt` remains `V29` during V30 gate work | drafted | -| Gate branch pattern | V30 work happens on `version/v30` or `v30/gate-N-*` branches | drafted | -| Spec-family shape | V30 SPEC, DELTA, NOTES, and PARITY satisfy the full spec-family checker | drafted | -| Gate 1 script | `pnpm run check:v30-gate1` fails closed on stale posture, missing roadmap truth, or missing gates | drafted | -| Gate-quality workflow | Gate workflow validates V29 active / V30 draft posture and V30 Gate 1 | drafted | -| Canon-quality workflow | Canon workflow validates V29 active / V30 draft posture and V30 draft family | drafted | +| Active canon pointer | `BITCODE_SPEC.txt` remains `V29` during V30 gate work | closed | +| Gate branch pattern | V30 work happens on `version/v30` or `v30/gate-N-*` branches | closed | +| Spec-family shape | V30 SPEC, DELTA, NOTES, and PARITY satisfy the full spec-family checker | closed | +| Gate 1 script | `pnpm run check:v30-gate1` fails closed on stale posture, missing roadmap truth, or missing gates | closed | +| Gate-quality workflow | Gate workflow validates V29 active / V30 draft posture and V30 Gate 1 | closed | +| Canon-quality workflow | Canon workflow validates V29 active / V30 draft posture and V30 draft family | closed | ## Gate 1 Parity diff --git a/BITCODE_SPEC_V30_PROVEN.md b/BITCODE_SPEC_V30_PROVEN.md index 42c49c478..a423e77e3 100644 --- a/BITCODE_SPEC_V30_PROVEN.md +++ b/BITCODE_SPEC_V30_PROVEN.md @@ -1,18 +1,18 @@ # Bitcode Spec V30 Proven - canonicalVersion: `V30` -- canonicalCommit: `f1771573c885652055c86ced1b43ba06a3ba7706` -- canonicalCommitRecordedAt: `2026-05-21T20:27:10-03:00` -- worktreeState: `dirty-preview` +- canonicalCommit: `c5b238b9958430c4611ef396ac8cea248c1aecf4` +- canonicalCommitRecordedAt: `2026-05-21T22:17:44-03:00` +- worktreeState: `clean` - generatorId: `bitcode.proven-generator.v1` -- generatedAt: `2026-05-21T20:27:10-03:00` +- generatedAt: `2026-05-21T22:17:44-03:00` - outputPath: `BITCODE_SPEC_V30_PROVEN.md` - scenarioIds: `auth-issuer-rollback`, `rust-validator-proof-gap`, `config-policy-precedence-incident`, `unsafe-patch-review-recovery`, `infra-deployment-mismatch`, `privacy-boundary-proof-export`, `polyglot-gateway-benchmark-remediation`, `auth-many-asset-normalization` - branchModes: `patch`, `context` ## Aggregate Verdict -- fullyProven: `false` +- fullyProven: `true` - runCount: `16` - familyCount: `9` - theoremCount: `58` @@ -36,13 +36,13 @@ | artifactPath | digest | byteLength | | --- | --- | --- | -| `.bitcode/v19-contract-change-ledger.json` | `sha256:94b35e79de119c0a13a2d46ae7ad27ae2015ecdb3dc2cc3139d5e3b9b51ce6ea` | 3311 | -| `.bitcode/v19-deterministic-replay-report.json` | `sha256:86674e92f2e5dcc32c350d111423f62157baa8bea044ee1837cd4edaa2be0d4f` | 8459 | -| `.bitcode/v19-negative-proof-mutation-matrix.json` | `sha256:50a5750cd371aa15cb8da60dc02ada762aa4c6b977b469eb5d44e625aa75c47b` | 8085 | -| `.bitcode/v19-proof-member-semantic-matrix.json` | `sha256:ad6eb883dd76f2488ddcfc6bbd73ae2f5d3c6ebf50cb0ed3b80aa382ef4f180b` | 1815750 | -| `.bitcode/v19-state-machine-matrix.json` | `sha256:51c99848cc8fc2427d989e39fccca1c6024d2282f6896cf98e646c771ddf1529` | 154965 | -| `.bitcode/v19-theorem-evidence-matrix.json` | `sha256:cadb4106c003cbe3e572348a14d0ec987da647c4259477f0caca84ffacc907ae` | 2405676 | -| `.bitcode/v19-volatility-inventory.json` | `sha256:41ce5afc23b73d693cccbbc09a9db4263bd9cfb2b8d79128390a10dad5a83ac7` | 6206 | +| `.bitcode/v19-contract-change-ledger.json` | `sha256:f4d1620dd7260aa07614d5e321e267dce47a3a5d201b339f7f72ab7ce3dff606` | 3311 | +| `.bitcode/v19-deterministic-replay-report.json` | `sha256:daacd0ba34ef568080cb9bd5729cf8e73f044001826f1133ac5ad6ab82d6c6b4` | 8459 | +| `.bitcode/v19-negative-proof-mutation-matrix.json` | `sha256:22769944b87608505fe6e33186fc948be3a4f91bc887db61462a758689b55331` | 8085 | +| `.bitcode/v19-proof-member-semantic-matrix.json` | `sha256:13627ebcbd8ea8bb5eeb3bb9d315f04e91e94e071c64b471aa1ea9d66b354e32` | 1815750 | +| `.bitcode/v19-state-machine-matrix.json` | `sha256:fb31c743b8f9a86f4a996f9590e29f57739c7d2ae50d3c46f9e10d160385cee4` | 154965 | +| `.bitcode/v19-theorem-evidence-matrix.json` | `sha256:d73da851088e3bcd6d3ab02aaade229ac87ad3a147cca51c852b9b86a2d23122` | 2405676 | +| `.bitcode/v19-volatility-inventory.json` | `sha256:450681dc9040e62e561a8a85202058e623b9e6683f494de2b4b41975a867f51e` | 6206 | ### V19 Inherited Positive Matrix Summaries @@ -61,13 +61,13 @@ | artifactPath | firstDigest | secondDigest | byteEqual | | --- | --- | --- | --- | -| `.bitcode/v19-contract-change-ledger.json` | `sha256:94b35e79de119c0a13a2d46ae7ad27ae2015ecdb3dc2cc3139d5e3b9b51ce6ea` | `sha256:94b35e79de119c0a13a2d46ae7ad27ae2015ecdb3dc2cc3139d5e3b9b51ce6ea` | `true` | -| `.bitcode/v19-negative-proof-mutation-matrix.json` | `sha256:50a5750cd371aa15cb8da60dc02ada762aa4c6b977b469eb5d44e625aa75c47b` | `sha256:50a5750cd371aa15cb8da60dc02ada762aa4c6b977b469eb5d44e625aa75c47b` | `true` | -| `.bitcode/v19-proof-member-semantic-matrix.json` | `sha256:ad6eb883dd76f2488ddcfc6bbd73ae2f5d3c6ebf50cb0ed3b80aa382ef4f180b` | `sha256:ad6eb883dd76f2488ddcfc6bbd73ae2f5d3c6ebf50cb0ed3b80aa382ef4f180b` | `true` | -| `.bitcode/v19-state-machine-matrix.json` | `sha256:51c99848cc8fc2427d989e39fccca1c6024d2282f6896cf98e646c771ddf1529` | `sha256:51c99848cc8fc2427d989e39fccca1c6024d2282f6896cf98e646c771ddf1529` | `true` | -| `.bitcode/v19-theorem-evidence-matrix.json` | `sha256:cadb4106c003cbe3e572348a14d0ec987da647c4259477f0caca84ffacc907ae` | `sha256:cadb4106c003cbe3e572348a14d0ec987da647c4259477f0caca84ffacc907ae` | `true` | -| `.bitcode/v19-volatility-inventory.json` | `sha256:41ce5afc23b73d693cccbbc09a9db4263bd9cfb2b8d79128390a10dad5a83ac7` | `sha256:41ce5afc23b73d693cccbbc09a9db4263bd9cfb2b8d79128390a10dad5a83ac7` | `true` | -| `_legacy/ENGI_SPEC_V19_PROVEN.md` | `sha256:5fc14d4cc38c116d1e3e30daaf625e3264d740f6906fa170e4fbc3595f8cd7d4` | `sha256:5fc14d4cc38c116d1e3e30daaf625e3264d740f6906fa170e4fbc3595f8cd7d4` | `true` | +| `.bitcode/v19-contract-change-ledger.json` | `sha256:f4d1620dd7260aa07614d5e321e267dce47a3a5d201b339f7f72ab7ce3dff606` | `sha256:f4d1620dd7260aa07614d5e321e267dce47a3a5d201b339f7f72ab7ce3dff606` | `true` | +| `.bitcode/v19-negative-proof-mutation-matrix.json` | `sha256:22769944b87608505fe6e33186fc948be3a4f91bc887db61462a758689b55331` | `sha256:22769944b87608505fe6e33186fc948be3a4f91bc887db61462a758689b55331` | `true` | +| `.bitcode/v19-proof-member-semantic-matrix.json` | `sha256:13627ebcbd8ea8bb5eeb3bb9d315f04e91e94e071c64b471aa1ea9d66b354e32` | `sha256:13627ebcbd8ea8bb5eeb3bb9d315f04e91e94e071c64b471aa1ea9d66b354e32` | `true` | +| `.bitcode/v19-state-machine-matrix.json` | `sha256:fb31c743b8f9a86f4a996f9590e29f57739c7d2ae50d3c46f9e10d160385cee4` | `sha256:fb31c743b8f9a86f4a996f9590e29f57739c7d2ae50d3c46f9e10d160385cee4` | `true` | +| `.bitcode/v19-theorem-evidence-matrix.json` | `sha256:d73da851088e3bcd6d3ab02aaade229ac87ad3a147cca51c852b9b86a2d23122` | `sha256:d73da851088e3bcd6d3ab02aaade229ac87ad3a147cca51c852b9b86a2d23122` | `true` | +| `.bitcode/v19-volatility-inventory.json` | `sha256:450681dc9040e62e561a8a85202058e623b9e6683f494de2b4b41975a867f51e` | `sha256:450681dc9040e62e561a8a85202058e623b9e6683f494de2b4b41975a867f51e` | `true` | +| `_legacy/ENGI_SPEC_V19_PROVEN.md` | `sha256:636b022333006682441fa0cab82227835d09987b47dff580527067a1b6fdb225` | `sha256:636b022333006682441fa0cab82227835d09987b47dff580527067a1b6fdb225` | `true` | ### V19 Volatility Inventory @@ -139,12 +139,12 @@ | artifactPath | digest | byteLength | | --- | --- | --- | -| `.bitcode/v20-accessibility-report.json` | `sha256:7e4101be2eac723d66184ebf64477ae682eeb801c2a959ebe866998880bca67e` | 8226 | -| `.bitcode/v20-operator-acceptance-transcript.json` | `sha256:eb6f506f5e26272ff8ef77c8db938cee534eed159b92ff8520a4d3e7d6889553` | 10929 | -| `.bitcode/v20-performance-budget-report.json` | `sha256:5cef33fd3836cac6cf0b23ffa297c7c3a3aa56ac4d867ee0b7af5ca21b6380c7` | 5054 | -| `.bitcode/v20-projection-quality-smoke-matrix.json` | `sha256:143bd7c761fafc679e513baedaeb7f66c5030f4eb7338f31329fe23f64013346` | 4951 | -| `.bitcode/v20-quality-summary.json` | `sha256:f52c2fe263c8067d674b7489ac293bc4d6f9d1d3d554f0ef1b6154e6d794c614` | 4480 | -| `.bitcode/v20-visual-regression-report.json` | `sha256:d33cd04d779f4ff62fff9b35927f0047fa780fd1397a346b239a6af90dc8a7fb` | 19385 | +| `.bitcode/v20-accessibility-report.json` | `sha256:4597230d1a891d6fb903712f6d96404febdaf7822ea994fc312384cf79a848eb` | 8210 | +| `.bitcode/v20-operator-acceptance-transcript.json` | `sha256:8205537fa69f17ac1c0dae1c040ebd9173ab1400a662f1a2a5326786d9bb291e` | 10913 | +| `.bitcode/v20-performance-budget-report.json` | `sha256:36c2db76c5acec9e5ee8e9231331a39b10ed7c0f32783a01538192db3b9085df` | 5038 | +| `.bitcode/v20-projection-quality-smoke-matrix.json` | `sha256:3eb1c2fb82a0fba10364fa757ceaac2cb1f56b61e3fe95436a8c089ed294f29e` | 4935 | +| `.bitcode/v20-quality-summary.json` | `sha256:49b42dfc7545d1092115b7e2f74312d584d941b59d1f277a148f15e903ffc381` | 4464 | +| `.bitcode/v20-visual-regression-report.json` | `sha256:217179ce5783460847f2222f7d467de6c196783527a471a6707f46c31503faf4` | 19369 | ### V20 Quality Summary @@ -712,7 +712,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:a08dcb38b21b853afb64378b8872b02e066da3a7a72adfa93c6abfd217c55cfc` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:1c38aa47b7361ce985b48e3da400d880f37290debf70271c34ed3b10fafe72fa` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:098b3934f79eaf77bbd0f72593b3e9d35a83344894d46a09a1c84853f2bc710e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:1acdeef8c14093b5a00c5eeb749869c45e367f0c102bec3394bd7c45ec929fa8` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:6dffe1ba8a565104bba74bcc20255eeaaf2ab87685ef394d16ab62eef57e4a59` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:f5da41a20f3a15375abbe1fdabd2a88239a2a8f637aaf033e8018915a0e9c7eb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:054a9bd14ffbfaf41201b72cde276e6d8d81378c0b4a369360de535f7a4ecb2e` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:0896df3fcc89b27fe7ac491caad0d739503111bdce24e03e8f037937ac2790de` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -743,7 +743,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:9592d38f7281eafa7ac658e48cbf6e35ab44591384bf73dc11e332237160df39` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:0458593a95733b5c411c3cbdfe188bcc394fbfe5811f5deb8e73bb3a83aca630` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:9901fc2c0ead9f1445ec4254fdc9c621f3fd92e413e815b0b8d768fb8ab30f5d` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:62e6b4c6ae434a217568f5b7b32cffae963ccdf95c479c1780ceabc2d41a9d53` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:7fece1f392e3dfa5a553c723f657910dc958fe0aab843ebb0305ee62f373f3c6` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:f6e862d56ff0166f78dd46659332af9cb94f638d39c165b1573dcfb524aed357` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:dff1642ab7d6939c2263360e45775d5e737934200b4dd05740f2aa1d437b26cf` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:433796e9495bb735acb1fd1a916b3e3d212cae22a4bec0ccda69a4ba7b538620` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -837,7 +837,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:cb89d3a06d4b07b5e70012ed8ad97838ee36e9689232913f9a86f1228dfe91cc` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:a077681f046fbb925c387550b5a8df129bfb602c74b0a482699ff28c8dcf6fac` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:ff2d9cec42dd2f31397e5bc8de46cffd9f53379230391b865468c27e8354122d` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:4585aad198e138fc78f9135fee9cfee97382e6077c47984b8c80db785172bb28` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:085592107e68aef0aba229e845f54dc862b32f28ebdced5598a5ba417c37ba3e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:588c76e7d32b2409990e39ad16946c59d6cf15db87d451f043f2a194cdd56dbb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:054a9bd14ffbfaf41201b72cde276e6d8d81378c0b4a369360de535f7a4ecb2e` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:ac206af0e4758da5b5b9b75d0972dee99057ce5f0694e7d84428c1e132f0d11c` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -868,7 +868,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:e5d0ddd164f244e7747c498ab9ebebd58c9bbc881a38786fc3185a6a47f27cf6` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:ecbd5a7070f28dda086bce15a4dde9516694e604b5a5813f0f17e85a2adefede` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:9901fc2c0ead9f1445ec4254fdc9c621f3fd92e413e815b0b8d768fb8ab30f5d` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:fd7fbdfc94ac24665c6f9ef031aaaa4d2ce5bc2e53869c9651d037a6dddde512` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:ebea4c0d8e0c76468c41d1e0973e9bdbca4a5bdc1b2d1ed5c6084a2f8f384685` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:38d3d641821f37594d0ee5dd779048826440a417be4faedfaa1c0273a9aafd83` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:bfa3f543a1f69577e855dc7432c5325b4b0be48a90890a1019559509f677af7f` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:d82bd7f5eef9645e375b456c1a159320b5b3c6d2cac1826c14e45d74098250d6` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -962,7 +962,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:954f6fe05a26bb44a1f65602fb4a23d8b88571c3453cd0ed215c45963766a83b` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:f62b272e830007b203ceff28d5b8bc0fd395e9da882d1e594174a9082a434dfc` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:54673ee8002b9b47cdf6543c747ea377da8d7a2f4b16672a7d3f1cd01cd08acb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:9c7af812b1bcb7516c38c90fd583b05d5cd66d5892985f87832e940eb44368f9` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:68ac31232216497bc1ef6d588d0dcd8c2e7461a10fa569025b392e8cfa38e436` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:03329a4920190ad468ca25efb3ca0848cac25529e67e23273f2b6126ea7b126d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:9be5dad921d2f261390a9b2fa5b46eb84cd82439e38cc1c3e49693d9820b0619` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:6d730db590e80e5b9070d41dc88dfa2a83ec00050ee9bd976eb63c221fded753` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -993,7 +993,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:0832ded750cdd02c6465643c4472466116da0c4543272bbcad7040e9ac166dee` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:3f7148afee2a0b067968500edbdc812560dbc5936fae54b6558474ac8a4687d9` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:ea8daa50baf855ebc90a9ce32cba0f9063d02f165f0badee508fb646b673e6c7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:5c60549653c64864562e650cd68bf6d8ffd188a8bed651d9a90d4fb7cc49c0ee` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:cdb924642b78d7ec5eeb3559a132afb0a2f2ae065fb868aacf3b340ac212941e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:2d9c02287ce036d3f03f9a47e18c617a933e3797d06f5309431e3a4c52eb8d0e` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:56d9507dd0e963d4c9391523388f28f105c1414c49cea88e0047aade1298663d` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:7b1b9bb523ffbadf3fe64cffd26bec00e2d6fd6c17aa068d933c5371237b4e0e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -1087,7 +1087,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:aa38f0352b0b25daa0bb120f6ec6bba92ad433f14fdbb522171f11e24add092d` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:10a58df1e6f48dcdf09098f83021c983c8bfe3c17173dc79b4a9e73e3fd96258` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:54673ee8002b9b47cdf6543c747ea377da8d7a2f4b16672a7d3f1cd01cd08acb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:9c7af812b1bcb7516c38c90fd583b05d5cd66d5892985f87832e940eb44368f9` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:68ac31232216497bc1ef6d588d0dcd8c2e7461a10fa569025b392e8cfa38e436` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:7bd6a0865e9267411b854f91754b10dc446d1b20375009a3099e670933eab4fb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:9be5dad921d2f261390a9b2fa5b46eb84cd82439e38cc1c3e49693d9820b0619` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:2fbb1f37244e7d0a1e313cfbe7f24e1cd88a6059bea1efe553030c45f3d31d24` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -1118,7 +1118,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:fae43adb9a288eabaf5946221c0715414693f6cf144b78fd3b6a8b43fe4b54ab` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:3f7148afee2a0b067968500edbdc812560dbc5936fae54b6558474ac8a4687d9` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:ea8daa50baf855ebc90a9ce32cba0f9063d02f165f0badee508fb646b673e6c7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:5c60549653c64864562e650cd68bf6d8ffd188a8bed651d9a90d4fb7cc49c0ee` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:cdb924642b78d7ec5eeb3559a132afb0a2f2ae065fb868aacf3b340ac212941e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:ca40d86f416da0c66700f1a3ca2dc6651a16ce69276bda6c0c081987edd67c39` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:25dca8a8160905ae58f03c40b3e12dfc364ffde6092510d80df425313a973380` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:faa095740f49cc6fcf3378253dd0e6416df8b6c3e9bb655c0acd1ac3c3ea2fd3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -1212,7 +1212,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:acd148ad1e066d9d770424e43c377e9e516aedab81942860b14da52311d0dc4e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:8b08e9c366913f1acc0fc80e40c4031756e21361ca5d502c15676c6e9aaf07f9` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:1ef6377e7a3c393fe2fc43f8a9b54f24904631c887e365200062f87c720d08d4` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:91869ba61a06e71b4a0c8b430851ec4be13b56f1a48a5b2acabceca62a690ca9` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:0eb817297102e7187000fb4807c3ca1fd46a3df4795ea9cdb3c10c5000f7972a` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:f4ea54ea40d36968ee1f9f3cf6938f04df6f448f98b4f5acad7a015bfed90ed8` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:46c77dccc38b3630e07c447f4b225e623dbf31b5ecc980da11f07dd8b33a975f` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:43693ee69ddeef8ddbf2fb1059065789e6112ca8afa015368d31bdd12ec08c95` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -1243,7 +1243,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:cef9aa43641f124d922603a162b931dcf0c616ce487316b777cdc29b976f03ed` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:501307fda8ba5ca845f985e7c2857595abc67ce54037f07ffa384080d45ca725` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:fdd7c9f7f92d31fd298f5a2259959d8f8e9b0cb1ce754e5d4a5a84aba4aa196b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:e3d46ecde5251218d94eec6efa209db2ebd7d2e1e5961b19fe07f2d1990292f7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:12a3a2efe7d7fa22d856c49ed9f5458da0683e6eded97bddb3da86a7f05e7e75` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:d4b23a10fd81910d3ec2b5a0b275f4507b4146685e3a833c94c2623970b5e49b` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:419448fbe69f2f592f7cdd64ebfb2f91d115670b389db2b0116cae60d0186036` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:b171b6c6807c2d2e6d94fd0565a9bed9c9963572c963aebe2ffc70453fcea25d` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -1337,7 +1337,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:95b45ae9eb9536bbfee549a496b4063a1be139c0c7afb6c793c4e2cb78d94012` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:4327385821b6c9f534039e1493494702105307e978a3b06fb3403794861f541f` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:1ef6377e7a3c393fe2fc43f8a9b54f24904631c887e365200062f87c720d08d4` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:91869ba61a06e71b4a0c8b430851ec4be13b56f1a48a5b2acabceca62a690ca9` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:0eb817297102e7187000fb4807c3ca1fd46a3df4795ea9cdb3c10c5000f7972a` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:74c8e4cf02f637a9e6dc48854666992a91f6402dd5f80b2f31bfe483df9ef71c` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:46c77dccc38b3630e07c447f4b225e623dbf31b5ecc980da11f07dd8b33a975f` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:5610c4975fb289b3909932d3f5b53a7032b7a2507f60ec1b69079cb50f84dbf8` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -1368,7 +1368,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:5effc18dd1f65e1188616aa32cf8e4dc3a8a06bdd3eb95cc2e04341d166fca65` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:501307fda8ba5ca845f985e7c2857595abc67ce54037f07ffa384080d45ca725` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:fdd7c9f7f92d31fd298f5a2259959d8f8e9b0cb1ce754e5d4a5a84aba4aa196b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:e3d46ecde5251218d94eec6efa209db2ebd7d2e1e5961b19fe07f2d1990292f7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:12a3a2efe7d7fa22d856c49ed9f5458da0683e6eded97bddb3da86a7f05e7e75` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:9d143e66aa4753576e168a51b6c81203c7f90154f8762c493a1d7e3e914f8c56` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:b4f48f36750bb8e789199080421c4a051dadf37bc0519ca0738c263961d0afc3` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:93619dac9545954b993d6058012a17d6b6a87d961cf68699492f29d5bfc7cb89` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -1462,7 +1462,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:211dcb4811d83b8ebc24e5c11af5fc09afb3c84e51c7d19b9f991fb7e7c81cdc` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:cdf13e57999ee55469779a4e1e2872709b99b67bf725465dc7a70ced3651cb4a` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:2260487892adf8f4485b3d2e93477abe006715da4c6b703f30d76a57e028a12c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:861d18b39f610b546a4844c2088add0be5d7ff4c72eece611e1535da52eb3d0b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:1eb50492d5b49bb8d712dc95ced1b4218445af1dbde94bc53c6275db2720421c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:4c34cfb8e09abc3fea234130d5e22306e4384e7e02b72d10c38ed4e6a48f9ed6` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:fcf95143cf39d8b2e5adc6b3946dfecebfad11037cf136640f4ec5bc790ebf1c` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:45acb0a245c588240d0e9198a27e3ffa3a65362869d56727eb807343e4e36413` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -1493,7 +1493,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:fcc2ca2a8cb1a47c046d4cb66e6cce5bda0205778c6ab6e262d3be2cf5871816` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:6d85aaed7d0cf7270dc0b1a3f44b04df5487492cb02b8165e63c08e7efc38a7e` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:5cf464309b76a143cbf7a6aa7809b3ba933be40f9d5f216b525853ab6cfc675b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:eac0966d247f59693d31f91541d7f2874f5189ca831591199aedbd9b83af9fed` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:2635f2b71717b88088e7f8b3e8e3ec19bce99c7d6d00d0e84f9c2bb4719639ee` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:02cc19fd505fa15604a7ef08ef0c8ec020ffab6bb6dd32482e70392023aae9c9` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:19433854367ec23425e38e1b53936787abe6160b52cd15ee32bb7e9c42ebad69` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:1e847396743898e5595e7e509eec458e430bedb888294df628c18ced2ed39ec5` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -1587,7 +1587,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:aedd512b38435c2c8788db85a80e13b2b3fc29417c12b244ad61101af9ba8b60` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:10fb949ac86f2c3234beeb4453c01b73de4a46c1413ccc83edcb9dff1074df5a` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:2260487892adf8f4485b3d2e93477abe006715da4c6b703f30d76a57e028a12c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:861d18b39f610b546a4844c2088add0be5d7ff4c72eece611e1535da52eb3d0b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:1eb50492d5b49bb8d712dc95ced1b4218445af1dbde94bc53c6275db2720421c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:3920104b24531e329948f80b2d900fc98cfc42698d4ac1fa0e7286df74a5e01d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:fcf95143cf39d8b2e5adc6b3946dfecebfad11037cf136640f4ec5bc790ebf1c` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:1821843556aeb7ea7924f52129b0e00e9e7c35a7795f842947bde87b9120b743` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -1618,7 +1618,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:f6abbdaf4249320486a9fd70d316ab1edda52b764cc4242f0136c40efa30ef27` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:6d85aaed7d0cf7270dc0b1a3f44b04df5487492cb02b8165e63c08e7efc38a7e` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:5cf464309b76a143cbf7a6aa7809b3ba933be40f9d5f216b525853ab6cfc675b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:eac0966d247f59693d31f91541d7f2874f5189ca831591199aedbd9b83af9fed` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:2635f2b71717b88088e7f8b3e8e3ec19bce99c7d6d00d0e84f9c2bb4719639ee` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:5ce74f215f9d60e8005345240f4ece14b01bf4d68cca0e452e66f69fea4a77c9` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:6ca0519ff7c12cc846645d1b0340688b7cd5391f185dfc67584a325f853cfc01` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:5aaca53542865b3794065212b504d1c0901e2b805b44aed4934c50a66b7e6a2d` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -1712,7 +1712,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:e6eb896b77c9fb159e64a9e29533a7c305055e01a579aeae6efbbb42bef72b77` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:d4d3e9495263cb92a69fddd0f7edb72c63c7c303c4cb5535f352ec51604959e8` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:2c1624cf684ae0a83834d9c7a28789d966ff776e1c61c5fbb611b5d73392547c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:7b13703fa960cd2cf144e019b6e8cd541fcb82971617d39a5efa55ce5fee4a48` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:3b59025b29bd0eb0af657dc93de4f408a6229dd75c6d885848fbc42c168c3ff3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:af3e0c2cb3148443ca9f967906fa079cade336b39bbd36b05e6f031353dc0715` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:40ae2a0b1f3a8f3370377819b744468030b79949a618759e65ece60795cead87` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:5bde14deb75ac18013f2f69e21112f774c1d4322a93489e95c3919c7a967f7d5` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -1743,7 +1743,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:a8f038138ceed6859020675d71736cdba5a587e6b48ddb29133db3011ef74d52` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:b0acbf48dbd4c5a4202a8683fc011822c96f6d7c566fd287412d544f7de1b4be` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:8f1970d50b815044e763d8f192ab7269689ea0b3916334f534df680e4b3eed57` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:7ecd2a609dd792ae261d77cb4700c2651625b713f8f9591bddb655cdf4c46d41` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:a3fd19721244d6a2d82e7c0deb26126a95aa07369314b8638e8a67c4a7bd8763` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:aef45c4332d64546c4ae0c94af83be2384f25ba49770b025c5bf85e40b82d71f` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:7cafe2b41af74f6a20eb15346a5100fcdb9026530df8386fc049bb792c3e9030` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:30518f8d5444b646771c961b268999103b5bd54a9a1438ff50d1813931edad56` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -1837,7 +1837,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:7d34b19c9298cfe043e5ab0096e5766e839444a3027c806efd64f115e98a38b9` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:8c81abd46de1f27dccd1607ef96d0fdd79f0f64d6436918478e6872d010660f1` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:2c1624cf684ae0a83834d9c7a28789d966ff776e1c61c5fbb611b5d73392547c` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:7b13703fa960cd2cf144e019b6e8cd541fcb82971617d39a5efa55ce5fee4a48` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:3b59025b29bd0eb0af657dc93de4f408a6229dd75c6d885848fbc42c168c3ff3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:0ee4bbf7e89b96f7249da804ad174d47b8ed2133ca5ee6d533b080eafdeca75d` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:40ae2a0b1f3a8f3370377819b744468030b79949a618759e65ece60795cead87` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:7f7de72b8b776f3b6b5250fb88ebb9efff0c3c67ba93043fc3efc63d507ea0a6` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -1868,7 +1868,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:4ed2198c3827ebb995f8a02e140884f55fc4af51746f586804533a0bcc7f6904` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:b0acbf48dbd4c5a4202a8683fc011822c96f6d7c566fd287412d544f7de1b4be` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:8f1970d50b815044e763d8f192ab7269689ea0b3916334f534df680e4b3eed57` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:7ecd2a609dd792ae261d77cb4700c2651625b713f8f9591bddb655cdf4c46d41` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:a3fd19721244d6a2d82e7c0deb26126a95aa07369314b8638e8a67c4a7bd8763` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:7ad6bd3fd130367f088328db7f66846195082ec030bda9f4a9b5efa3ab04c7d2` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:0a31a8bd83ab1d4b208f31790940e2fed1c7ecedda8e3b904fb25b0824fdbbb5` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:e5fdec8d3f9cc0ae660fede823a31ffdddab96b3b2fdb808738bc2385ba59d0a` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -1962,7 +1962,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:880417de4a0cbaa4d2f42bc0b11ab35ae6f10df26bf243dd13eaac365485aacf` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:e37a1973ff0ecb2bfff26028905d753286e6ce17c636cc944775ed6628a1bec2` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:d0a68ad68adbab5b801152274edbd5e7914f9172858603b62f2b16ba47c23c8b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:c7d8fb99bff075054c3d7512abc6b7e4302655afeaf8591f8f1702c2cf50eb7e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:c77737c5ba485c2f28e4d4af02668db391ffe2e3a9f6a0ec74986cbb03cff004` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:f7c3eaa6764f14eeee4e24e7692dfa16936c6051f3fb3f30a3464aad5ddaeca8` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:2e3fe016971d44f9df40986e81e57c0d8aabfd3e4d7c1fb71a8b91883a0af3a6` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:f19ba812efd8d9010544988cbf24396d069b1996f6e96d3414278422ca581d3f` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -1993,7 +1993,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:9c75d8e790d30a067d1eebbd604bacf8be0ddab8a1b121e9b71f7e4fd1871ec3` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:d2bb74466474b95020ef27ac13ab2978c4b4fe1d19cb41146414f38dfca8200b` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:51a841a7255f59929dbd350752437fd41a64b9fd512ffb10dbdf090b0652ab6a` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:3bf3098a83de9331a2e8dbcb5679f27fb61438e6d30a71b94d490680074196a3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:b11d22b49cb2d1dd113e565569e8094b52a707d69b22ef70c05d0a71202429d7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:a5c163e62bec0a1d0942a3cc1e1ee9fa69810e3a443ae937b2148f65b0b957c9` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:d7ccac088cc1d6f442e6c2643b56b1f3a4116c4ecee5bb0d5b5cd3d813d08f5b` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:2de06d0d907c63f24a43fa2c28e1e12c5ab2a83003ced5b4db19f49743aa0787` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -2087,7 +2087,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:04ba8c7c86a5d011ed124447ba82e47b05c3eedc12dfcc68371b1da4158857b9` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:8b16f037f1078be1cef6650dac42752e414afc52f680fa3e5fd0ebd603cbc054` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:d0a68ad68adbab5b801152274edbd5e7914f9172858603b62f2b16ba47c23c8b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:c7d8fb99bff075054c3d7512abc6b7e4302655afeaf8591f8f1702c2cf50eb7e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:c77737c5ba485c2f28e4d4af02668db391ffe2e3a9f6a0ec74986cbb03cff004` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:49f8db175b8e0b080dbf8b99c35eab571742c0cd9047e213bfc29195d006ed34` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:2e3fe016971d44f9df40986e81e57c0d8aabfd3e4d7c1fb71a8b91883a0af3a6` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:25b1de6de0319574567b9345d304adc2bbf7626fd606391213062744b1690f8f` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -2118,7 +2118,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:62345c3c0528519a4ba2ee002df3c4e5a5c37895bfb80dcf9e20b064f6a5d6aa` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:d2bb74466474b95020ef27ac13ab2978c4b4fe1d19cb41146414f38dfca8200b` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:51a841a7255f59929dbd350752437fd41a64b9fd512ffb10dbdf090b0652ab6a` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:3bf3098a83de9331a2e8dbcb5679f27fb61438e6d30a71b94d490680074196a3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:b11d22b49cb2d1dd113e565569e8094b52a707d69b22ef70c05d0a71202429d7` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:6a812e4e668d8ef1fc28ad2f8d8ee77da8bafdd71c54845f8d702891f283bc40` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:926c1aab017318fa8511f4790233f5658cf37dfa6455266d42aac2bb2867205e` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:712dae63457f735eb11c24d036d7a93c3e8c93ec20a7e0d686ec4391979889d3` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -2212,7 +2212,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:8d90f117e89ca5fd018f3ceb01de869a40618cc0676cbe6b7f7b8b60f514bb66` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:6870d6756abb2632fa4d124c1d23d46c54fd59f1f06b9a0c9bf92d9d2ad7d794` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:8c6a898ee8e19a41a8f8399f98c61b80362ac20513ecd53dae26950fcae6e772` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:49e433b9666092c67dad59625bb8fcfed68c299d2b355308b23177ec05ff8709` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:165b49b885290310e7a8ad75d583ea35db4d01ecf9023d9a08e2250b71125d57` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:15f24a288cbf0de131137d9d96db7322a1e08fbd1a97bb987d5b63e8589693eb` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:36ecea7e7c6932111c192bc6f0843164d0209d691ac3423c98c6b66d033472b4` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:46424cedd179cc2e3248e7a9360316513092e0223703b917fdbaae180a9badb0` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -2243,7 +2243,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:c08c6baf9c335ea6d9f771efde006ff8577953196a2bab6b9acace0521350189` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:c1e577b132475f4b327b593f0ec0052f8bb6668c7efad0693bfdc79debd96f2c` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:7cd7e52ebfbe66f7b7fedc9100e7803f6823a28488837f408ce98b076987d75b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:b2cd7f6fa99d77557dee345e686958fd0d52ee5e82e4549c241e4ec91fe0fcea` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:42c7b801b8f1208eb7438615e306e8d847a1772c474596145a45cd795863347e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:16d764b15028c1c70d2b1b023f0007ae9082c9673a8f2d606a58b2d5c9cf313e` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:bb7194024cad19cc03abf7ef89fe672a990be8dd6a25b8e34ce3fc8830958a7e` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:623ae942a593bb129e3c864ca3d1a4975290493197f6c86cc86d69c80a45fb0e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -2337,7 +2337,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:a3cbf9297ffd5abaf253fc9ab4f7ebcb5f7d21f0ae8077d66292de6c59773528` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:e3118a3a34b3348834b504893014d99748974a6498b9bb6a3ef439f294aa7e9b` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:8c6a898ee8e19a41a8f8399f98c61b80362ac20513ecd53dae26950fcae6e772` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:49e433b9666092c67dad59625bb8fcfed68c299d2b355308b23177ec05ff8709` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:165b49b885290310e7a8ad75d583ea35db4d01ecf9023d9a08e2250b71125d57` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:f96900f0e7fee9f34ff255f1bd686f4d0332e055bb170604c4da7eaf9ff45130` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:36ecea7e7c6932111c192bc6f0843164d0209d691ac3423c98c6b66d033472b4` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:e47ecbea6d5fe25f3bcb908905403927e553c9c4c01063b58a2a4cf7b5e154ac` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -2368,7 +2368,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:64713d43c3cf4ffe06599dd9a3571e5ba55636fd3a2fca591dc507c476edf424` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:c1e577b132475f4b327b593f0ec0052f8bb6668c7efad0693bfdc79debd96f2c` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:7cd7e52ebfbe66f7b7fedc9100e7803f6823a28488837f408ce98b076987d75b` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:b2cd7f6fa99d77557dee345e686958fd0d52ee5e82e4549c241e4ec91fe0fcea` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:42c7b801b8f1208eb7438615e306e8d847a1772c474596145a45cd795863347e` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:8be23f5f1875a101ba6de6aa6ef5beaf82b2d5b88eb2ef06f2a6dff714a3e6bf` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:0dfd94e5a9e486386b9fb81e4973951b070993b66a3cdd7a2b8631899a569454` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:638d67a9b5409f737dc0070b57ea7070006e49afbc17020f515f5093ae37b27e` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -2462,7 +2462,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:c487b54c19633f825bba257c5fbc803c2411cb9826ba760fc721436fc8c1ac99` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:213eb10dd78b5eda96564d25f7f2e66519a5f2deaf3956328d370c3f53607a7b` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:9958392c28c4be80006c2bb33b353601ac820b5b635544a0ecdfb672629535e1` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:5752b43201ea449f504a9f7d64dcd38aa83c897b15be57b3e533cc1e2aad66ff` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:4875bbbf33fd65b41583114bc2e1c041116335b2de62106597f7604755c59848` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:e74ce71b622f8a4351bf789598fb2422993e0f52d8cb57b7ec3857c841f461ec` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:59707e32027d24dc82bb1e3c6a16ceef0cd84fd3471c9fa2c37a6d090b13de7b` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:93a6ae4d4886dea6ad89f294965b4980be1e971839a80510bf75c669a86f207e` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -2493,7 +2493,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:93443b0becdeebae98f5e288352518435faff73ab467b341fad0bd038eceefbc` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:3bfc16906769f2d1c0ed837a29f95a1b94589171a4aa0fed584ce85434742659` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:8e6cb9e1a5f53b05188964fc477ed3dc9cb246a3bfbaa57690cd38ad833b4dcb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:05d019692f2686ea0f5baa78bcc2c1ff4a466c28885b88332a9fb09f9fe004d3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:00ca6388fd0c6fe3347cad21fd4b9b96803f512dfa0f83d2bb16e1d7d03590d5` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:85562bd4e401bc83d714a4da40234b3b03e6fc34157cb4f2ba4185646febcf6f` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:e0331346702d3904ffafc0e1f0d82d7ef6c7afec8dc415f92d553729d68a02e8` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:dece620c1dd99b204862c8372a376e01fb46c9da7c988732582c2bb1ed0b7e32` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | @@ -2587,7 +2587,7 @@ | `.bitcode/accounting-precision-report.json` | `sha256:9c0f5287e2cc4af88889d02d72d1d34a127745dfbfc02c47d59bd55a37478e11` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/asset-pack.lock.json` | `sha256:967d39cbb5233e24d1e4ced45f3ad715d396afc47ea21cc06f0eee81df1996d2` | `selection-and-materialization`, `settlement-source-to-shares` | `private-proof-artifact` | `false` | | `.bitcode/authorization-and-sensitive-flow-proof.json` | `sha256:9958392c28c4be80006c2bb33b353601ac820b5b635544a0ecdfb672629535e1` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/authorization-decisions.json` | `sha256:5752b43201ea449f504a9f7d64dcd38aa83c897b15be57b3e533cc1e2aad66ff` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/authorization-decisions.json` | `sha256:4875bbbf33fd65b41583114bc2e1c041116335b2de62106597f7604755c59848` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/bounded-public-proof.json` | `sha256:faa5bed0f9cd0e812aee5a69e3f21ac975f21e29e57eca1200f53636b2d20093` | `disclosure-boundary` | `bounded-public-proof-metadata` | `true` | | `.bitcode/code-analysis-fact-registry.json` | `sha256:59707e32027d24dc82bb1e3c6a16ceef0cd84fd3471c9fa2c37a6d090b13de7b` | `static-code-analysis` | `bounded-public-proof-metadata` | `true` | | `.bitcode/disclosure-boundary-proof.json` | `sha256:d4ecd4fa6a549fec13e5514cc6960b24afaaf385e312f2c6ae3c2280e5417584` | `disclosure-boundary` | `private-proof-artifact` | `false` | @@ -2618,7 +2618,7 @@ | `.bitcode/selection-and-materialization-proof.json` | `sha256:44178db54efb33b972cd2e6cff2159b7d6c03cfc69901fa81a47ade8ef1b3e9b` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/selection-consistency-proof.json` | `sha256:3bfc16906769f2d1c0ed837a29f95a1b94589171a4aa0fed584ce85434742659` | `selection-and-materialization` | `private-proof-artifact` | `false` | | `.bitcode/sensitive-data-flow-proof.json` | `sha256:8e6cb9e1a5f53b05188964fc477ed3dc9cb246a3bfbaa57690cd38ad833b4dcb` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | -| `.bitcode/sensitive-data-flow.json` | `sha256:05d019692f2686ea0f5baa78bcc2c1ff4a466c28885b88332a9fb09f9fe004d3` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | +| `.bitcode/sensitive-data-flow.json` | `sha256:00ca6388fd0c6fe3347cad21fd4b9b96803f512dfa0f83d2bb16e1d7d03590d5` | `authorization-and-sensitive-flow` | `private-proof-artifact` | `false` | | `.bitcode/settlement-participation.json` | `sha256:b23dd79a34d7fb37ff0884e0d475413c5760303d27525501c00069415a280588` | `settlement-source-to-shares` | `settlement-preview` | `false` | | `.bitcode/settlement-preview.json` | `sha256:a9f661b49799f2c6bf9a3460452a72681d8bf9c899de68b97f1cff085b355f3d` | `settlement-source-to-shares`, `bitcoin-settlement-interface` | `settlement-preview` | `false` | | `.bitcode/settlement-proof.json` | `sha256:afa5aa92da369956610e7ffd1a0e01aa7bba9732775d56a65f4cdfcef41e1ce9` | `settlement-source-to-shares` | `private-proof-artifact` | `false` | diff --git a/packages/protocol/README.md b/packages/protocol/README.md index b1ce61b71..8f806d9f1 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -15,7 +15,7 @@ inventories, but it is not a commercial runtime implementation dependency. Current exported commercial helpers include: -- active/draft canon posture (`V29` active, `V30` draft); +- active/draft canon posture (`V30` active, `V31` draft after V30 promotion); - spec-family and canonical-input validation helpers; - canon-posture drift reporting; - canonical proven-generation helpers; @@ -25,7 +25,7 @@ This is the `V29` active, `V30` draft after V29 promotion posture accepted by V29 Gate 10. V30 Gate 1 treats this package as promotion-critical runtime posture. `packages/protocol/src/canon-posture.js` and `packages/protocol/data/state.json` -must remain aligned to `V29` active, `V30` draft until V30 promotion. +must remain aligned to `V30` active, `V31` draft after promotion. V30 Gate 10 promotes this package posture by rewriting those same runtime carriers to `V30` active, `V31` draft and regenerating the V30 generated appendix plus `.bitcode/v30-*` promotion artifacts. diff --git a/packages/protocol/data/state.json b/packages/protocol/data/state.json index dfaf976ea..c7e88901d 100644 --- a/packages/protocol/data/state.json +++ b/packages/protocol/data/state.json @@ -1,18 +1,18 @@ { "version": 3, - "specVersion": "Bitcode Spec V29 active canon / V30 system draft", + "specVersion": "Bitcode Spec V30 active canon / V31 system draft", "canonPosture": { - "activeCanonVersion": "V29", - "draftTargetVersion": "V30", - "operatorLabel": "V29 active canon / V30 system draft", - "specVersionLabel": "Bitcode Spec V29 active canon / V30 system draft", + "activeCanonVersion": "V30", + "draftTargetVersion": "V31", + "operatorLabel": "V30 active canon / V31 system draft", + "specVersionLabel": "Bitcode Spec V30 active canon / V31 system draft", "documentTitle": "Bitcode Demonstration", - "policyRef": "policy://bitcode/spec-v29-active-v30-system-draft/current", - "activeProvenAppendixPath": "BITCODE_SPEC_V29_PROVEN.md", - "draftSpecPath": "BITCODE_SPEC_V30.md", - "draftDeltaPath": "BITCODE_SPEC_V30_DELTA.md", - "draftParityPath": "BITCODE_SPEC_V30_PARITY_MATRIX.md", - "inheritedCanonSurfaceLabel": "V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27/V28", + "policyRef": "policy://bitcode/spec-v30-active-v31-system-draft/current", + "activeProvenAppendixPath": "BITCODE_SPEC_V30_PROVEN.md", + "draftSpecPath": "BITCODE_SPEC_V31.md", + "draftDeltaPath": "BITCODE_SPEC_V31_DELTA.md", + "draftParityPath": "BITCODE_SPEC_V31_PARITY_MATRIX.md", + "inheritedCanonSurfaceLabel": "V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27/V28/V29", "heroEyebrow": "Bitcode transactions and activity", "heroLede": "Set the active scenario, select supply, and follow the flow from deposit through settlement.", "heroTip": "Use the guide and lower runtime surfaces when you read exact replay, proof, or settlement detail." diff --git a/packages/protocol/src/canon-posture.js b/packages/protocol/src/canon-posture.js index 61a66bc27..3349b1577 100644 --- a/packages/protocol/src/canon-posture.js +++ b/packages/protocol/src/canon-posture.js @@ -1,7 +1,7 @@ // @ts-check -export const ACTIVE_CANON_VERSION = 'V29'; -export const DRAFT_TARGET_VERSION = 'V30'; +export const ACTIVE_CANON_VERSION = 'V30'; +export const DRAFT_TARGET_VERSION = 'V31'; export const CURRENT_CANON_OPERATOR_LABEL = `${ACTIVE_CANON_VERSION} active canon / ${DRAFT_TARGET_VERSION} system draft`; /** @@ -48,7 +48,7 @@ export function buildCanonPosture() { draftSpecPath: DRAFT_SPEC_PATH, draftDeltaPath: DRAFT_DELTA_PATH, draftParityPath: DRAFT_PARITY_PATH, - inheritedCanonSurfaceLabel: 'V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27/V28', + inheritedCanonSurfaceLabel: 'V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27/V28/V29', heroEyebrow: `${CURRENT_PROJECT_LABEL} transactions and activity`, heroLede: 'Set the active scenario, select supply, and follow the flow from deposit through settlement.', heroTip: 'Use the guide and lower runtime surfaces when you read exact replay, proof, or settlement detail.' diff --git a/protocol-demonstration/README.md b/protocol-demonstration/README.md index 71abc228f..073d11418 100644 --- a/protocol-demonstration/README.md +++ b/protocol-demonstration/README.md @@ -1,14 +1,12 @@ -# Bitcode Protocol Demonstration - V29 canonical deterministic local prototype +# Bitcode Protocol Demonstration - V30 canonical deterministic local prototype This package is the deterministic demonstration of Bitcode. Within this package the correct name is demonstration. `BITCODE_SPEC.txt` is the canonical pointer for active-system work. It currently -resolves to `V29`; V30 is the active draft target for Protocol/BTD hardening. -`BITCODE_SPEC.txt -> V29`. -This demo is governed by the active V29 canonical spec and -`BITCODE_SPEC_V29_PROVEN.md` as the current generated appendix while V30 draft -work proceeds outside the demonstration runtime boundary. +resolves to `V30`; V31 is the next draft target after this promotion. +`BITCODE_SPEC.txt -> V30`. This demo is governed by the active V30 canonical +spec and `BITCODE_SPEC_V30_PROVEN.md` as the current generated appendix. ## What This Demonstration Carries diff --git a/protocol-demonstration/src/canon-posture.js b/protocol-demonstration/src/canon-posture.js index 61a66bc27..3349b1577 100644 --- a/protocol-demonstration/src/canon-posture.js +++ b/protocol-demonstration/src/canon-posture.js @@ -1,7 +1,7 @@ // @ts-check -export const ACTIVE_CANON_VERSION = 'V29'; -export const DRAFT_TARGET_VERSION = 'V30'; +export const ACTIVE_CANON_VERSION = 'V30'; +export const DRAFT_TARGET_VERSION = 'V31'; export const CURRENT_CANON_OPERATOR_LABEL = `${ACTIVE_CANON_VERSION} active canon / ${DRAFT_TARGET_VERSION} system draft`; /** @@ -48,7 +48,7 @@ export function buildCanonPosture() { draftSpecPath: DRAFT_SPEC_PATH, draftDeltaPath: DRAFT_DELTA_PATH, draftParityPath: DRAFT_PARITY_PATH, - inheritedCanonSurfaceLabel: 'V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27/V28', + inheritedCanonSurfaceLabel: 'V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27/V28/V29', heroEyebrow: `${CURRENT_PROJECT_LABEL} transactions and activity`, heroLede: 'Set the active scenario, select supply, and follow the flow from deposit through settlement.', heroTip: 'Use the guide and lower runtime surfaces when you read exact replay, proof, or settlement detail.'