From 3df65099590eef3a09b52ed0b4b4e4fb426b6275 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Wed, 20 May 2026 12:57:18 -0300 Subject: [PATCH 01/18] Open V29 objectives and gate plan Opens the V29 draft specification family, retargets draft-quality checks to V28/V29 posture, and adds the V29 Gate 1 checker. --- .github/workflows/bitcode-canon-quality.yml | 17 +- .github/workflows/bitcode-gate-quality.yml | 17 +- BITCODE_SPEC_V29.md | 633 ++++++++++++++++++ BITCODE_SPEC_V29_DELTA.md | 118 ++++ BITCODE_SPEC_V29_NOTES.md | 116 ++-- BITCODE_SPEC_V29_PARITY_MATRIX.md | 94 +++ README.md | 42 +- package.json | 1 + .../test/v21-specifying.test.js | 2 +- scripts/check-bitcode-pre-commit.mjs | 4 +- .../check-v29-gate1-objectives-and-gating.mjs | 177 +++++ 11 files changed, 1138 insertions(+), 83 deletions(-) create mode 100644 BITCODE_SPEC_V29.md create mode 100644 BITCODE_SPEC_V29_DELTA.md create mode 100644 BITCODE_SPEC_V29_PARITY_MATRIX.md create mode 100644 scripts/check-v29-gate1-objectives-and-gating.mjs diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index 920e72e6e..f8e889e6c 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -20,11 +20,12 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Validate active canon and V28 draft posture + - name: Validate active canon and V29 draft posture run: | - node scripts/check-bitcode-canonical-inputs.mjs --current-target V27 - node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V27 --draft-target V28 - node scripts/check-bitcode-spec-family.mjs --version V28 --mode draft --current-target V27 + node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29 + node scripts/check-bitcode-spec-family.mjs --version V28 --mode promoted --current-target V28 + node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 bitcode-demonstration-mvp: name: Bitcode Demonstration MVP @@ -53,13 +54,13 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Run V28 strict draft conformance for spec-title changes + - name: Run V29 strict draft conformance for spec-title changes run: | case "$SPEC_TITLE" in - spec:\ V28*|spec:\ v28*) - node scripts/check-bitcode-spec-family.mjs --version V28 --mode draft --current-target V27 + spec:\ V29*|spec:\ v29*) + node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 ;; *) - echo "Skipping strict spec-title conformance; title is not a V28 spec change." + echo "Skipping strict spec-title conformance; title is not a V29 spec change." ;; esac diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 992ad80fd..f5c2d03d7 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -40,17 +40,12 @@ jobs: - name: Validate draft canon posture run: | - test "$(cat BITCODE_SPEC.txt)" = "V27" - node scripts/check-bitcode-spec-family.mjs --version V28 --mode draft --current-target V27 - node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V27 --draft-target V28 - node scripts/check-bitcode-canonical-inputs.mjs --current-target V27 - node scripts/check-v28-metadevelopment-readiness.mjs --skip-branch-check - node scripts/check-v28-gate9-depository-evidence.mjs - node scripts/check-v28-gate10-read-need-comprehension.mjs - node scripts/check-v28-gate11-read-fits-finding-preview.mjs - node scripts/check-v28-gate12-settlement-rights-delivery.mjs - node scripts/check-v28-gate13-product-closure-promotion-readiness.mjs - node scripts/promote-bitcode-canon.mjs --version V28 --commit HEAD --dry-run + test "$(cat BITCODE_SPEC.txt)" = "V28" + node scripts/check-bitcode-spec-family.mjs --version V28 --mode promoted --current-target V28 + node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29 + node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 + node scripts/check-v29-gate1-objectives-and-gating.mjs --skip-branch-check - name: Validate source casing and imports run: | diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md new file mode 100644 index 000000000..f7f02f795 --- /dev/null +++ b/BITCODE_SPEC_V29.md @@ -0,0 +1,633 @@ +# Bitcode Spec V29 + +## Status + +- Version: `V29` +- V29 state: draft target opened; V29 owns deeper Terminal transaction operation after V28 promotion and must not alter the active V28 canon pointer until promotion +- Current canonical/latest target: `V28` +- Prior canonical anchor: `BITCODE_SPEC_V28.md` +- Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` +- Generated structured artifact inventory: draft `.bitcode/v29-spec-family-report.json`, draft `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality evidence, and no `BITCODE_SPEC_V29_PROVEN.md` until promotion +- Source parity state: V29 Gate 1 opens the draft specification and quality gates; product-source parity begins from V28 Terminal, Reading, AssetPack, settlement, ledger, and workflow implementation truth +- State: draft target opened +- Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V28` +- Draft target source: `protocol-demonstration/src/canon-posture.js` declares `DRAFT_TARGET_VERSION = 'V29'` +- Primary scope: deeper Terminal workflows and transaction operation over the promoted V28 commercial Reading, Finding Fits, AssetPack, settlement, delivery, and promotion baseline +- Prior active canon: `BITCODE_SPEC_V28.md` +- Notes companion: `BITCODE_SPEC_V29_NOTES.md` +- Delta companion: `BITCODE_SPEC_V29_DELTA.md` +- Parity companion: `BITCODE_SPEC_V29_PARITY_MATRIX.md` +- Generated proof appendix: none until V29 promotion +- Scope: V29 canonical system specification for Terminal transaction depth, operator recovery, wallet/BTC settlement operation, AssetPack disclosure and rights review, ledger/database reconciliation, organization permission decisions, and promotion-ready workflow proof over V28 + +V29 begins from promoted V28. +V28 made Depositing, Read Request, Read-Need Comprehension, Finding Fits, AssetPack synthesis, source-safe preview, settlement posture, delivery, and promotion governance coherent enough for canon. +V29 deepens the Terminal as the primary operator surface for that system. + +## Version executive summary + +V29 is a Terminal-depth version. +It does not create a new protocol supply law, a new `$BTD` denomination, or a versioned implementation route family. +It turns V28's promoted commercial Reading system into a more complete enterprise operator experience: + +- transaction state is navigable, recoverable, and explainable; +- wallet, signer session, BTC fee, PSBT, broadcast, replacement, reorg, blocked-readiness, and recovery states are ordinary Terminal states; +- Read Request, synthesized Need, Finding Fits, source-safe AssetPack preview, settlement, rights transfer, and pull-request delivery are presented as one coherent journey; +- proof roots, telemetry, prompt/inference/tool traces, ledger state, database projection, metaphysical state, reconciliation drift, and repair actions are visible at controlled levels of detail; +- organization holdings, roles, read-license usage, and registry-derived permission decisions are first-class Terminal facts; +- V28's demonstration-origin commercial internals continue being formalized into packages and narrow APIs without importing demonstration runtime code. + +V29 closes only when the Terminal can be used as a commercial transaction cockpit for the V28 Read/Fit/AssetPack system and when every V29 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 V28 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. + +V29 does not redefine those laws. +V29 makes their operation deeper, more recoverable, more legible, and more completely validated in Terminal. + +## V29 source-of-truth hierarchy + +The V29 source-of-truth hierarchy is: + +1. `BITCODE_SPEC.txt`, which remains `V28` until V29 promotion. +2. `BITCODE_SPEC_V29.md` during V29 drafting. +3. `BITCODE_SPEC_V29_NOTES.md`. +4. `BITCODE_SPEC_V29_DELTA.md`. +5. `BITCODE_SPEC_V29_PARITY_MATRIX.md`. +6. generated V29 artifacts under `.bitcode/` when produced. +7. `BITCODE_SPEC_V29_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. + +## V29 full-system, re-implementation, and audit rule + +V29 must be re-implementable and auditable from its specification family without reading conversation history. +Every Terminal 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. + +## V29 totality and precision enforcement rule + +V29 fails closed when a Terminal 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. + +## V29 system goals, non-goals, and design principles + +Goals: + +- make Terminal the complete enterprise operator path for Reading transactions; +- deepen recovery, evidence, prompt/telemetry visibility, and ledger/database synchronization; +- preserve the V28 five-step Reading UX while adding transaction detail without overwhelming the default operator path; +- make BTC settlement and BTD rights transfer readable and repairable; +- make organization permissions and license usage registry-derived; +- keep local and staging validation realistic enough to reveal operational defects before promotion. + +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 Terminal-owned hooks; +- no direct runtime dependency on `protocol-demonstration/`. + +Design principles: + +- low-detail by default, complete detail on expansion; +- no protected source leakage before settlement; +- typed events over raw JSON as the operator contract; +- ledger truth and database projection remain synchronized but distinct; +- failures must name the blocking primitive and the repair path. + +## V29 system architecture and layer boundaries + +V29 preserves the V28 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 Terminal UI; +- `protocol-demonstration` remains a standalone minimal reference and proof witness outside the workspace import graph. + +Layer boundaries: + +- Terminal may call commercial APIs and packages; it 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. + +## V29 canonical domain model + +The V29 domain model extends V28 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. +- `TerminalTransaction`: URL-addressable activity combining execution, pipeline, agent, tool, prompt, ledger, database, delivery, and proof state. + +## V29 whole Bitcode operator chain + +The V29 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. + +## V29 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: V29 gate checks, V28 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 V29 gate checks. +- Current accepted boundaries: full-profile async push completion can deepen in V29 gates but cannot bypass source-safe preview or settlement boundaries. + +### 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 V29 gate checks. +- Current accepted boundaries: full mainnet value delivery remains approval-gated. + +### 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 V29 only when tied to Terminal transaction operation. + +### 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, reorg, replacement, broadcast failure, or custody ambiguity blocks finality. +- Current proof obligations: quote root, 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 payment UI, and Supabase projections. +- Current validating commands and parity basis: BTD tests, settlement route tests, staging ledger/database readback, and V29 gate checks. +- Current accepted boundaries: value-bearing mainnet stays outside V29 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 V29 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`, V29 gate scripts, canon-posture drift checks, demonstration tests, package tests, and promotion workflow. +- Current accepted boundaries: V29 promotion automation may be hardened across gates but must be complete before `version/v29` merges to `main`. + +## V29 proof-family canon + +### Exact proof-family inventory matrix + +| proofFamily | proofArtifactPath | memberIds | theoremIds | replayStepIds | witnessArtifactPaths | Current source basis | +| --- | --- | --- | --- | --- | --- | --- | +| Inference-synthesis | `.bitcode/v29-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/v29-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/v29-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/v29-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/v29-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/v29-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/v29-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/v29-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/v29-proof-contract.json` | families, theorems, witnesses | complete-family, replayable | generate, validate, promote | spec/proven artifacts | spec-family tools | + +### Inference-synthesis + +- proofArtifactPath: `.bitcode/v29-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/v29-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/v29-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/v29-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/v29-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/v29-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/v29-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/v29-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/v29-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/v29-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/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `BITCODE_SPEC_V29_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. + +## V29 generated canon + +### Inherited V19 reproducible-canon artifacts + +V29 continues the reproducible-canon requirement: generated reports must be deterministic, path-addressable, and promotion-bound. + +### Inherited V20 operator-quality artifacts + +V29 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/v29-spec-family-report.json` | yes | yes | validates the hand-authored V29 family shape | +| `.bitcode/v29-canonical-input-report.json` | yes | yes | records canonical input closure for active V28 plus V29 draft | +| `.bitcode/v29-canon-posture-drift-report.json` | gate-dependent | yes | proves runtime/docs active/draft posture | +| `BITCODE_SPEC_V29_PROVEN.md` | no | yes | generated proof appendix for promoted V29 | + +### V29 specifying generated artifacts + +The minimum V29 generated set is `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, and `BITCODE_SPEC_V29_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_V29_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. + +## V29 validation canon + +V29 validation is layered: + +- spec-family and canonical-input checks for the V29 draft; +- canon-posture drift checks for V28 active and V29 draft; +- V29 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. + +## V29 promotion canon + +V29 promotes only through `version/v29` into `main`. +Promotion must: + +1. pass every V29 gate check; +2. pass active V28 and draft V29 posture checks before promotion; +3. generate `.bitcode/v29-*` canonical reports; +4. generate `BITCODE_SPEC_V29_PROVEN.md`; +5. update runtime posture carriers from active V28/draft V29 to active V29/next draft; +6. commit `BITCODE_SPEC.txt` changing from `V28` to `V29`; +7. keep main protected by pull request and verified-signature rules. + +## V29 appendices and canonical supporting material + +The appendices below are binding draft structure for V29. +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 V29 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 V29 promotion. + +## Appendix C. Generated artifact contract catalog + +The V29 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:v29-gate1`. +Later gates must add focused scripts before claiming implementation closure. +Promotion validation must run all V29 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 `V28` during V29 drafting. +- `BITCODE_SPEC_V29.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 + +V29 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 V29. + +## Appendix G. Canonical file-family and promotion contract catalog + +V29 file family: + +- `BITCODE_SPEC_V29.md` +- `BITCODE_SPEC_V29_DELTA.md` +- `BITCODE_SPEC_V29_NOTES.md` +- `BITCODE_SPEC_V29_PARITY_MATRIX.md` +- future `BITCODE_SPEC_V29_PROVEN.md` +- `.bitcode/v29-spec-family-report.json` +- `.bitcode/v29-canonical-input-report.json` +- future `.bitcode/v29-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 + +V29 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_V29_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. + +## V29 accepted boundaries and reopen conditions + +Accepted boundaries: + +- V29 remains Terminal-depth, not Exchange depth. +- V29 may deepen MCP/ChatGPT only where Terminal transaction authority requires shared permission truth. +- V29 may harden demonstration-origin commercial internals but must keep the demonstration standalone. +- V29 may use staging-testnet and local live validation; value-bearing mainnet remains separately approved. +- V29 promotion automation may be implemented across gates, but it must be complete before promotion. + +Reopen conditions: + +- V28 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. + +## V29 completion condition + +V29 is complete only when: + +- all gates in the V29 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/v29`; +- generated V29 proof artifacts and `BITCODE_SPEC_V29_PROVEN.md` are produced; +- `BITCODE_SPEC.txt` changes from `V28` to `V29` only in the formal promotion commit. diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md new file mode 100644 index 000000000..a8be71610 --- /dev/null +++ b/BITCODE_SPEC_V29_DELTA.md @@ -0,0 +1,118 @@ +# Bitcode Spec V29 Delta + +## Status + +- Version: `V29` +- V29 state: draft target opened; this delta records V29's planned Terminal-depth changes over promoted V28 +- Current canonical/latest target: `V28` +- Prior canonical anchor: `BITCODE_SPEC_V28.md` +- Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` +- Generated structured artifact inventory: draft `.bitcode/v29-spec-family-report.json`, draft `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, and no `BITCODE_SPEC_V29_PROVEN.md` until promotion +- Source parity state: V29 delta truth is opened in documentation and gate-quality scripts; product implementation begins only through V29 gate branches +- State: draft target delta opened +- Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V28` +- Scope: V29 delta for deeper Terminal transaction operation after V28 commercial Reading, AssetPack, settlement, delivery, and promotion closure +- Spec companion: `BITCODE_SPEC_V29.md` +- Notes companion: `BITCODE_SPEC_V29_NOTES.md` +- Parity companion: `BITCODE_SPEC_V29_PARITY_MATRIX.md` +- Generated proof appendix: none until V29 promotion + +## Why V29 exists + +V28 canonically promoted the first commercial Bitcode Protocol and Terminal MVP: + +- Depositing creates source-bound depository evidence. +- Read Request to Read-Need comprehension is formalized. +- Finding Fits searches the depository and synthesizes source-safe AssetPack previews. +- Settlement, read-license/right transfer, and PR delivery are specified and implemented at MVP depth. +- Gate, branch, commit, CI, and promotion governance are formalized. + +V29 exists because the Terminal now needs enterprise operational depth. +The product must not merely complete the happy path; it must make every transaction state navigable, recoverable, provable, and comprehensible. + +## Accepted V29 decisions + +- V28 remains active canon during V29 drafting. +- V29 owns deeper Terminal workflows and transaction operation. +- V29 gate branches are opened from `version/v29` and merged back only when their gate acceptance criteria are closed. +- V29 preserves the V28 five-step Reading UX: request Read, review synthesized Need, request Finding Fits, review source-safe AssetPack preview, buy/settle. +- V29 deepens wallet, signer-session, BTC fee, PSBT, broadcast, replacement, reorg, blocked-readiness, and failure recovery in Terminal. +- V29 deepens AssetPack range detail, owner-read, licensed-read, denied-state, source-safe preview, paid unlock, and access-policy review. +- V29 deepens Terminal journal diffing, ledger/database/metaphysical separation, reconciliation repair, and proof-root surfacing. +- V29 deepens organization holdings, roles, read-license usage, and registry-derived permission decisions. +- V29 continues formalizing demonstration-origin commercial internals into packages and narrow APIs without importing `protocol-demonstration/` runtime code. +- V29 workflows and scripts must be retargeted to active V28 and draft V29. + +## Explicitly deferred + +- Exchange product/market depth remains beyond V29. +- Website Conversations product depth remains beyond V29. +- New `$BTD` supply law remains out of scope. +- Value-bearing mainnet launch remains separately approval-gated. +- Full provider-family completion remains out of scope unless a Terminal transaction gate requires a narrow hook. +- V30 remains the home for Protocol/BTD hardening discovered during V28/V29 when the hardening is not required to complete Terminal transaction depth. +- V31+ scopes remain future unless explicitly reopened by a later spec. + +## Pre-Implementation Sequence + +1. Open `version/v29` from promoted `main`. +2. Open `v29/gate-1-objectives-and-gating` from `version/v29`. +3. Create the V29 SPEC, DELTA, NOTES, and PARITY family while preserving `BITCODE_SPEC.txt -> V28`. +4. Retarget gate-quality and canon-quality workflow posture checks from V27/V28 to V28/V29. +5. Add a V29 Gate 1 checker and package script. +6. Define V29 gates, acceptance criteria, and carryforward parity rows. +7. Validate spec family, canonical inputs, canon posture, workflows, and diff hygiene. +8. Push the gate branch and open a pull request to `version/v29`. + +## Commit-Body Direction + +V29 gate commit bodies should describe the closed gate, the spec-family changes, the implementation surfaces, the validation commands, and any accepted boundaries. +The eventual V29 promotion commit body must name the Terminal transaction-depth surfaces, list all closed V29 gates, cite generated proof artifacts, state that `BITCODE_SPEC.txt` advances from `V28` to `V29`, and explicitly defer Exchange/Conversations/value-bearing-mainnet work. + +## Gate Delta + +### Gate 1: V29 Objectives And Gating + +Gate 1 opens V29 correctly: + +- V29 SPEC, DELTA, NOTES, and PARITY files exist. +- `BITCODE_SPEC.txt` remains `V28`. +- README and workflows describe V28 active / V29 draft posture. +- `check:v29-gate1` validates branch naming, spec family, notes, parity, workflow posture, and promotion boundaries. +- The V29 gate list is explicit before product implementation begins. + +### Gate 2: Terminal Transaction Read Models And Navigation + +Gate 2 owns URL-addressable transaction state, Terminal state machine, detail panes, execution-to-transaction read models, low-detail defaults, expandable detail, and no raw-JSON dependency for ordinary operators. + +### Gate 3: Wallet Signer Session And BTC Fee Operations + +Gate 3 owns wallet connection depth, signer-session recovery, BTC fee quote lifecycle, PSBT handoff, broadcast/finality/replacement/reorg/failure states, blocked-readiness receipts, and no server-custody posture. + +### Gate 4: Reading Transaction Recovery And Pipeline Observability + +Gate 4 owns deep Terminal visibility over `ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis`, including execution, phase, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, output, and typed parse telemetry. + +### Gate 5: AssetPack Disclosure Rights And Preview Depth + +Gate 5 owns AssetPack range detail, owner-read/licensed-read/denied-state flows, source-safe preview, disclosure policy review, paid unlock state, and protected-source leakage tests. + +### Gate 6: Settlement Reconciliation And Repair + +Gate 6 owns ledger/database/metaphysical separation, journal diffing, reconciliation repair actions, proof-root surfacing, settlement conservation drift handling, and delivery recovery. + +### Gate 7: Organization Permissions And Interface Authority + +Gate 7 owns organization holdings, roles, read-license usage, registry-derived permission decisions, MCP/ChatGPT action authority alignment, and Terminal permission explainers. + +### Gate 8: Demonstration-Origin Commercial Formalization + +Gate 8 owns cleanup of freshly ported demonstration-origin internals into package-native APIs, no demonstration runtime imports, durable package tests, and updated internal/public documentation. + +### Gate 9: Terminal UX Quality And Browser Proof + +Gate 9 owns accessibility, responsive layout, copy/prose clarity, empty/loading/blocked/failed states, Playwright coverage, and visual/browser verification for the complete Terminal transaction cockpit. + +### Gate 10: Local And Staging Promotion Readiness + +Gate 10 owns non-mocked local validation, staging-testnet readback, generated proof artifacts, V29 promotion workflow support, promotion dry-run, and final version branch readiness. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 858dc18d8..57c79f90d 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -3,59 +3,95 @@ ## Status - Version: `V29` -- V29 state: future notes scaffold only -- Current canonical/latest target: `V27` -- Current active draft target: `V28` -- Prior canonical anchor: `BITCODE_SPEC_V27.md` -- Prior generated proof appendix: `BITCODE_SPEC_V27_PROVEN.md` -- Generated structured artifact inventory: none for V29 yet -- Source parity state: not opened; V29 source parity begins only after V29 draft opening -- Scope: future notes for deeper Terminal work after V28 commercial Protocol/Terminal MVP QA. - -This NOTES file does not promote V29 and does not open V29 implementation. -It preserves roadmap intent so V28 can remain focused on commercial Protocol/Terminal MVP QA, bugfixing, audit, and hardening. +- V29 state: draft target opened; V29 notes now track active V28 canon and V29 Terminal-depth gate planning +- Current canonical/latest target: `V28` +- Prior canonical anchor: `BITCODE_SPEC_V28.md` +- Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` +- Generated structured artifact inventory: draft `.bitcode/v29-spec-family-report.json`, draft `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, and no `BITCODE_SPEC_V29_PROVEN.md` until promotion +- Source parity state: notes opened from V28 handoff; source implementation begins gate-by-gate after Gate 1 +- Scope: V29 notes for deeper Terminal workflow, transaction operation, evidence readability, wallet/BTC operation, settlement repair, organization permission, and promotion-readiness work. ## Notes companion rule -This file is planning memory only. -Requirements become binding only when V29 is explicitly opened as the draft-target SPEC family. +This file is a required companion to `BITCODE_SPEC_V29.md`. +It may carry planning detail, QA observations, and simplified reading, but it must not override the main V29 SPEC. +Binding V29 requirements must be reflected in SPEC, DELTA, and PARITY before a gate closes. ## Concise current-system reading -V27 is active canon. -V28 is current draft target and owns commercial Protocol implementation, Terminal MVP QA, MCP API/ChatGPT App MVP, BTD/testnet/ledgerization, and demonstration-to-commercial boundary cleanup. -V29 is expected to deepen Terminal after the Terminal/Protocol shell, Auxillaries active shell, BTD disclosure, MCP/ChatGPT MVP, and route QA are stable. +V28 is active canon. +V29 is the current draft target and owns deeper Terminal transaction operation over the promoted V28 commercial Reading system. -## Intended V29 focus +The V28 system already defines: -V29 owns deeper Terminal: +- source Depositing into the Bitcode depository; +- Read Request to reviewed Read-Need comprehension; +- Finding Fits over fit deposits in the depository; +- source-safe AssetPack preview before settlement; +- BTC fee posture, BTD range/read-license/right transfer, and delivery; +- ledger/database reconciliation, telemetry, and promotion governance at MVP depth. -- full Read submission, measurement, review, Fit, proof, dedupe, measuremint, and settlement workflows; -- wallet connection, signer-session recovery, BTC fee preparation, PSBT handoff, broadcast, replacement, reorg, and failure recovery depth; -- AssetPack range detail, owner-read, licensed-read, denied-state, and access-policy review as ordinary operator workflows; -- Terminal journal diffing, reconciliation repair, ledger/database/metaphysical state separation, and proof-root surfacing; -- organization holdings, team roles, read-license usage, and registry-derived Terminal permission decisions; -- Terminal-specific route, UI, accessibility, responsive, error-state, and Playwright coverage. -- Terminal prose, labels, explainers, and read/write guidance refined for clearer commercial comprehension while preserving V27 technical law. +V29's job is to make those flows operationally excellent in Terminal: recoverable, navigable, typed, inspectable, accessible, and promotion-proven. -## Inputs deferred from V28 QA +## Simplified-spec reading rule -- May 7, 2026 V28 manual QA accepted Terminal as the primary operator surface at MVP level but identified prose clarity as a Terminal-focused improvement. -- V29 should improve Terminal copy, hierarchy, explanatory precision, and operator sequencing around Deposit, Read, Fit, proof, AssetPack, BTC fee posture, BTD range/read-right posture, and selected activity detail. -- This is not a V28 blocker unless specific wording prevents a user from completing basic V28 MVP navigation or materially misstates Bitcode law. -- May 7, 2026 follow-up QA clarified that Terminal should not present itself as a market-wide master-detail product surface. V28 must fix that MVP architecture and any obvious dead/ambiguous click targets; V29 should then deepen Terminal-specific sequencing, density management, task progression, and richer Deposit/Read result reading without reintroducing Exchange-style market language. -- V28 introduces a formal `@bitcode/protocol` package and removes direct commercial imports from the standalone `protocol-demonstration`, but some package internals are intentionally fresh ports for parity. V29 must continue commercializing those demonstration-origin internals into formal packages, narrower APIs, durable package tests, and Terminal-owned protocol adapters. -- The standalone `protocol-demonstration` should remain a sibling reference guide and proof witness outside the workspace build graph. V29 should use it to reveal commercial implementation gaps, not as runtime code imported by commercial UAPI, Terminal, Auxillaries, MCP, ChatGPT App, or package consumers. +For a simplified reading of V29: -## Boundaries +1. V28 is the current law. +2. V29 does not change the law of BTD supply, BTC fee asset, or source-safe paid unlock. +3. V29 improves how a commercial operator uses Terminal to carry a transaction from readiness through paid delivery and repair. +4. If a Terminal state is important for money, source visibility, rights, proof, or delivery, it must be visible, typed, and recoverable. +5. `BITCODE_SPEC.txt` must remain `V28` until the V29 promotion workflow commits the canonical pointer change. -V29 deepens Terminal only after V28 establishes commercial Protocol/Terminal MVP coherence. -It must not absorb V30 Protocol/BTD hardening, V31 Auxillaries depth, V32 provation/testing depth, V33 interface finalization, V34 deployment depth, V35 telemetry/documentation depth, or V36+ Exchange/Conversations depth except for narrow Terminal-owned hooks. +## V29 gate plan -V29 must also avoid reopening V28's demonstration/commercial boundary. -Any Terminal feature that currently depends on freshly ported demonstration-origin modules should be formalized in-place inside commercial packages or replaced with package-native primitives, while the standalone demonstration stays a reference implementation. +1. **Gate 1: V29 Objectives And Gating** + - Open the V29 spec family. + - Retarget workflows and branch/readme posture to active V28 / draft V29. + - Add a Gate 1 checker and define all V29 gates. -## Return To V28 +2. **Gate 2: Terminal Transaction Read Models And Navigation** + - Build URL-addressable Terminal transaction state, typed read models, default-low-detail navigation, and expandable detail panes. -Do not start V29 implementation during V28. -Record Terminal gaps found during V28 QA as future V29 inputs unless they block V28 commercial Protocol/Terminal MVP usability. +3. **Gate 3: Wallet Signer Session And BTC Fee Operations** + - Deepen signer-session recovery, BTC fee quote, PSBT handoff, broadcast, replacement, reorg, failure, and blocked-readiness states. + +4. **Gate 4: Reading Transaction Recovery And Pipeline Observability** + - Make `ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis` execution telemetry fully readable in Terminal at execution, phase, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, raw output, and parsed output levels. + +5. **Gate 5: AssetPack Disclosure Rights And Preview Depth** + - Deepen source-safe preview, AssetPack range detail, owner-read/licensed-read/denied state, disclosure policy review, paid unlock, and source-leakage tests. + +6. **Gate 6: Settlement Reconciliation And Repair** + - Make ledger/database/metaphysical separation, journal diffing, reconciliation repair, proof roots, and delivery recovery ordinary Terminal workflows. + +7. **Gate 7: Organization Permissions And Interface Authority** + - Deepen org holdings, roles, read-license usage, registry-derived permission decisions, and MCP/ChatGPT action authority parity. + +8. **Gate 8: Demonstration-Origin Commercial Formalization** + - Continue moving freshly ported internals into package-native APIs and durable tests while preserving the standalone demonstration boundary. + +9. **Gate 9: Terminal UX Quality And Browser Proof** + - Close accessibility, responsive, copy, loading/empty/error/blocked states, browser checks, and Playwright coverage for the complete Terminal cockpit. + +10. **Gate 10: Local And Staging Promotion Readiness** + - Run non-mocked local validation, staging-testnet readback, generated proof artifacts, promotion dry-run, and `version/v29` promotion readiness. + +## Gate 1 closure notes + +Gate 1 is complete only when the V29 family exists, validates, and is wired to CI. +It intentionally does not claim Terminal product closure. + +Gate 1 accepted evidence: + +- `BITCODE_SPEC_V29.md`, DELTA, NOTES, and PARITY exist. +- `BITCODE_SPEC.txt` remains `V28`. +- workflows and README describe V28 active / V29 draft posture. +- `pnpm run check:v29-gate1` validates branch, posture, workflow, docs, and spec-family shape. + +## Later-version boundaries + +- V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. +- V31+ scopes remain future unless a later spec family reopens them. +- Exchange and website Conversations remain outside V29 product depth. +- Value-bearing mainnet remains separately approved. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md new file mode 100644 index 000000000..69a3958e4 --- /dev/null +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -0,0 +1,94 @@ +# Bitcode Spec V29 Parity Matrix + +## Status + +- Version: `V29` +- V29 state: draft target opened; parity now tracks V29 gates over active V28 canon +- Current canonical/latest target: `V28` +- Prior canonical anchor: `BITCODE_SPEC_V28.md` +- Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` +- Generated structured artifact inventory: draft `.bitcode/v29-spec-family-report.json`, draft `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, and no `BITCODE_SPEC_V29_PROVEN.md` until promotion +- Source parity state: Gate 1 parity is documentation/workflow/checker closure; product-source rows start as pending V29 gate work +- State: draft target parity matrix opened +- Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V28` +- Scope: V29 parity ledger for Terminal transaction depth, wallet/BTC operations, Reading pipeline observability, AssetPack disclosure, settlement repair, organization permissions, UX quality, and promotion readiness +- Spec companion: `BITCODE_SPEC_V29.md` +- Notes companion: `BITCODE_SPEC_V29_NOTES.md` +- Delta companion: `BITCODE_SPEC_V29_DELTA.md` +- Generated proof appendix: none until V29 promotion + +## Purpose + +The V29 parity matrix prevents Terminal-depth work from becoming vague product polish. +Each gate must name source surfaces, tests, proof evidence, documentation, and accepted boundaries before it closes. + +## Audit basis + +Gate 1 audit basis: + +- `BITCODE_SPEC.txt` +- `BITCODE_SPEC_V28.md` +- `BITCODE_SPEC_V28_DELTA.md` +- `BITCODE_SPEC_V28_NOTES.md` +- `BITCODE_SPEC_V28_PARITY_MATRIX.md` +- `BITCODE_SPEC_V28_PROVEN.md` +- `BITCODE_SPEC_V29_NOTES.md` +- `README.md` +- `AGENTS.md` +- `.github/workflows/bitcode-gate-quality.yml` +- `.github/workflows/bitcode-canon-quality.yml` +- `package.json` +- `protocol-demonstration/src/canon-posture.js` +- Terminal, Reading pipeline, BTD, pipeline-host, UAPI, and workflow surfaces named by V28 promotion. + +No `_legacy/` source is active source truth. + +## V29 implementation matrix + +| Area | Gate | Source evidence | Judgment | Closure requirement | +| --- | --- | --- | --- | --- | +| Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V29.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v29/gate-1-objectives-and-gating` | drafted | V29 family validates in draft mode over active V28 and `check:v29-gate1` passes. | +| Workflow retargeting | Gate 1 | `.github/workflows/bitcode-gate-quality.yml`, `.github/workflows/bitcode-canon-quality.yml` | drafted | CI checks V28 active / V29 draft posture instead of stale V27/V28 posture. | +| Terminal transaction read models | Gate 2 | `uapi/app/terminal`, API execution routes, read-model adapters | pending | Terminal transaction state is URL-addressable, recoverable, and typed. | +| Wallet signer/BTC operations | Gate 3 | `packages/btd`, wallet API, BTC fee route, Terminal wallet UI | pending | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | +| Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack`, `packages/pipeline-hosts`, Terminal stream components | pending | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt telemetry is complete and readable. | +| AssetPack disclosure rights | Gate 5 | BTD access primitives, AssetPack preview UI, disclosure policy tests | pending | Source-safe preview and paid unlock are proven without source leakage. | +| Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, Terminal repair UI | pending | Ledger, database, and metaphysical state drift is visible and repairable. | +| Organization permission authority | Gate 7 | access policy, org holdings, MCP/ChatGPT gates, Terminal permission UI | pending | Registry-derived roles, holdings, and read-license authority govern actions. | +| Commercial formalization | Gate 8 | packages/protocol, package tests, import scans, docs | pending | Demonstration-origin commercial internals are package-native and no runtime demo imports remain. | +| Terminal UX quality | Gate 9 | Playwright/Jest/a11y/responsive/browser QA | pending | Complete transaction cockpit is usable by default and inspectable in detail. | +| Promotion readiness | Gate 10 | promotion workflow, `.bitcode/v29-*`, `BITCODE_SPEC_V29_PROVEN.md` | pending | `version/v29` can promote to `main` only after all V29 checks pass. | + +## V29 implementation checklist + +| Area | Required V29 result | Judgment | +| --- | --- | --- | +| Active canon pointer | `BITCODE_SPEC.txt` remains `V28` during V29 gate work | drafted | +| Gate branch pattern | V29 work happens on `version/v29` or `v29/gate-N-*` branches | drafted | +| Spec-family shape | V29 SPEC, DELTA, NOTES, and PARITY satisfy the full spec-family checker | drafted | +| Gate 1 script | `pnpm run check:v29-gate1` fails closed on stale posture or missing gates | drafted | +| Product implementation gates | Gates 2-9 close Terminal transaction depth with tests and docs | pending | +| Promotion gate | Gate 10 closes generated proof and promotion automation | pending | + +## Gate 1 Parity + +| Requirement | Source evidence | Current V29 judgment | +| --- | --- | --- | +| Active canon remains V28 during V29 draft opening | `BITCODE_SPEC.txt` contains `V28` | drafted | +| Runtime draft target is V29 | `protocol-demonstration/src/canon-posture.js` declares V28 active and V29 draft | drafted | +| V29 SPEC family exists as draft | `BITCODE_SPEC_V29.md`, DELTA, NOTES, and PARITY | drafted | +| Gate-quality workflow is V29-aware | `.github/workflows/bitcode-gate-quality.yml` | drafted | +| Canon-quality workflow is V29-aware | `.github/workflows/bitcode-canon-quality.yml` | drafted | +| README reflects V28/V29 posture | `README.md` | drafted | +| V29 Gate 1 checker exists | `scripts/check-v29-gate1-objectives-and-gating.mjs` and package script | drafted | + +## accepted boundaries + +- Gate 1 does not implement Terminal product depth. +- Gate 1 does not create `BITCODE_SPEC_V29_PROVEN.md`. +- Gate 1 does not promote `BITCODE_SPEC.txt` to V29. +- Gate 1 may retarget workflows to active V28 / draft V29 so later gates are greenable. + +## completion condition + +Gate 1 is complete when the V29 draft family validates, `check:v29-gate1` passes, workflow posture is V29-aware, README/docs reflect V29 initiation, and the gate branch is committed and pushed for review into `version/v29`. diff --git a/README.md b/README.md index 50889834b..cede61449 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 `V27`; V28 is the active draft target for commercial MVP QA, -hardening, and surface cleanup. +resolves to `V28`; V29 is the active draft target for deeper Terminal +transaction workflows and operator recovery. ## Current Product Posture @@ -12,9 +12,10 @@ The primary operator routes are: - `/terminal` for depositing, reading, transaction work, and protocol follow-through. - `/auxillaries` for Wallet, Externals, Profile, and Interfaces support surfaces. -Exchange and website Conversations remain in source as deferred commercial work, -but V28 closure focuses on Terminal, Auxillaries, wallet/BTC testnet, MCP API, -and ChatGPT App MVP behavior. +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. The protocol demonstration remains the minimal deterministic reference for the same protocol. Commercial code may mount or compare against demonstration @@ -39,10 +40,10 @@ verified signatures. Use a version branch and gate-numbered branches: -1. Create one base branch per draft target, such as `version/v28`. +1. Create one base branch per draft target, such as `version/v29`. 2. Create scoped gate branches from the version branch. Prefix every gate branch - with the gate number, for example `v28/gate-3-read-fit-workflow` or - `v28/gate-8-promotion-proof`. + with the gate number, for example `v29/gate-1-objectives-and-gating` or + `v29/gate-6-settlement-reconciliation-repair`. 3. Group related work into clear commits with quality commit messages whose titles and bodies describe the proof, implementation, or documentation change. @@ -54,16 +55,15 @@ Use a version branch and gate-numbered branches: version is formally promoted as canon. Gate pull requests into `version/**` run the Bitcode gate-quality workflow: -draft-canon checks, casing/import checks, relevant package typechecks and 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 MVP demonstration proof, while full promoted-suite closure is reserved for -the version promotion workflow. Version pull requests into `main` run the -version promotion workflow. For V28, that workflow validates the promotion proof -posture and, only after promotion validations pass, executes the canonical -promotion script, generates `BITCODE_SPEC_V28_PROVEN.md`, and commits the -promotion artifacts plus `BITCODE_SPEC.txt` pointer change from `V27` to `V28` -on the version branch. +active/draft canon checks, casing/import checks, relevant package typechecks and +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. 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 @@ -74,9 +74,9 @@ or promotion validation. ## Key Surfaces - [BITCODE_SPEC.txt](BITCODE_SPEC.txt) is the canonical version pointer. -- [BITCODE_SPEC_V27.md](BITCODE_SPEC_V27.md) is the active promoted spec family. -- [BITCODE_SPEC_V28.md](BITCODE_SPEC_V28.md) is the active draft target. -- [BITCODE_V28_QA.md](BITCODE_V28_QA.md) tracks commercial MVP QA. +- [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. - [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/package.json b/package.json index 4420fd808..f02eb3ef2 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "check:v28-gate11": "node scripts/check-v28-gate11-read-fits-finding-preview.mjs", "check:v28-gate12": "node scripts/check-v28-gate12-settlement-rights-delivery.mjs", "check:v28-gate13": "node scripts/check-v28-gate13-product-closure-promotion-readiness.mjs", + "check:v29-gate1": "node scripts/check-v29-gate1-objectives-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/protocol-demonstration/test/v21-specifying.test.js b/protocol-demonstration/test/v21-specifying.test.js index a9018bf0b..61c1a8876 100644 --- a/protocol-demonstration/test/v21-specifying.test.js +++ b/protocol-demonstration/test/v21-specifying.test.js @@ -20,7 +20,7 @@ function projectLabel(version) { function expectedActiveCanonicalInputArtifactCount(version) { const numeric = Number.parseInt(String(version || '').replace(/^V/u, ''), 10); if (!Number.isInteger(numeric)) return 3; - if (numeric === 27) return 0; + if (numeric === 27 || numeric === 28) return 0; if (numeric >= 26) return 22; if (numeric >= 22) return 3; if (numeric === 21) return 2; diff --git a/scripts/check-bitcode-pre-commit.mjs b/scripts/check-bitcode-pre-commit.mjs index 45196b945..3bf0fe841 100644 --- a/scripts/check-bitcode-pre-commit.mjs +++ b/scripts/check-bitcode-pre-commit.mjs @@ -16,9 +16,9 @@ const SPEC_RELEVANT_PATHS = [ /^BITCODE_SPEC\.txt$/u, /^packages\/protocol-demonstration\/src\/canonical\/v21-specifying\.js$/u, /^package\.json$/u, - /^scripts\/(?:check-bitcode-|check-v28-metadevelopment-readiness|prepare-bitcode-spec-family-promotion|prepare-bitcode-runtime-canon-promotion|promote-bitcode-canon|run-bitcode-spec-quality|setup-bitcode-git-hooks)/u, + /^scripts\/(?:check-bitcode-|check-v28-metadevelopment-readiness|check-v29-gate1-objectives-and-gating|prepare-bitcode-spec-family-promotion|prepare-bitcode-runtime-canon-promotion|promote-bitcode-canon|run-bitcode-spec-quality|setup-bitcode-git-hooks)/u, /^\.githooks\/(?:pre-commit|commit-msg)$/u, - /^\.github\/workflows\/(?:bitcode-canon-quality|bitcode-gate-quality|v28-canon-promotion)\.yml$/u + /^\.github\/workflows\/(?:bitcode-canon-quality|bitcode-gate-quality|v28-canon-promotion|v29-canon-promotion)\.yml$/u ]; function projectLabel(version) { diff --git a/scripts/check-v29-gate1-objectives-and-gating.mjs b/scripts/check-v29-gate1-objectives-and-gating.mjs new file mode 100644 index 000000000..cf8ce67b5 --- /dev/null +++ b/scripts/check-v29-gate1-objectives-and-gating.mjs @@ -0,0 +1,177 @@ +#!/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-v29-gate1-objectives-and-gating.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 1 draft-family, branch, workflow, docs, and 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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 gate work. Observed ${pointer || 'empty'}.` + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-\d+-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 work must occur on version/v29 or gate-prefixed branches. Observed ${branch || 'detached HEAD'}.` + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'BITCODE_SPECIFYING.md', + 'BITCODE_SPEC_TEMPLATEGUIDE.md', + '.github/workflows/bitcode-gate-quality.yml', + '.github/workflows/bitcode-canon-quality.yml', + 'README.md', + 'AGENTS.md' + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing required V29 Gate 1 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.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 readme = read(root, 'README.md'); + const agents = read(root, 'AGENTS.md'); + const posture = read(root, 'protocol-demonstration/src/canon-posture.js'); + + assertCheck(failures, spec.includes('Current canonical/latest target: `V28`'), 'V29 SPEC must declare V28 as current canonical/latest target.'); + assertCheck(failures, delta.includes('Current canonical/latest target: `V28`'), 'V29 DELTA must declare V28 as current canonical/latest target.'); + assertCheck(failures, notes.includes('Current canonical/latest target: `V28`'), 'V29 NOTES must declare V28 as current canonical/latest target.'); + assertCheck(failures, parity.includes('Current canonical/latest target: `V28`'), 'V29 PARITY must declare V28 as current canonical/latest target.'); + assertCheck(failures, posture.includes("ACTIVE_CANON_VERSION = 'V28'"), 'Runtime canon posture must keep V28 active.'); + assertCheck(failures, posture.includes("DRAFT_TARGET_VERSION = 'V29'"), 'Runtime canon posture must declare V29 as draft target.'); + + for (const gate of [ + 'Gate 1: V29 Objectives And Gating', + 'Gate 2: Terminal Transaction Read Models And Navigation', + 'Gate 3: Wallet Signer Session And BTC Fee Operations', + 'Gate 4: Reading Transaction Recovery And Pipeline Observability', + 'Gate 5: AssetPack Disclosure Rights And Preview Depth', + 'Gate 6: Settlement Reconciliation And Repair', + 'Gate 7: Organization Permissions And Interface Authority', + 'Gate 8: Demonstration-Origin Commercial Formalization', + 'Gate 9: Terminal UX Quality And Browser Proof', + 'Gate 10: Local And Staging Promotion Readiness' + ]) { + assertCheck(failures, hasSection(delta, gate) || notes.includes(gate), `V29 gate plan is missing ${gate}.`); + } + + assertCheck(failures, hasSection(notes, 'Simplified-spec reading rule'), 'V29 NOTES must carry the simplified-spec reading rule.'); + assertCheck(failures, hasSection(parity, 'V29 implementation matrix'), 'V29 PARITY must carry an implementation matrix.'); + assertCheck(failures, hasSection(parity, 'V29 implementation checklist'), 'V29 PARITY must carry an implementation checklist.'); + assertCheck(failures, parity.includes('| Draft family and branch posture | Gate 1 |'), 'V29 PARITY must name Gate 1 draft-family posture.'); + + assertCheck(failures, packageJson.includes('"check:v29-gate1"'), 'package.json must expose check:v29-gate1.'); + assertCheck(failures, gateWorkflow.includes('check-v29-gate1-objectives-and-gating.mjs'), 'Gate workflow must run the V29 Gate 1 checker.'); + assertCheck(failures, gateWorkflow.includes('--version V29 --mode draft --current-target V28'), 'Gate workflow must validate V29 draft spec over V28.'); + assertCheck(failures, gateWorkflow.includes('--active-canon V28 --draft-target V29'), 'Gate workflow must validate V28/V29 canon posture.'); + assertCheck(failures, canonWorkflow.includes('--active-canon V28 --draft-target V29'), 'Canon quality workflow must validate V28/V29 canon posture.'); + assertCheck(failures, canonWorkflow.includes('--version V29 --mode draft --current-target V28'), 'Canon quality workflow must validate V29 draft family.'); + + assertCheck(failures, readme.includes('resolves to `V28`; V29 is the active draft target'), 'README must state V28 active / V29 draft posture.'); + assertCheck(failures, readme.includes('version/v29'), 'README must document the version/v29 branch workflow.'); + assertCheck(failures, readme.includes('v29/gate-1-objectives-and-gating'), 'README must document a V29 gate branch example.'); + assertCheck(failures, agents.includes('version/v29') || agents.includes('such as `version/v28`'), 'AGENTS.md must document version base branch usage.'); + assertCheck(failures, /gate branches must be prefixed with the gate number/i.test(agents), 'AGENTS.md must retain gate-number branch discipline.'); + + 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('V29 Gate 1 objectives and gating check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write(`V29 Gate 1 objectives 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 4fc0a832d822d12585f0a31d87019ce061c55605 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Wed, 20 May 2026 13:22:19 -0300 Subject: [PATCH 02/18] Define Terminal transaction read models (#21) Closes V29 Gate 2 by specifying and implementing route-owned Terminal transaction read models, default transaction route recovery, typed section navigation, and low-detail detail headers. Adds focused query/read-model tests plus a Gate 2 checker wired into gate-quality CI. Validation: pnpm run check:v29-gate1; pnpm run check:v29-gate2; node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28; node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29; node scripts/check-bitcode-canonical-inputs.mjs --current-target V28; node scripts/check-bitcode-spec-family.mjs --version V28 --mode promoted --current-target V28; pnpm --dir uapi exec jest --runTestsByPath tests/terminalTransactionDetail.test.ts tests/terminalTransactionDetailCards.test.tsx tests/terminalTransactionDetailSnapshot.test.ts tests/terminalTransactionQuery.test.ts tests/terminalTransactionReadModel.test.ts tests/terminalTransactionSource.test.ts tests/terminalPageShell.test.tsx tests/exchangePageClient.test.tsx --runInBand; pnpm --dir uapi exec tsc --noEmit; pnpm --dir uapi exec eslint . --ext .ts,.tsx --quiet; bash scripts/check-import-casing.sh; bash scripts/find-uppercase-raw-promptparts.sh; git diff --check; node scripts/check-bitcode-pre-commit.mjs. --- .github/workflows/bitcode-gate-quality.yml | 3 + BITCODE_SPEC_V29.md | 20 + BITCODE_SPEC_V29_DELTA.md | 10 + BITCODE_SPEC_V29_NOTES.md | 17 + BITCODE_SPEC_V29_PARITY_MATRIX.md | 27 +- package.json | 1 + ...gate2-terminal-transaction-read-models.mjs | 219 +++++++++++ uapi/app/exchange/ExchangePageClient.tsx | 1 + uapi/app/terminal/README.md | 18 + uapi/app/terminal/TerminalPageClient.tsx | 17 +- .../TerminalTransactionDetailActionBar.tsx | 53 ++- .../TerminalTransactionDetailHero.tsx | 39 +- .../TerminalTransactionDetailSurface.tsx | 64 ++-- .../terminal/TerminalTransactionWorkspace.tsx | 3 + .../terminal/terminal-transaction-query.ts | 10 + .../terminal-transaction-read-model.ts | 356 ++++++++++++++++++ uapi/jest.config.cjs | 1 + uapi/tests/terminalTransactionQuery.test.ts | 28 ++ .../terminalTransactionReadModel.test.ts | 173 +++++++++ 19 files changed, 1004 insertions(+), 56 deletions(-) create mode 100755 scripts/check-v29-gate2-terminal-transaction-read-models.mjs create mode 100644 uapi/app/terminal/terminal-transaction-read-model.ts create mode 100644 uapi/tests/terminalTransactionReadModel.test.ts diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index f5c2d03d7..1987f2b59 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -46,6 +46,7 @@ jobs: node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29 node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 node scripts/check-v29-gate1-objectives-and-gating.mjs --skip-branch-check + node scripts/check-v29-gate2-terminal-transaction-read-models.mjs --skip-branch-check - name: Validate source casing and imports run: | @@ -71,6 +72,8 @@ jobs: tests/api/pipelineHarnessRoute.test.ts \ tests/terminalPipelineHarnessClient.test.ts \ tests/terminalDepositReadWorkbench.test.ts \ + tests/terminalTransactionQuery.test.ts \ + tests/terminalTransactionReadModel.test.ts \ tests/pipelineExecutionLogHeader.test.tsx \ --runInBand diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index f7f02f795..b2b630985 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -158,6 +158,7 @@ The V29 domain model extends V28 operationally: - `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. - `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. ## V29 whole Bitcode operator chain @@ -179,6 +180,25 @@ Readiness 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. +## V29 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, 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. + ## V29 canonical subsystem surfaces ### Depositing and asset supply diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index a8be71610..fe95e4d01 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -85,6 +85,16 @@ Gate 1 opens V29 correctly: Gate 2 owns URL-addressable transaction state, Terminal state machine, detail panes, execution-to-transaction read models, low-detail defaults, expandable detail, and no raw-JSON dependency for ordinary operators. +Closure acceptance: + +- the Terminal writes a selected transaction id into the route whenever live, projected, or review-fallback activity is selectable; +- former `runId` links continue resolving but are rewritten to `transactionId`; +- a typed `TerminalTransactionReadModel` derives the selected activity's low-detail operator summary, section navigation, active detail focus, and expandable audit posture; +- Shippables, identity, closure, proofs, history, journal, activity stream, and console sections expose availability, target ids, route hrefs, and blocking reasons without raw JSON inspection; +- console detail is blocked outside live execution-history mode rather than presented as an inert or misleading section; +- unit tests cover route recovery, section availability, legacy query migration, low-detail defaults, and filter/pagination preservation; +- V29 SPEC, DELTA, NOTES, PARITY, Terminal README, package scripts, and gate-quality workflow name the Gate 2 closure surface. + ### Gate 3: Wallet Signer Session And BTC Fee Operations Gate 3 owns wallet connection depth, signer-session recovery, BTC fee quote lifecycle, PSBT handoff, broadcast/finality/replacement/reorg/failure states, blocked-readiness receipts, and no server-custody posture. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 57c79f90d..4961b10fa 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -52,6 +52,7 @@ For a simplified reading of V29: 2. **Gate 2: Terminal Transaction Read Models And Navigation** - Build URL-addressable Terminal transaction state, typed read models, default-low-detail navigation, and expandable detail panes. + - Acceptance detail: selected transactions must recover through `transactionId`, detail focus must recover through `transactionDetail`, the first selectable row must write itself into a bare Terminal URL, and the operator-facing model must expose section summaries and blockers before raw payloads. 3. **Gate 3: Wallet Signer Session And BTC Fee Operations** - Deepen signer-session recovery, BTC fee quote, PSBT handoff, broadcast, replacement, reorg, failure, and blocked-readiness states. @@ -89,6 +90,22 @@ Gate 1 accepted evidence: - workflows and README describe V28 active / V29 draft posture. - `pnpm run check:v29-gate1` validates branch, posture, workflow, docs, and spec-family shape. +## Gate 2 working notes + +Gate 2 closes the first product-source V29 slice. +Its read model is intentionally not a new protocol primitive and not a versioned API route. +It is the Terminal projection that lets operators recover, share, and inspect a selected transaction without depending on browser network logs or raw JSON. + +The low-detail default should answer: + +- which transaction is selected; +- whether the selected detail section is available, empty, or blocked; +- where to navigate next inside the transaction; +- which facts are proof, ledger, database, delivery, or execution facts; +- whether deeper audit payloads exist behind an expansion. + +The detailed view may still carry raw payload accordions for audit, but the ordinary collapsed view must be typed and readable. + ## Later-version boundaries - V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 69a3958e4..54e80cc1f 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -49,7 +49,7 @@ No `_legacy/` source is active source truth. | --- | --- | --- | --- | --- | | Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V29.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v29/gate-1-objectives-and-gating` | drafted | V29 family validates in draft mode over active V28 and `check:v29-gate1` passes. | | Workflow retargeting | Gate 1 | `.github/workflows/bitcode-gate-quality.yml`, `.github/workflows/bitcode-canon-quality.yml` | drafted | CI checks V28 active / V29 draft posture instead of stale V27/V28 posture. | -| Terminal transaction read models | Gate 2 | `uapi/app/terminal`, API execution routes, read-model adapters | pending | Terminal transaction state is URL-addressable, recoverable, and typed. | +| Terminal transaction read models | Gate 2 | `uapi/app/terminal/terminal-transaction-read-model.ts`, `uapi/app/terminal/terminal-transaction-query.ts`, `TerminalTransactionWorkspace.tsx`, `TerminalTransactionDetailSurface.tsx`, UAPI tests, Gate 2 checker | drafted | Terminal transaction state is URL-addressable, recoverable, typed, low-detail by default, and expandable without raw JSON as the ordinary operator contract. | | Wallet signer/BTC operations | Gate 3 | `packages/btd`, wallet API, BTC fee route, Terminal wallet UI | pending | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | | Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack`, `packages/pipeline-hosts`, Terminal stream components | pending | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt telemetry is complete and readable. | | AssetPack disclosure rights | Gate 5 | BTD access primitives, AssetPack preview UI, disclosure policy tests | pending | Source-safe preview and paid unlock are proven without source leakage. | @@ -67,7 +67,8 @@ No `_legacy/` source is active source truth. | Gate branch pattern | V29 work happens on `version/v29` or `v29/gate-N-*` branches | drafted | | Spec-family shape | V29 SPEC, DELTA, NOTES, and PARITY satisfy the full spec-family checker | drafted | | Gate 1 script | `pnpm run check:v29-gate1` fails closed on stale posture or missing gates | drafted | -| Product implementation gates | Gates 2-9 close Terminal transaction depth with tests and docs | pending | +| Gate 2 read model | `pnpm run check:v29-gate2` proves typed route-owned Terminal transaction reading | drafted | +| Product implementation gates | Gates 3-9 close remaining Terminal transaction depth with tests and docs | pending | | Promotion gate | Gate 10 closes generated proof and promotion automation | pending | ## Gate 1 Parity @@ -92,3 +93,25 @@ No `_legacy/` source is active source truth. ## completion condition Gate 1 is complete when the V29 draft family validates, `check:v29-gate1` passes, workflow posture is V29-aware, README/docs reflect V29 initiation, and the gate branch is committed and pushed for review into `version/v29`. + +## Gate 2 Parity + +| Requirement | Source evidence | Current V29 judgment | +| --- | --- | --- | +| Selected transactions are URL-addressable | `terminal-transaction-query.ts`, `TerminalPageClient.tsx` | drafted | +| Detail focus is typed and recoverable | `terminal-transaction-read-model.ts`, `TerminalTransactionDetailActionBar.tsx` | drafted | +| Low-detail read model exists before raw payloads | `terminal-transaction-read-model.ts`, `TerminalTransactionDetailHero.tsx` | drafted | +| Section navigation exposes availability and blockers | `terminal-transaction-read-model.ts`, `TerminalTransactionDetailSurface.tsx` | drafted | +| Console is blocked outside live execution-history mode | `terminal-transaction-read-model.ts`, UAPI read-model tests | drafted | +| Gate 2 checker is wired to package scripts and CI | `scripts/check-v29-gate2-terminal-transaction-read-models.mjs`, `package.json`, gate workflow | drafted | + +## Gate 2 accepted boundaries + +- Gate 2 does not implement wallet signing, PSBT, broadcast, reorg, or replacement depth. +- Gate 2 does not implement deeper Reading pipeline telemetry; Gate 4 owns that work. +- Gate 2 does not expose protected AssetPack source before settlement. +- Gate 2 does not add versioned API routes or source identifiers. + +## Gate 2 completion condition + +Gate 2 is complete when Terminal selected transaction state rewrites recoverable URLs, a typed read model drives detail navigation and low-detail summaries, focused tests pass, `check:v29-gate2` passes, CI invokes the checker, docs name the implemented source surfaces, and the gate branch is committed and pushed for review into `version/v29`. diff --git a/package.json b/package.json index f02eb3ef2..1aaa9ac23 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "check:v28-gate12": "node scripts/check-v28-gate12-settlement-rights-delivery.mjs", "check:v28-gate13": "node scripts/check-v28-gate13-product-closure-promotion-readiness.mjs", "check:v29-gate1": "node scripts/check-v29-gate1-objectives-and-gating.mjs", + "check:v29-gate2": "node scripts/check-v29-gate2-terminal-transaction-read-models.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/scripts/check-v29-gate2-terminal-transaction-read-models.mjs b/scripts/check-v29-gate2-terminal-transaction-read-models.mjs new file mode 100755 index 000000000..b248ea283 --- /dev/null +++ b/scripts/check-v29-gate2-terminal-transaction-read-models.mjs @@ -0,0 +1,219 @@ +#!/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-v29-gate2-terminal-transaction-read-models.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 2 Terminal transaction read-model and navigation closure.', + ].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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 Gate 2 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-2-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 2 work must occur on version/v29 or v29/gate-2-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'uapi/app/terminal/terminal-transaction-read-model.ts', + 'uapi/app/terminal/terminal-transaction-query.ts', + 'uapi/app/terminal/TerminalPageClient.tsx', + 'uapi/app/terminal/TerminalTransactionWorkspace.tsx', + 'uapi/app/terminal/TerminalTransactionDetailSurface.tsx', + 'uapi/app/terminal/TerminalTransactionDetailActionBar.tsx', + 'uapi/tests/terminalTransactionReadModel.test.ts', + 'uapi/tests/terminalTransactionQuery.test.ts', + 'uapi/app/terminal/README.md', + 'package.json', + '.github/workflows/bitcode-gate-quality.yml', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 2 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const readModel = read(root, 'uapi/app/terminal/terminal-transaction-read-model.ts'); + const query = read(root, 'uapi/app/terminal/terminal-transaction-query.ts'); + const pageClient = read(root, 'uapi/app/terminal/TerminalPageClient.tsx'); + const detailSurface = read(root, 'uapi/app/terminal/TerminalTransactionDetailSurface.tsx'); + const actionBar = read(root, 'uapi/app/terminal/TerminalTransactionDetailActionBar.tsx'); + const readModelTest = read(root, 'uapi/tests/terminalTransactionReadModel.test.ts'); + const queryTest = read(root, 'uapi/tests/terminalTransactionQuery.test.ts'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + assertCheck(failures, spec.includes('V29 Terminal transaction read-model canon'), 'V29 SPEC must define the Terminal transaction read-model canon.'); + assertCheck(failures, delta.includes('Closure acceptance:'), 'V29 DELTA must list Gate 2 closure acceptance.'); + assertCheck(failures, notes.includes('Gate 2 working notes'), 'V29 NOTES must carry Gate 2 working notes.'); + assertCheck(failures, parity.includes('## Gate 2 Parity'), 'V29 PARITY must include Gate 2 parity.'); + assertCheck(failures, parity.includes('Gate 2 completion condition'), 'V29 PARITY must include Gate 2 completion condition.'); + + for (const requiredSymbol of [ + 'TerminalTransactionReadModel', + 'TerminalTransactionSectionReadModel', + 'buildTerminalTransactionReadModel', + 'TerminalTransactionSectionAvailability', + 'routeHref', + 'payloadAvailable', + ]) { + assertCheck(failures, readModel.includes(requiredSymbol), `Read model is missing ${requiredSymbol}.`); + } + + assertCheck( + failures, + readModel.includes("'blocked'") && + readModel.includes('Console detail is available only for live execution-history rows.'), + 'Read model must block console outside live execution-history rows.', + ); + assertCheck( + failures, + query.includes('shouldRecoverTerminalTransactionRoute'), + 'Terminal query helpers must expose default route recovery.', + ); + assertCheck( + failures, + pageClient.includes('shouldRecoverTerminalTransactionRoute'), + 'Terminal page must use route recovery for the first selectable transaction.', + ); + assertCheck( + failures, + detailSurface.includes('buildTerminalTransactionReadModel') && + detailSurface.includes('detailActions={transactionReadModel.sections.map'), + 'Detail surface must derive and use the typed transaction read model.', + ); + assertCheck( + failures, + actionBar.includes('detailActions') && actionBar.includes('disabledReason'), + 'Detail action bar must render read-model section navigation and blockers.', + ); + assertCheck( + failures, + readModelTest.includes('buildTerminalTransactionReadModel') && + readModelTest.includes('route.selectionRecoverable') && + readModelTest.includes("availability: 'blocked'"), + 'Read-model tests must cover route recovery and blocked sections.', + ); + assertCheck( + failures, + queryTest.includes('shouldRecoverTerminalTransactionRoute'), + 'Query tests must cover default transaction route recovery.', + ); + assertCheck( + failures, + terminalReadme.includes('TerminalTransactionReadModel') && + terminalReadme.includes('Former `runId` links are still accepted on read and rewritten on write.'), + 'Terminal README must document the Gate 2 read-model and legacy runId rewrite.', + ); + assertCheck(failures, packageJson.includes('"check:v29-gate2"'), 'package.json must expose check:v29-gate2.'); + assertCheck( + failures, + gateWorkflow.includes('check-v29-gate2-terminal-transaction-read-models.mjs'), + 'Gate quality workflow must run the Gate 2 checker.', + ); + assertCheck( + failures, + gateWorkflow.includes('tests/terminalTransactionReadModel.test.ts'), + 'Gate quality workflow must run the read-model tests.', + ); + + const versionedTerminalSource = execFileSync('find', ['uapi/app/terminal', '-name', '*v29*', '-print'], { + cwd: root, + encoding: 'utf8', + }).trim(); + assertCheck( + failures, + versionedTerminalSource.length === 0, + `Terminal source identifiers must remain unversioned. Found:\n${versionedTerminalSource}`, + ); + + if (failures.length > 0) { + process.stderr.write('V29 Gate 2 Terminal transaction read-model check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write(`V29 Gate 2 Terminal transaction read-model 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; +} diff --git a/uapi/app/exchange/ExchangePageClient.tsx b/uapi/app/exchange/ExchangePageClient.tsx index aba403aeb..db485663d 100644 --- a/uapi/app/exchange/ExchangePageClient.tsx +++ b/uapi/app/exchange/ExchangePageClient.tsx @@ -187,6 +187,7 @@ export default function ExchangePageClient() { { - if (!runs.length) return; - if (selectedTransactionId && runs.some((run) => run.id === selectedTransactionId)) return; - const hasRouteContext = - typeof window !== 'undefined' - ? window.location.pathname === TERMINAL_ROUTE && window.location.search.length > 1 - : searchParams.toString().length > 0; - if (!hasRouteContext) return; + if ( + !shouldRecoverTerminalTransactionRoute({ + transactionIds: runs.map((run) => run.id), + selectedTransactionId, + }) + ) { + return; + } const nextParams = writeTerminalTransactionId(readCurrentTerminalSearchParams(), runs[0].id); replaceTerminalSearchParams(nextParams); }, [ @@ -496,6 +498,7 @@ export default function TerminalPageClient() { void; onRunClosure: () => void; onRefreshDetail: () => void; @@ -33,6 +36,7 @@ interface TerminalTransactionDetailActionBarProps { export default function TerminalTransactionDetailActionBar({ activeSection, + detailActions = DETAIL_ACTIONS, onChangeSection, onRunClosure, onRefreshDetail, @@ -41,7 +45,17 @@ export default function TerminalTransactionDetailActionBar({ mockMode, surface = 'terminal', }: TerminalTransactionDetailActionBarProps) { - const visibleActions = mockMode ? DETAIL_ACTIONS.filter((action) => action.id !== 'console') : DETAIL_ACTIONS; + const visibleActions = mockMode + ? detailActions.map((action) => + action.id === 'console' + ? { + ...action, + disabled: true, + disabledReason: action.disabledReason || 'Console detail is available only for live execution-history rows.', + } + : action, + ) + : detailActions; const isExchangeSurface = surface === 'exchange'; const witnessActionDisabled = isActing || !shellReady; const witnessActionDisabledTooltip = isActing @@ -104,20 +118,29 @@ export default function TerminalTransactionDetailActionBar({
- {visibleActions.map((action) => ( - - ))} + {visibleActions.map((action) => { + const sectionButton = ( + + ); + + return action.disabled && action.disabledReason ? ( + + {sectionButton} + + ) : sectionButton; + })}
); diff --git a/uapi/app/terminal/TerminalTransactionDetailHero.tsx b/uapi/app/terminal/TerminalTransactionDetailHero.tsx index 54ac02529..36359d307 100644 --- a/uapi/app/terminal/TerminalTransactionDetailHero.tsx +++ b/uapi/app/terminal/TerminalTransactionDetailHero.tsx @@ -10,6 +10,10 @@ interface TerminalTransactionDetailHeroProps { proofPosture: string; modeLabel: string; metrics: Array<{ label: string; value: string }>; + routeHref?: string; + activeSectionLabel?: string; + activeSectionAvailability?: string; + postureChips?: string[]; surface?: 'terminal' | 'exchange'; } @@ -19,6 +23,10 @@ export default function TerminalTransactionDetailHero({ proofPosture, modeLabel, metrics, + routeHref, + activeSectionLabel, + activeSectionAvailability, + postureChips = [], surface = 'terminal', }: TerminalTransactionDetailHeroProps) { const kicker = @@ -47,8 +55,35 @@ export default function TerminalTransactionDetailHero({ />
-

Activity posture

-

{proofPosture}

+
+
+

Activity posture

+

{proofPosture}

+
+ {activeSectionLabel ? ( +
+ {activeSectionLabel} + {activeSectionAvailability ? ` / ${activeSectionAvailability}` : ''} +
+ ) : null} +
+ {postureChips.length ? ( +
+ {postureChips.slice(0, 5).map((chip) => ( + + {chip} + + ))} +
+ ) : null} + {routeHref ? ( +

+ {routeHref} +

+ ) : null}
); diff --git a/uapi/app/terminal/TerminalTransactionDetailSurface.tsx b/uapi/app/terminal/TerminalTransactionDetailSurface.tsx index 6ef9e02ca..e3f938e45 100644 --- a/uapi/app/terminal/TerminalTransactionDetailSurface.tsx +++ b/uapi/app/terminal/TerminalTransactionDetailSurface.tsx @@ -35,8 +35,8 @@ import { buildTerminalTransactionClosureFollowThrough, buildTerminalTransactionClosureRows, buildTerminalTransactionIdentityRows, - buildTerminalTransactionOverviewMetrics, } from './terminal-transaction-detail'; +import { buildTerminalTransactionReadModel } from './terminal-transaction-read-model'; import { jumpToShellSection } from './terminal-shell-reading'; import { useTerminalShellBridge } from './terminal-shell-bridge'; @@ -61,6 +61,7 @@ interface TerminalTransactionDetailSurfaceProps { transactionDataMode: TransactionDataMode; detailSection: TerminalTransactionDetailSection; onDetailSectionChange: (detailSection: TerminalTransactionDetailSection) => void; + routeSearchParams: URLSearchParams; onRecordActivity?: (draft: TerminalActivityRecordDraft) => Promise; surface?: 'terminal' | 'exchange'; } @@ -73,6 +74,7 @@ export default function TerminalTransactionDetailSurface({ transactionDataMode, detailSection, onDetailSectionChange, + routeSearchParams, onRecordActivity, surface = 'terminal', }: TerminalTransactionDetailSurfaceProps) { @@ -101,36 +103,29 @@ export default function TerminalTransactionDetailSurface({ const showHistory = detailSection === 'history'; const showJournal = detailSection === 'journal'; const showActivity = detailSection === 'activity'; - const showConsole = detailSection === 'console' && !usesMockTransactions; + const transactionReadModel = useMemo( + () => + buildTerminalTransactionReadModel({ + selectedRun, + detail, + detailSection, + dataMode: transactionDataMode, + searchParams: routeSearchParams, + }), + [detail, detailSection, routeSearchParams, selectedRun, transactionDataMode], + ); + const showConsole = detailSection === 'console' && transactionReadModel.activeSection.availability !== 'blocked'; const selectedActivityNoun = surface === 'exchange' ? 'selected Bitcode activity detail' : 'selected Terminal activity result'; - const activeFocusNoun = surface === 'exchange' ? 'detail focus' : 'result focus'; const normalizedSummary = detail?.summary || `The ${selectedActivityNoun} is loaded.`; const sectionSummary = useMemo(() => { - if (showTransaction) { - return `${normalizedSummary} Activity identity, repository, and timing posture are the active ${activeFocusNoun}.`; - } - if (showClosure) { - return `${normalizedSummary} Closure proof, settlement follow-through, and re-run controls are the active ${activeFocusNoun}.`; - } - if (showProofs) { - return `${normalizedSummary} Proof families and bounded verification posture are the active ${activeFocusNoun}.`; - } - if (showHistory) { - return `${normalizedSummary} Ledger-linked activity history and recent closure continuity are the active ${activeFocusNoun}.`; - } - if (showJournal) { - return `${normalizedSummary} Journal reconciliation, ledger observations, database projections, and root-bound canonical facts are the active ${activeFocusNoun}.`; - } - if (showActivity) { - return `${normalizedSummary} Activity streaming, work updates, and retained execution posture are the active ${activeFocusNoun}.`; - } - if (showConsole) { - return `${normalizedSummary} The execution console remains available when you read the lower-level witness detail.`; - } - return `${normalizedSummary} Finish-delivered pull-request Shippables, stored AssetPack evidence, and summary text are the active ${activeFocusNoun}.`; - }, [activeFocusNoun, normalizedSummary, showActivity, showClosure, showConsole, showHistory, showJournal, showProofs, showTransaction]); + const activeSectionBlocker = transactionReadModel.activeSection.blocker + ? ` ${transactionReadModel.activeSection.blocker}` + : ''; + const activeSectionSummary = `${transactionReadModel.activeSection.summary}${activeSectionBlocker}`; + return `${normalizedSummary} ${activeSectionSummary}`; + }, [normalizedSummary, transactionReadModel.activeSection]); const transactionPayload = useMemo( () => ({ transaction: { @@ -225,7 +220,6 @@ export default function TerminalTransactionDetailSurface({ ); } - const overviewMetrics = buildTerminalTransactionOverviewMetrics(selectedRun, detail); const identityRows = buildTerminalTransactionIdentityRows(selectedRun, detail); const closureRows = buildTerminalTransactionClosureRows(detail); @@ -296,16 +290,26 @@ export default function TerminalTransactionDetailSurface({
({ + id: section.id, + label: section.label, + disabled: section.availability === 'blocked', + disabledReason: section.blocker || undefined, + }))} onChangeSection={onDetailSectionChange} onRunClosure={() => { void handleRunClosure(); diff --git a/uapi/app/terminal/TerminalTransactionWorkspace.tsx b/uapi/app/terminal/TerminalTransactionWorkspace.tsx index e564141bc..da6f4dccc 100644 --- a/uapi/app/terminal/TerminalTransactionWorkspace.tsx +++ b/uapi/app/terminal/TerminalTransactionWorkspace.tsx @@ -219,6 +219,7 @@ function buildActivitySubstructures( interface TerminalTransactionWorkspaceProps { runs: WorkspaceRun[]; selectedRun: WorkspaceRun | null; + routeSearchParams: URLSearchParams; filters: TransactionFilters; onFiltersChange: (nextFilters: TransactionFilters) => void; onResetFilters: () => void; @@ -237,6 +238,7 @@ interface TerminalTransactionWorkspaceProps { export default function TerminalTransactionWorkspace({ runs, selectedRun, + routeSearchParams, filters, onFiltersChange, onResetFilters, @@ -360,6 +362,7 @@ export default function TerminalTransactionWorkspace({ transactionDataMode={transactionDataMode} detailSection={detailSection} onDetailSectionChange={onDetailSectionChange} + routeSearchParams={routeSearchParams} onRecordActivity={onRecordActivity} surface={surface} /> diff --git a/uapi/app/terminal/terminal-transaction-query.ts b/uapi/app/terminal/terminal-transaction-query.ts index 9c14fd13b..0239f4426 100644 --- a/uapi/app/terminal/terminal-transaction-query.ts +++ b/uapi/app/terminal/terminal-transaction-query.ts @@ -230,6 +230,16 @@ export function writeTerminalTransactionPagination( return nextParams; } +export function shouldRecoverTerminalTransactionRoute({ + transactionIds, + selectedTransactionId, +}: { + transactionIds: string[]; + selectedTransactionId: string | null; +}) { + return transactionIds.length > 0 && (!selectedTransactionId || !transactionIds.includes(selectedTransactionId)); +} + export function resetTerminalTransactionFilters(searchParams: URLSearchParams) { const nextParams = new URLSearchParams(searchParams.toString()); nextParams.delete(SEARCH_PARAM_KEYS.search); diff --git a/uapi/app/terminal/terminal-transaction-read-model.ts b/uapi/app/terminal/terminal-transaction-read-model.ts new file mode 100644 index 000000000..d5eeebb75 --- /dev/null +++ b/uapi/app/terminal/terminal-transaction-read-model.ts @@ -0,0 +1,356 @@ +import type { + TransactionDataMode, +} from '@/components/base/bitcode/execution/bitcode-transaction-types'; +import { buildTerminalHref } from './terminal-routes'; +import { + readTerminalTransactionId, + type TerminalTransactionDetailSection, + writeTerminalTransactionDetailSection, + writeTerminalTransactionId, +} from './terminal-transaction-query'; +import type { TerminalRunDetailSnapshot } from './terminal-transaction-detail-snapshot'; +import type { WorkspaceRun } from './terminal-run-data'; +import { normalizeTerminalTransactions, type TerminalTransactionRecord } from './terminal-transactions'; + +export type TerminalTransactionSectionAvailability = 'available' | 'empty' | 'blocked'; +export type TerminalTransactionFactFamily = + | 'delivery' + | 'identity' + | 'settlement' + | 'proof' + | 'ledger' + | 'execution'; + +export type TerminalTransactionSectionReadModel = { + id: TerminalTransactionDetailSection; + label: string; + summary: string; + targetId: string; + routeHref: string; + availability: TerminalTransactionSectionAvailability; + blocker: string | null; + factFamily: TerminalTransactionFactFamily; + metricCount: number; + rowCount: number; + payloadAvailable: boolean; +}; + +export type TerminalTransactionLowDetailReadModel = { + title: string; + summary: string; + proofPosture: string; + metrics: Array<{ label: string; value: string }>; + postureChips: string[]; +}; + +export type TerminalTransactionRouteReadModel = { + transactionId: string; + routeTransactionId: string | null; + activeSection: TerminalTransactionDetailSection; + href: string; + selectionRecoverable: boolean; +}; + +export type TerminalTransactionReadModel = { + transaction: TerminalTransactionRecord; + dataMode: TransactionDataMode; + route: TerminalTransactionRouteReadModel; + lowDetail: TerminalTransactionLowDetailReadModel; + sections: TerminalTransactionSectionReadModel[]; + activeSection: TerminalTransactionSectionReadModel; + expandableDetail: { + rawPayloadAvailable: boolean; + detailPayloadAvailable: boolean; + auditSectionsAvailable: number; + }; +}; + +const SECTION_DEFINITIONS: Array<{ + id: TerminalTransactionDetailSection; + label: string; + targetId: string; + summary: string; + factFamily: TerminalTransactionFactFamily; +}> = [ + { + id: 'shippables', + label: 'Shippables', + targetId: 'terminalTransactionShippables', + summary: 'Finish-delivered pull-request output and source-safe AssetPack evidence.', + factFamily: 'delivery', + }, + { + id: 'transaction', + label: 'Identity', + targetId: 'terminalTransactionTransaction', + summary: 'Transaction identity, route selection, repository, participant, and timing facts.', + factFamily: 'identity', + }, + { + id: 'closure', + label: 'Closure', + targetId: 'terminalTransactionClosure', + summary: 'Closure posture, settlement metrics, branch artifacts, and follow-through controls.', + factFamily: 'settlement', + }, + { + id: 'proofs', + label: 'Proofs', + targetId: 'terminalTransactionProofs', + summary: 'Proof posture, proof-family artifacts, and bounded verification facts.', + factFamily: 'proof', + }, + { + id: 'history', + label: 'History', + targetId: 'terminalTransactionHistory', + summary: 'Recent execution history and ledger-linked continuity for this activity.', + factFamily: 'execution', + }, + { + id: 'journal', + label: 'Journal', + targetId: 'terminalTransactionJournal', + summary: 'Journal rows, ledger observations, database projections, and repair receipts.', + factFamily: 'ledger', + }, + { + id: 'activity', + label: 'Execution stream', + targetId: 'terminalTransactionActivity', + summary: 'Retained execution stream, work updates, and activity telemetry posture.', + factFamily: 'execution', + }, + { + id: 'console', + label: 'Console', + targetId: 'terminalTransactionConsole', + summary: 'Detailed execution console for live execution-history rows.', + factFamily: 'execution', + }, +]; + +function formatNumber(value?: number | null, options?: Intl.NumberFormatOptions) { + if (value === null || value === undefined || Number.isNaN(value)) return 'n/a'; + return new Intl.NumberFormat('en-US', options).format(value); +} + +function formatUsd(value?: number | null) { + if (value === null || value === undefined || Number.isNaN(value)) return 'n/a'; + return new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + maximumFractionDigits: 2, + }).format(value); +} + +function countShippableSurfaces(detail: TerminalRunDetailSnapshot | null) { + let count = 0; + if (detail?.shippables?.pullRequest || detail?.deliveryMechanism?.pullRequest) count += 1; + if (detail?.writtenAssets?.fileChanges || detail?.writtenAssets?.summary) count += 1; + return count; +} + +function countJournalRows(detail: TerminalRunDetailSnapshot | null) { + return ( + (detail?.terminalJournal?.entries.length || 0) + + (detail?.terminalJournal?.repairs.length || 0) + + (detail?.terminalJournal?.readErrors.length || 0) + ); +} + +function createSectionHref( + searchParams: URLSearchParams, + transactionId: string, + detailSection: TerminalTransactionDetailSection, +) { + return buildTerminalHref( + writeTerminalTransactionDetailSection( + writeTerminalTransactionId(searchParams, transactionId), + detailSection, + ), + ); +} + +function resolveSectionAvailability({ + sectionId, + selectedRun, + detail, + dataMode, +}: { + sectionId: TerminalTransactionDetailSection; + selectedRun: WorkspaceRun; + detail: TerminalRunDetailSnapshot | null; + dataMode: TransactionDataMode; +}): Pick { + if (sectionId === 'console') { + const consoleAvailable = dataMode === 'live' && selectedRun.sourceModel === 'execution-history'; + return { + availability: consoleAvailable ? 'available' : 'blocked', + blocker: consoleAvailable + ? null + : 'Console detail is available only for live execution-history rows.', + metricCount: 0, + rowCount: 0, + payloadAvailable: consoleAvailable, + }; + } + + if (sectionId === 'shippables') { + const shippableCount = countShippableSurfaces(detail); + return { + availability: shippableCount > 0 ? 'available' : 'empty', + blocker: shippableCount > 0 ? null : 'No source-safe Shippables or paid delivery evidence is attached yet.', + metricCount: 1, + rowCount: detail?.shippables?.pullRequest || detail?.deliveryMechanism?.pullRequest ? 1 : 0, + payloadAvailable: shippableCount > 0, + }; + } + + if (sectionId === 'transaction') { + return { + availability: 'available', + blocker: null, + metricCount: 4, + rowCount: detail ? 8 : 5, + payloadAvailable: Boolean(detail), + }; + } + + if (sectionId === 'closure') { + const hasClosure = + Boolean(detail?.closureState) || + Boolean(detail?.closureFollowThrough) || + Boolean(detail?.ledgerSettlement) || + 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, + payloadAvailable: hasClosure, + }; + } + + if (sectionId === 'proofs') { + const proofCount = detail?.closureFollowThrough?.proofFamilies.length || 0; + const hasProof = proofCount > 0 || Boolean(detail?.proofStatus || selectedRun.proofStatus); + return { + availability: hasProof ? 'available' : 'empty', + blocker: hasProof ? null : 'No proof-family detail is attached yet.', + metricCount: proofCount || 1, + rowCount: proofCount, + payloadAvailable: hasProof, + }; + } + + if (sectionId === 'history') { + const historyCount = detail?.historyItemCount ?? selectedRun.itemCount ?? 0; + const recentHistoryCount = detail?.closureFollowThrough?.recentHistory.length || 0; + return { + availability: historyCount > 0 || recentHistoryCount > 0 ? 'available' : 'empty', + blocker: historyCount > 0 || recentHistoryCount > 0 ? null : 'No retained history rows are attached yet.', + metricCount: 2, + rowCount: historyCount + recentHistoryCount, + payloadAvailable: historyCount > 0 || recentHistoryCount > 0, + }; + } + + if (sectionId === 'journal') { + const journalRows = countJournalRows(detail); + const hasLedger = journalRows > 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, + payloadAvailable: hasLedger, + }; + } + + const eventCount = detail?.eventCount || 0; + return { + availability: eventCount > 0 || selectedRun.sourceModel === 'execution-history' ? 'available' : 'empty', + blocker: + eventCount > 0 || selectedRun.sourceModel === 'execution-history' + ? null + : 'Execution-stream events are not attached to this projected row yet.', + metricCount: 2, + rowCount: eventCount, + payloadAvailable: eventCount > 0, + }; +} + +export function buildTerminalTransactionReadModel({ + selectedRun, + detail, + detailSection, + dataMode, + searchParams = new URLSearchParams(), +}: { + selectedRun: WorkspaceRun; + detail: TerminalRunDetailSnapshot | null; + detailSection: TerminalTransactionDetailSection; + dataMode: TransactionDataMode; + searchParams?: URLSearchParams; +}): TerminalTransactionReadModel { + const transaction = normalizeTerminalTransactions([selectedRun])[0]; + const routeTransactionId = readTerminalTransactionId(searchParams); + const route: TerminalTransactionRouteReadModel = { + transactionId: selectedRun.id, + routeTransactionId, + activeSection: detailSection, + href: createSectionHref(searchParams, selectedRun.id, detailSection), + selectionRecoverable: routeTransactionId === selectedRun.id, + }; + const sections = SECTION_DEFINITIONS.map((definition) => ({ + ...definition, + routeHref: createSectionHref(searchParams, selectedRun.id, definition.id), + ...resolveSectionAvailability({ + sectionId: definition.id, + selectedRun, + detail, + dataMode, + }), + })); + const activeSection = + sections.find((section) => section.id === detailSection) || + sections.find((section) => section.id === 'shippables') || + sections[0]; + const postureChips = [ + transaction.transactionLens, + transaction.status, + transaction.repository, + activeSection.availability === 'blocked' ? 'blocked detail' : activeSection.factFamily, + ].filter(Boolean); + const rawPayloadAvailable = Boolean(detail); + const auditSectionsAvailable = sections.filter((section) => section.payloadAvailable).length; + + return { + transaction, + dataMode, + route, + lowDetail: { + title: transaction.typeLabel || transaction.type, + summary: + detail?.summary || + transaction.summary || + 'Selected Terminal transaction is loaded for typed operator review.', + proofPosture: detail?.proofStatus || transaction.proofStatus || 'closure state in flight', + metrics: [ + { label: 'Shippables', value: formatNumber(countShippableSurfaces(detail)) }, + { label: 'History items', value: formatNumber(detail?.historyItemCount ?? transaction.itemCount) }, + { label: 'Measured $BTD', value: formatNumber(detail?.processingStats.measuredBtd ?? transaction.measuredBtd, { maximumFractionDigits: 1 }) }, + { label: 'BTC fee basis', value: formatUsd(detail?.processingStats.btcFeeUsdEquivalent ?? transaction.btcFeeUsdEquivalent) }, + ], + postureChips, + }, + sections, + activeSection, + expandableDetail: { + rawPayloadAvailable, + detailPayloadAvailable: sections.some((section) => section.payloadAvailable), + auditSectionsAvailable, + }, + }; +} diff --git a/uapi/jest.config.cjs b/uapi/jest.config.cjs index 9a1282a71..b2bb78224 100644 --- a/uapi/jest.config.cjs +++ b/uapi/jest.config.cjs @@ -147,6 +147,7 @@ module.exports = { '/tests/terminalTransactionDetailCards.test.tsx', '/tests/terminalTransactionDetailSnapshot.test.ts', '/tests/terminalTransactionQuery.test.ts', + '/tests/terminalTransactionReadModel.test.ts', '/tests/terminalCoreNativeSections.test.tsx', '/tests/terminalDepositComposer.test.ts', '/tests/terminalDepositComposerCard.test.tsx', diff --git a/uapi/tests/terminalTransactionQuery.test.ts b/uapi/tests/terminalTransactionQuery.test.ts index 32e154dd5..1f72f712e 100644 --- a/uapi/tests/terminalTransactionQuery.test.ts +++ b/uapi/tests/terminalTransactionQuery.test.ts @@ -6,6 +6,7 @@ import { readTerminalTransactionId, readTerminalTransactionPagination, resetTerminalTransactionFilters, + shouldRecoverTerminalTransactionRoute, writeTerminalDebugEnabled, writeTerminalEnvironmentMode, writeTerminalTransactionDetailSection, @@ -107,6 +108,33 @@ describe('terminal-transaction-query', () => { expect(nextParams.get('provider')).toBe('github'); }); + it('decides when Terminal should recover selected transaction route state', () => { + expect( + shouldRecoverTerminalTransactionRoute({ + transactionIds: ['tx-1', 'tx-2'], + selectedTransactionId: null, + }), + ).toBe(true); + expect( + shouldRecoverTerminalTransactionRoute({ + transactionIds: ['tx-1', 'tx-2'], + selectedTransactionId: 'tx-missing', + }), + ).toBe(true); + expect( + shouldRecoverTerminalTransactionRoute({ + transactionIds: ['tx-1', 'tx-2'], + selectedTransactionId: 'tx-2', + }), + ).toBe(false); + expect( + shouldRecoverTerminalTransactionRoute({ + transactionIds: [], + selectedTransactionId: null, + }), + ).toBe(false); + }); + it('reads and writes transaction pagination through route query state', () => { expect( readTerminalTransactionPagination(new URLSearchParams('transactionPage=3&transactionPageSize=25')), diff --git a/uapi/tests/terminalTransactionReadModel.test.ts b/uapi/tests/terminalTransactionReadModel.test.ts new file mode 100644 index 000000000..ecd1387eb --- /dev/null +++ b/uapi/tests/terminalTransactionReadModel.test.ts @@ -0,0 +1,173 @@ +import { + buildTerminalTransactionReadModel, +} from '@/app/terminal/terminal-transaction-read-model'; +import type { WorkspaceRun } from '@/app/terminal/terminal-run-data'; +import type { TerminalRunDetailSnapshot } from '@/app/terminal/terminal-transaction-detail-snapshot'; + +const selectedRun: WorkspaceRun = { + id: 'tx-read-1', + created_at: '2026-05-20T12:00:00.000Z', + type: 'agentic-execution:read-measurement', + status: 'completed', + summary: 'Read Need accepted and ready for Finding Fits.', + repository: 'engineeredsoftware/ENGI', + branch: 'main', + sourceModel: 'execution-history', + participant: 'engineeredsoftware', + isOwnTransaction: true, + transactionLens: 'read', + itemCount: 2, + tokenTotal: 1200, + measuredBtd: 42.25, + btcFeeUsdEquivalent: 2.75, + proofStatus: 'read measurement accepted', + closureFocus: 'Read Need review', +}; + +const detail: TerminalRunDetailSnapshot = { + summary: 'Accepted Read Need for Finding Fits.', + shippables: null, + writtenAssets: { + pullRequest: null, + fileChanges: { + edited: 2, + created: 1, + deleted: 0, + paths: ['BITCODE_READ_NEED.md'], + }, + summary: 'Source-safe AssetPack preview metadata is attached.', + }, + deliveryMechanism: null, + repoSnapshot: { + org: 'engineeredsoftware', + repo: 'ENGI', + branch: 'main', + commit: 'abc123', + }, + processingStats: { + time: '1m', + tokenTotal: 2400, + measuredBtd: 50.5, + btcFeeUsdEquivalent: 3.1, + averageLatencyMs: 900, + }, + proofStatus: 'source-safe preview ready', + closureFocus: 'AssetPack preview', + closureFollowThrough: { + canonLabel: 'Bitcode active posture', + settlementMetrics: [{ label: 'Settlement', value: 'blocked before payment' }], + branchArtifacts: ['BITCODE_READ_NEED.md'], + proofFamilies: [ + { + label: 'preview-boundary', + artifactPath: '.bitcode/preview-boundary.json', + theoremStatus: 'passed', + replayArtifacts: '1', + }, + ], + recentHistory: [{ label: 'Read accepted', summary: 'Need reviewed.' }], + }, + closureState: null, + ledgerSettlement: { + status: 'preview_only', + settlementAdmissible: false, + reason: 'Awaiting BTC fee payment.', + assetPackId: 'asset-pack-1', + btdRange: null, + ledgerAnchorId: 'anchor-1', + btcFeeReceiptId: null, + depositorWalletId: 'wallet-depositor', + readerWalletId: 'wallet-reader', + btcFee: null, + ownershipBoundary: null, + readback: { assetPackRange: true }, + journalEntryIds: ['journal-1'], + ownershipEventId: null, + readLicenseId: null, + }, + terminalJournal: { + expectedJournalEntryIds: ['journal-1'], + entries: [], + repairs: [], + ledgerRows: { + assetPackRanges: [], + btcFeeTransactions: [], + ledgerAnchors: [], + ownershipEvents: [], + readLicenses: [], + }, + readErrors: [], + }, + bitcodeActivityState: null, + historyItemCount: 3, + eventCount: 7, +}; + +describe('terminal transaction read model', () => { + it('builds a route-owned low-detail projection for the selected transaction', () => { + const model = buildTerminalTransactionReadModel({ + selectedRun, + detail, + detailSection: 'proofs', + dataMode: 'live', + searchParams: new URLSearchParams( + 'runId=legacy-run&provider=github&transactionSearch=need', + ), + }); + + expect(model.transaction).toMatchObject({ + id: 'tx-read-1', + repository: 'engineeredsoftware/ENGI', + transactionLens: 'read', + }); + expect(model.route.href).toContain('/terminal?'); + expect(model.route.href).toContain('transactionId=tx-read-1'); + expect(model.route.href).toContain('transactionDetail=proofs'); + expect(model.route.href).toContain('provider=github'); + expect(model.route.href).not.toContain('runId=legacy-run'); + expect(model.route.selectionRecoverable).toBe(false); + expect(model.lowDetail.metrics).toEqual( + expect.arrayContaining([ + { label: 'Shippables', value: '1' }, + { label: 'Measured $BTD', value: '50.5' }, + ]), + ); + expect(model.activeSection).toMatchObject({ + id: 'proofs', + availability: 'available', + factFamily: 'proof', + }); + }); + + it('marks empty and blocked sections explicitly without raw payload dependency', () => { + const model = buildTerminalTransactionReadModel({ + selectedRun: { + ...selectedRun, + sourceModel: 'mock-review', + }, + detail: { + ...detail, + writtenAssets: null, + closureFollowThrough: null, + terminalJournal: null, + eventCount: 0, + }, + detailSection: 'console', + dataMode: 'mock-review', + searchParams: new URLSearchParams('transactionId=tx-read-1'), + }); + + expect(model.route.selectionRecoverable).toBe(true); + expect(model.sections.find((section) => section.id === 'shippables')).toMatchObject({ + availability: 'empty', + payloadAvailable: false, + }); + expect(model.sections.find((section) => section.id === 'console')).toMatchObject({ + availability: 'blocked', + blocker: 'Console detail is available only for live execution-history rows.', + payloadAvailable: false, + }); + expect(model.expandableDetail.rawPayloadAvailable).toBe(true); + expect(model.expandableDetail.auditSectionsAvailable).toBeGreaterThan(0); + }); +}); From 94abf30129497a89ad3313936b4cb21e1b5c5c11 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Wed, 20 May 2026 14:25:46 -0300 Subject: [PATCH 03/18] Define wallet signer BTC operations (#22) Close V29 Gate 3 with BTD-owned BTC fee quote lifecycle, signer-session recovery, blocked-readiness receipts, and operation posture. Expose operation posture through the BTC fee route and add a source-safe Terminal Wallet/BTC detail section with focused package, route, UI, spec, and gate-quality coverage. --- .github/workflows/bitcode-gate-quality.yml | 3 + BITCODE_SPEC_V29.md | 36 +- BITCODE_SPEC_V29_DELTA.md | 10 + BITCODE_SPEC_V29_NOTES.md | 14 + BITCODE_SPEC_V29_PARITY_MATRIX.md | 26 +- package.json | 1 + .../src/routes/__tests__/btd-crypto.test.ts | 42 +- packages/api/src/routes/btd-crypto.ts | 42 +- .../btd/__tests__/btc-fee-operation.test.ts | 237 ++++++++ packages/btd/src/btc-fee-operation.ts | 553 ++++++++++++++++++ packages/btd/src/index.ts | 1 + ...v29-gate3-wallet-signer-btc-operations.mjs | 250 ++++++++ uapi/app/terminal/README.md | 15 +- .../TerminalTransactionDetailSurface.tsx | 13 + .../TerminalTransactionWalletBtcCard.tsx | 46 ++ .../terminal/terminal-transaction-query.ts | 2 + .../terminal-transaction-read-model.ts | 24 + .../terminal/terminal-wallet-btc-operation.ts | 201 +++++++ uapi/jest.config.cjs | 1 + .../terminalTransactionReadModel.test.ts | 14 +- uapi/tests/terminalWalletBtcOperation.test.ts | 145 +++++ 21 files changed, 1664 insertions(+), 12 deletions(-) create mode 100644 packages/btd/__tests__/btc-fee-operation.test.ts create mode 100644 packages/btd/src/btc-fee-operation.ts create mode 100755 scripts/check-v29-gate3-wallet-signer-btc-operations.mjs create mode 100644 uapi/app/terminal/TerminalTransactionWalletBtcCard.tsx create mode 100644 uapi/app/terminal/terminal-wallet-btc-operation.ts create mode 100644 uapi/tests/terminalWalletBtcOperation.test.ts diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 1987f2b59..3d84605ab 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -47,6 +47,7 @@ jobs: node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 node scripts/check-v29-gate1-objectives-and-gating.mjs --skip-branch-check node scripts/check-v29-gate2-terminal-transaction-read-models.mjs --skip-branch-check + node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs --skip-branch-check - name: Validate source casing and imports run: | @@ -62,6 +63,7 @@ jobs: - name: Test gate packages run: | pnpm --filter @bitcode/btd test + pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btc-fee-operation.test.ts 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 @@ -74,6 +76,7 @@ jobs: tests/terminalDepositReadWorkbench.test.ts \ tests/terminalTransactionQuery.test.ts \ tests/terminalTransactionReadModel.test.ts \ + tests/terminalWalletBtcOperation.test.ts \ tests/pipelineExecutionLogHeader.test.tsx \ --runInBand diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index b2b630985..4f0975226 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -157,6 +157,9 @@ The V29 domain model extends V28 operationally: - `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. - `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. @@ -191,7 +194,7 @@ 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, closure, proofs, history, journal, activity stream, and console; +- 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. @@ -199,6 +202,29 @@ The Terminal transaction read model must contain: 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. +## V29 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. + ## V29 canonical subsystem surfaces ### Depositing and asset supply @@ -265,10 +291,10 @@ It must tolerate partial live readback by preserving a fallback selected-run pro - 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, reorg, replacement, broadcast failure, or custody ambiguity blocks finality. -- Current proof obligations: quote root, 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 payment UI, and Supabase projections. -- Current validating commands and parity basis: BTD tests, settlement route tests, staging ledger/database readback, and V29 gate checks. +- 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 V29 gate checks. - Current accepted boundaries: value-bearing mainnet stays outside V29 unless separately approved. ### Proof contract, witnesses, and replay diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index fe95e4d01..25bb6a1c9 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -99,6 +99,16 @@ Closure acceptance: Gate 3 owns wallet connection depth, signer-session recovery, BTC fee quote lifecycle, PSBT handoff, broadcast/finality/replacement/reorg/failure states, blocked-readiness receipts, and no server-custody posture. +Closure acceptance: + +- `packages/btd` defines `BtcFeeQuote`, `WalletSignerSessionRecovery`, `BtcFeeBlockedReadinessReceipt`, and `BtcFeeOperationPosture`. +- BTC fee quotes have deterministic quote roots, accepted/expired/superseded/failed lifecycle transitions, BTC-only fee asset, and measurement-root pricing posture. +- Signer recovery distinguishes missing, prepared, stored reconnect, expired, revoked, failed, network mismatch, capability missing, server-custody rejected, and live authorized states. +- BTC fee operation posture maps accepted quote, PSBT-ready, signed, broadcast, confirmed, replaced, reorged, failed, and blocked states into next actions and settlement booleans. +- The BTC fee API serializes operation posture and accepts JSON-safe quote carriers without mutating registry rows unless explicitly requested. +- Terminal adds a Wallet/BTC transaction detail section with source-safe metrics, rows, blockers, quote root, signer session, PSBT handoff, txid, finality, and server-custody posture. +- Gate-quality CI runs the Gate 3 checker plus BTD operation and Terminal Wallet/BTC tests. + ### Gate 4: Reading Transaction Recovery And Pipeline Observability Gate 4 owns deep Terminal visibility over `ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis`, including execution, phase, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, output, and typed parse telemetry. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 4961b10fa..8498e5e84 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -56,6 +56,7 @@ For a simplified reading of V29: 3. **Gate 3: Wallet Signer Session And BTC Fee Operations** - Deepen signer-session recovery, BTC fee quote, PSBT handoff, broadcast, replacement, reorg, failure, and blocked-readiness states. + - Acceptance detail: BTC quote lifecycle and signer recovery are package-owned primitives; API responses expose JSON-safe operation posture; Terminal exposes Wallet/BTC as a route-owned transaction detail section with blockers before raw payloads. 4. **Gate 4: Reading Transaction Recovery And Pipeline Observability** - Make `ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis` execution telemetry fully readable in Terminal at execution, phase, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, raw output, and parsed output levels. @@ -106,6 +107,19 @@ The low-detail default should answer: The detailed view may still carry raw payload accordions for audit, but the ordinary collapsed view must be typed and readable. +## Gate 3 working notes + +Gate 3 makes wallet and BTC fee operation readable and typed before the later settlement-repair gate. + +Accepted Gate 3 posture: + +- BTC fee quote lifecycle and quote-root derivation live in `packages/btd`. +- Signer-session recovery is explicit and never implies server custody. +- PSBT, signed, broadcast, confirmed, replaced, reorged, failed, and blocked readiness are represented as operation posture, not prose-only route errors. +- The BTC fee API can serialize the operation posture and normalize JSON-safe quote carriers. +- Terminal has a Wallet/BTC detail section so fee readiness is visible before raw ledger payload inspection. +- Gate 3 does not implement settlement reconciliation repair; Gate 6 owns drift repair and ledger/database reconciliation action depth. + ## Later-version boundaries - V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 54e80cc1f..42b037d8c 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -50,7 +50,7 @@ No `_legacy/` source is active source truth. | Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V29.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v29/gate-1-objectives-and-gating` | drafted | V29 family validates in draft mode over active V28 and `check:v29-gate1` passes. | | Workflow retargeting | Gate 1 | `.github/workflows/bitcode-gate-quality.yml`, `.github/workflows/bitcode-canon-quality.yml` | drafted | CI checks V28 active / V29 draft posture instead of stale V27/V28 posture. | | Terminal transaction read models | Gate 2 | `uapi/app/terminal/terminal-transaction-read-model.ts`, `uapi/app/terminal/terminal-transaction-query.ts`, `TerminalTransactionWorkspace.tsx`, `TerminalTransactionDetailSurface.tsx`, UAPI tests, Gate 2 checker | drafted | Terminal transaction state is URL-addressable, recoverable, typed, low-detail by default, and expandable without raw JSON as the ordinary operator contract. | -| Wallet signer/BTC operations | Gate 3 | `packages/btd`, wallet API, BTC fee route, Terminal wallet UI | pending | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | +| Wallet signer/BTC operations | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, BTC fee route, Terminal Wallet/BTC detail section, BTD and UAPI tests, Gate 3 checker | drafted | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | | Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack`, `packages/pipeline-hosts`, Terminal stream components | pending | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt telemetry is complete and readable. | | AssetPack disclosure rights | Gate 5 | BTD access primitives, AssetPack preview UI, disclosure policy tests | pending | Source-safe preview and paid unlock are proven without source leakage. | | Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, Terminal repair UI | pending | Ledger, database, and metaphysical state drift is visible and repairable. | @@ -68,6 +68,7 @@ No `_legacy/` source is active source truth. | Spec-family shape | V29 SPEC, DELTA, NOTES, and PARITY satisfy the full spec-family checker | drafted | | Gate 1 script | `pnpm run check:v29-gate1` fails closed on stale posture or missing gates | drafted | | Gate 2 read model | `pnpm run check:v29-gate2` proves typed route-owned Terminal transaction reading | drafted | +| Gate 3 wallet/BTC operation | `pnpm run check:v29-gate3` proves quote lifecycle, signer recovery, blocked readiness, API posture, and Terminal Wallet/BTC detail | drafted | | Product implementation gates | Gates 3-9 close remaining Terminal transaction depth with tests and docs | pending | | Promotion gate | Gate 10 closes generated proof and promotion automation | pending | @@ -115,3 +116,26 @@ Gate 1 is complete when the V29 draft family validates, `check:v29-gate1` passes ## Gate 2 completion condition Gate 2 is complete when Terminal selected transaction state rewrites recoverable URLs, a typed read model drives detail navigation and low-detail summaries, focused tests pass, `check:v29-gate2` passes, CI invokes the checker, docs name the implemented source surfaces, and the gate branch is committed and pushed for review into `version/v29`. + +## Gate 3 Parity + +| Requirement | Source evidence | Current V29 judgment | +| --- | --- | --- | +| BTC fee quote lifecycle is package-owned | `packages/btd/src/btc-fee-operation.ts`, `packages/btd/__tests__/btc-fee-operation.test.ts` | drafted | +| Signer-session recovery is explicit and no-custody | `buildWalletSignerSessionRecovery`, BTD operation tests | drafted | +| Blocked-readiness receipts name blocker and repair path | `buildBtcFeeBlockedReadinessReceipt`, BTD operation tests | drafted | +| Operation posture covers PSBT, broadcast, finality, replacement, reorg, failure | `buildBtcFeeOperationPosture`, BTD operation tests | drafted | +| BTC fee route serializes JSON-safe operation posture | `packages/api/src/routes/btd-crypto.ts`, route typecheck, route tests | drafted | +| Terminal exposes Wallet/BTC detail section | `terminal-transaction-query.ts`, `terminal-transaction-read-model.ts`, `TerminalTransactionWalletBtcCard.tsx`, `terminal-wallet-btc-operation.ts`, UAPI tests | drafted | +| Gate 3 checker is wired to package scripts and CI | `scripts/check-v29-gate3-wallet-signer-btc-operations.mjs`, `package.json`, gate workflow | drafted | + +## Gate 3 accepted boundaries + +- Gate 3 does not implement full settlement reconciliation repair; Gate 6 owns drift repair and readback repair actions. +- Gate 3 does not expose protected AssetPack source before settlement. +- Gate 3 does not broadcast value-bearing mainnet transactions. +- Gate 3 does not add versioned API routes or source identifiers. + +## Gate 3 completion condition + +Gate 3 is complete when package primitives model BTC quotes, signer recovery, operation posture, and blocked readiness; API responses serialize operation posture; Terminal has a Wallet/BTC route-owned detail section; focused package and UAPI tests pass; `check:v29-gate3` passes; CI invokes the checker and tests; docs name the implemented source surfaces; and the gate branch is committed and pushed for review into `version/v29`. diff --git a/package.json b/package.json index 1aaa9ac23..b3169f58a 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "check:v28-gate13": "node scripts/check-v28-gate13-product-closure-promotion-readiness.mjs", "check:v29-gate1": "node scripts/check-v29-gate1-objectives-and-gating.mjs", "check:v29-gate2": "node scripts/check-v29-gate2-terminal-transaction-read-models.mjs", + "check:v29-gate3": "node scripts/check-v29-gate3-wallet-signer-btc-operations.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 ff3b87df9..a95669d7f 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -36,7 +36,11 @@ import { buildPostBtdReadAccessRoute, buildPostBtdTerminalJournalRoute, } from '../btd-crypto'; -import { createBtdMeasureMintState } from '@bitcode/btd'; +import { + advanceBtcFeeQuote, + buildBtcFeeQuote, + createBtdMeasureMintState, +} from '@bitcode/btd'; const issuedAt = '2026-05-06T00:00:00.000Z'; @@ -59,6 +63,23 @@ function walletSessionInput() { }; } +function acceptedFeeQuote() { + return advanceBtcFeeQuote( + buildBtcFeeQuote({ + quoteId: 'quote-api-1', + feePurpose: 'asset_pack_anchor', + network: 'signet', + sats: 1200n, + satsPerVbyte: 4, + measurementRoot: 'measurement-root-api-1', + relatedAssetPackId: 'asset-pack-api-1', + issuedAt, + expiresAt: '2026-05-06T01:00:00.000Z', + }), + { state: 'accepted' }, + ); +} + function mintDraftInput() { return { assetPackId: 'asset-pack-api-1', @@ -511,6 +532,7 @@ describe('BTD crypto API builders', () => { receiptId: 'btc-fee-api-1', feePurpose: 'asset_pack_anchor', payerSession: walletSessionInput(), + feeQuote: acceptedFeeQuote(), psbt: 'cHNidP8BAHECAAAAA', satsPaid: 1200n, satsPerVbyte: 4, @@ -546,6 +568,12 @@ describe('BTD crypto API builders', () => { expect(prepared.receipt.feeAsset).toBe('BTC'); expect(prepared.receipt.walletAuthorizationProof.proofKind).toBe('message_signature'); expect(prepared.receipt.exchangeSequence).toBe(11n); + expect(prepared.operationPosture).toMatchObject({ + phase: 'psbt_ready', + canSignPsbt: true, + noServerCustody: true, + quote: { quoteId: 'quote-api-1' }, + }); expect(prepared.terminalJournalEntry.transactionKind).toBe('btc_fee_payment'); expect(confirmed.receipt.txid).toBe('btc-txid-api-1'); expect(confirmed.receipt.confirmations).toBe(2); @@ -915,6 +943,10 @@ describe('BTD crypto API builders', () => { receiptId: 'btc-fee-api-1', feePurpose: 'asset_pack_anchor', payerSession: walletSessionInput(), + feeQuote: { + ...acceptedFeeQuote(), + sats: '1200', + }, psbt: 'cHNidP8BAHECAAAAA', satsPaid: '1200', satsPerVbyte: 4, @@ -933,6 +965,14 @@ describe('BTD crypto API builders', () => { expect(body.receipt.feeAsset).toBe('BTC'); expect(body.receipt.serverCustody).toBe(false); expect(body.receipt.exchangeSequence).toBe('11'); + expect(body.operationPosture).toMatchObject({ + phase: 'psbt_ready', + canSignPsbt: true, + quote: { + quoteId: 'quote-api-1', + sats: '1200', + }, + }); expect(body.committed).toBe(true); expect(insertBtcFeeTransaction).toHaveBeenCalledWith( expect.objectContaining({ diff --git a/packages/api/src/routes/btd-crypto.ts b/packages/api/src/routes/btd-crypto.ts index 2ff1c223d..f158d6004 100644 --- a/packages/api/src/routes/btd-crypto.ts +++ b/packages/api/src/routes/btd-crypto.ts @@ -22,8 +22,10 @@ import { type AssetPackExchangeOrderKind, type AssetPackRightsTransferReceipt, type BtcFeeFinalityState, + type BtcFeeOperationPosture, type DatabaseProjectedFact, type BtcFeePurpose, + type BtcFeeQuote, type BtcFeeTransactionReceipt, type LedgerObservedFact, type LedgerFinalityState, @@ -55,6 +57,9 @@ import { buildV27CryptoTelemetryRecord, buildPreparedAssetPackLedgerAnchor, buildPreparedBtcFeeTransactionReceipt, + buildBtcFeeOperationPosture, + assertBtcFeeQuote, + assertBtcFeeQuoteActive, buildLicensedReadRevenueRoute, buildPlannedBtdProtocolUpgradeReceipt, buildTerminalJournalEntry, @@ -203,6 +208,7 @@ export interface BtdBtcFeeTransactionInput { relatedAssetPackId?: string; relatedOrderId?: string; previousReceipt?: BtcFeeTransactionReceipt; + feeQuote?: BtcFeeQuote; txid?: string; vout?: number; observedFinalityState?: Exclude; @@ -358,6 +364,7 @@ export interface BtdBtcFeeTransactionSettlement { actorId: string; action: BtdBtcFeeTransactionAction; receipt: BtcFeeTransactionReceipt; + operationPosture: BtcFeeOperationPosture; terminalJournalEntry: ReturnType; registryWrite?: Awaited>; committed: boolean; @@ -715,7 +722,15 @@ export function buildBtdBtcFeeTransactionSettlement( ): Omit { const actorId = assertNonEmptyString(input.actorId, 'actorId'); const issuedAt = input.issuedAt ?? new Date().toISOString(); - const receipt = buildBtcFeeReceiptForAction(input); + 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, @@ -745,6 +760,7 @@ export function buildBtdBtcFeeTransactionSettlement( actorId, action: input.action, receipt, + operationPosture, terminalJournalEntry, }; } @@ -1605,6 +1621,19 @@ function buildBtcFeeReceiptForAction( 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, @@ -1859,6 +1888,17 @@ function normalizeBtcFeeTransactionReceipt( }); } +function normalizeBtcFeeQuote(quote: BtcFeeQuote | undefined): BtcFeeQuote | undefined { + if (!quote) { + return undefined; + } + + return assertBtcFeeQuote({ + ...quote, + sats: BigInt(quote.sats), + }); +} + function normalizeAssetPackLedgerAnchor( anchor: AssetPackLedgerAnchor | undefined, ): AssetPackLedgerAnchor { diff --git a/packages/btd/__tests__/btc-fee-operation.test.ts b/packages/btd/__tests__/btc-fee-operation.test.ts new file mode 100644 index 000000000..952a7c362 --- /dev/null +++ b/packages/btd/__tests__/btc-fee-operation.test.ts @@ -0,0 +1,237 @@ +import { + advanceBtcFeeQuote, + advanceBtcFeeTransactionReceipt, + buildBtcFeeOperationPosture, + buildBtcFeeQuote, + buildPreparedBtcFeeTransactionReceipt, + buildWalletSignerSessionRecovery, + createWalletSignerSession, +} from '../src'; + +const issuedAt = '2026-05-20T12:00:00.000Z'; +const expiresAt = '2026-05-20T12:30:00.000Z'; + +function authorizedSession(overrides = {}) { + return createWalletSignerSession({ + walletSessionId: 'wallet-session-1', + walletId: 'wallet-reader', + userId: 'reader-1', + address: 'tb1qbitcodereader0000000000000000000000000', + network: 'testnet', + nonce: 'nonce-1', + capabilities: ['psbt_sign', 'message_sign'], + authorizationProof: { + proofKind: 'message_signature', + message: 'Authorize Bitcode BTC fee settlement.', + signature: 'signature-1', + verifiedAt: issuedAt, + }, + expiresAt, + ...overrides, + }); +} + +function acceptedQuote() { + return advanceBtcFeeQuote( + buildBtcFeeQuote({ + quoteId: 'quote-1', + feePurpose: 'licensed_read', + network: 'testnet', + sats: 1200n, + satsPerVbyte: 4, + measurementRoot: 'need-fit-measurement-root', + relatedAssetPackId: 'asset-pack-1', + issuedAt, + expiresAt, + }), + { state: 'accepted' }, + ); +} + +function preparedReceipt() { + return buildPreparedBtcFeeTransactionReceipt({ + receiptId: 'btc-fee-1', + feePurpose: 'licensed_read', + payerSession: authorizedSession(), + psbt: 'cHNidP8BAHECAAAAA', + satsPaid: 1200n, + satsPerVbyte: 4, + exchangeSequence: 10n, + terminalJournalRoot: 'terminal-journal-root', + relatedAssetPackId: 'asset-pack-1', + issuedAt, + }); +} + +describe('BTC fee quote lifecycle', () => { + it('builds a BTC quote with deterministic pricing and quote root posture', () => { + const quote = buildBtcFeeQuote({ + quoteId: 'quote-1', + feePurpose: 'licensed_read', + network: 'testnet', + sats: '1200', + measurementRoot: 'need-fit-measurement-root', + issuedAt, + expiresAt, + }); + + expect(quote).toMatchObject({ + kind: 'btc.fee_quote', + feeAsset: 'BTC', + pricingVersion: 'measurement-weight-volume', + state: 'quoted', + quoteRoot: expect.stringMatching(/^btc-fee-quote-/), + }); + expect(quote.sats).toBe(1200n); + }); + + it('allows quote acceptance and rejects invalid terminal transitions', () => { + const quote = acceptedQuote(); + expect(quote.state).toBe('accepted'); + expect(() => advanceBtcFeeQuote(quote, { state: 'accepted' })).toThrow( + /Invalid BTC fee quote transition/, + ); + }); +}); + +describe('wallet signer recovery', () => { + it('recovers live authorized PSBT signing without server custody', () => { + const recovery = buildWalletSignerSessionRecovery({ + session: authorizedSession(), + network: 'testnet', + at: issuedAt, + }); + + expect(recovery).toMatchObject({ + state: 'live_authorized', + canSign: true, + serverCustody: false, + walletSessionId: 'wallet-session-1', + }); + }); + + it('blocks stale stored or mismatched signer sessions with actionable reasons', () => { + expect( + buildWalletSignerSessionRecovery({ + session: authorizedSession(), + network: 'signet', + at: issuedAt, + }), + ).toMatchObject({ + state: 'network_mismatch', + canSign: false, + }); + + expect( + buildWalletSignerSessionRecovery({ + session: authorizedSession({ expiresAt: '2026-05-20T11:00:00.000Z' }), + network: 'testnet', + at: issuedAt, + }), + ).toMatchObject({ + state: 'expired', + canSign: false, + }); + }); +}); + +describe('BTC fee operation posture', () => { + it('returns blocked-readiness when signer, quote, or quote acceptance is missing', () => { + const noSigner = buildBtcFeeOperationPosture({ + quote: acceptedQuote(), + at: issuedAt, + }); + expect(noSigner).toMatchObject({ + phase: 'blocked', + blockedReadiness: { + blockerId: 'wallet-signer-session', + noServerCustody: true, + }, + canPreparePsbt: false, + }); + + const unacceptedQuote = buildBtcFeeQuote({ + quoteId: 'quote-2', + feePurpose: 'licensed_read', + network: 'testnet', + sats: 1200n, + measurementRoot: 'measurement-root', + issuedAt, + expiresAt, + }); + expect( + buildBtcFeeOperationPosture({ + quote: unacceptedQuote, + payerSession: authorizedSession(), + at: issuedAt, + }), + ).toMatchObject({ + phase: 'blocked', + blockedReadiness: { blockerId: 'fee-quote-not-accepted' }, + }); + }); + + it('moves from accepted quote to PSBT, broadcast, and confirmed settlement posture', () => { + const quote = acceptedQuote(); + const quoted = buildBtcFeeOperationPosture({ + quote, + payerSession: authorizedSession(), + at: issuedAt, + }); + expect(quoted).toMatchObject({ + phase: 'quoted', + canPreparePsbt: true, + canSettle: false, + }); + + const prepared = preparedReceipt(); + const psbtReady = buildBtcFeeOperationPosture({ + quote, + payerSession: authorizedSession(), + receipt: prepared, + at: issuedAt, + }); + expect(psbtReady).toMatchObject({ + phase: 'psbt_ready', + canSignPsbt: true, + canBroadcast: false, + }); + + const signed = advanceBtcFeeTransactionReceipt(prepared, { + finalityState: 'signed', + psbt: 'signed-psbt', + }); + const broadcast = advanceBtcFeeTransactionReceipt(signed, { + finalityState: 'broadcast', + txid: 'txid-1', + }); + const confirmed = advanceBtcFeeTransactionReceipt(broadcast, { + finalityState: 'confirmed', + confirmations: 2, + }); + + expect( + buildBtcFeeOperationPosture({ + quote, + payerSession: authorizedSession(), + receipt: broadcast, + at: issuedAt, + }), + ).toMatchObject({ + phase: 'broadcast', + canObserveFinality: true, + }); + expect( + buildBtcFeeOperationPosture({ + quote, + payerSession: authorizedSession(), + receipt: confirmed, + at: issuedAt, + }), + ).toMatchObject({ + phase: 'confirmed', + canSettle: true, + noServerCustody: true, + }); + }); +}); diff --git a/packages/btd/src/btc-fee-operation.ts b/packages/btd/src/btc-fee-operation.ts new file mode 100644 index 000000000..3a6a918ce --- /dev/null +++ b/packages/btd/src/btc-fee-operation.ts @@ -0,0 +1,553 @@ +import { + BITCODE_FEE_ASSET, + BitcoinNetwork, + assertBitcoinNetwork, + assertNonEmptyString, + toBigIntAmount, +} from './constants'; +import type { + BtcFeeFinalityState, + BtcFeePurpose, + BtcFeeTransactionReceipt, +} from './bitcoin-fees'; +import type { WalletCapability, WalletSignerSession } from './wallet'; + +export type BtcFeeQuoteState = 'quoted' | 'accepted' | 'expired' | 'superseded' | 'failed'; + +export interface BtcFeeQuote { + kind: 'btc.fee_quote'; + quoteId: string; + feePurpose: BtcFeePurpose; + network: BitcoinNetwork; + sats: bigint; + satsPerVbyte?: number; + measurementRoot: string; + quoteRoot: string; + pricingVersion: 'measurement-weight-volume'; + state: BtcFeeQuoteState; + feeAsset: typeof BITCODE_FEE_ASSET; + relatedAssetPackId?: string; + relatedOrderId?: string; + issuedAt: string; + expiresAt: string; + failureReason?: string; +} + +export type WalletSignerSessionRecoveryState = + | 'live_authorized' + | 'missing' + | 'prepared_authorization_required' + | 'stored_authorized_reconnect_required' + | 'expired' + | 'revoked' + | 'failed' + | 'network_mismatch' + | 'capability_missing' + | 'server_custody_rejected'; + +export interface WalletSignerSessionRecovery { + state: WalletSignerSessionRecoveryState; + canSign: boolean; + walletSessionId: string | null; + walletId: string | null; + address: string | null; + network: BitcoinNetwork | null; + requiredCapability: WalletCapability; + serverCustody: false | null; + blocker: string | null; + nextAction: string; +} + +export type BtcFeeOperationPhase = + | 'blocked' + | 'quoted' + | 'psbt_ready' + | 'signed' + | 'broadcast' + | 'confirmed' + | 'replaced' + | 'reorged' + | 'failed'; + +export type BtcFeeBlockedReadinessBlockerId = + | 'wallet-signer-session' + | 'wallet-network' + | 'wallet-capability' + | 'wallet-server-custody' + | 'fee-quote' + | 'fee-quote-expired' + | 'fee-quote-not-accepted' + | 'psbt-handoff' + | 'broadcast' + | 'finality'; + +export interface BtcFeeBlockedReadinessReceipt { + kind: 'btc.fee_blocked_readiness'; + blockerId: BtcFeeBlockedReadinessBlockerId; + summary: string; + requiredAction: string; + quoteId: string | null; + walletSessionId: string | null; + receiptId: string | null; + noServerCustody: true; + issuedAt: string; +} + +export interface BtcFeeOperationPosture { + kind: 'btc.fee_operation_posture'; + phase: BtcFeeOperationPhase; + feeAsset: typeof BITCODE_FEE_ASSET; + network: BitcoinNetwork | null; + quote: BtcFeeQuote | null; + receipt: BtcFeeTransactionReceipt | null; + signerRecovery: WalletSignerSessionRecovery; + blockedReadiness: BtcFeeBlockedReadinessReceipt | null; + canPreparePsbt: boolean; + canSignPsbt: boolean; + canBroadcast: boolean; + canObserveFinality: boolean; + canSettle: boolean; + noServerCustody: true; + nextAction: string; +} + +const QUOTE_TRANSITIONS: Record = { + quoted: ['accepted', 'expired', 'superseded', 'failed'], + accepted: ['expired', 'superseded', 'failed'], + expired: [], + superseded: [], + failed: [], +}; + +export function buildBtcFeeQuote(input: { + quoteId: string; + feePurpose: BtcFeePurpose; + network: BitcoinNetwork; + sats: bigint | number | string; + measurementRoot: string; + issuedAt?: string; + expiresAt: string; + satsPerVbyte?: number; + relatedAssetPackId?: string; + relatedOrderId?: string; +}): BtcFeeQuote { + 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(); + const quoteRoot = stableBtcOperationRoot('btc-fee-quote', [ + input.quoteId, + input.feePurpose, + input.network, + sats.toString(), + input.measurementRoot, + issuedAt, + input.expiresAt, + ]); + + return { + kind: 'btc.fee_quote', + quoteId: assertNonEmptyString(input.quoteId, 'quoteId'), + feePurpose: input.feePurpose, + network: assertBitcoinNetwork(input.network), + sats, + satsPerVbyte: input.satsPerVbyte, + measurementRoot: assertNonEmptyString(input.measurementRoot, 'measurementRoot'), + quoteRoot, + pricingVersion: 'measurement-weight-volume', + state: 'quoted', + feeAsset: BITCODE_FEE_ASSET, + relatedAssetPackId: input.relatedAssetPackId, + relatedOrderId: input.relatedOrderId, + issuedAt, + expiresAt: assertNonEmptyString(input.expiresAt, 'expiresAt'), + }; +} + +export function advanceBtcFeeQuote( + quote: BtcFeeQuote, + next: { state: Exclude; failureReason?: string }, +): BtcFeeQuote { + assertBtcFeeQuote(quote); + if (!QUOTE_TRANSITIONS[quote.state].includes(next.state)) { + throw new Error(`Invalid BTC fee quote transition: ${quote.state} -> ${next.state}.`); + } + + return { + ...quote, + state: next.state, + failureReason: next.failureReason, + }; +} + +export function assertBtcFeeQuote(quote: BtcFeeQuote): BtcFeeQuote { + if (quote.kind !== 'btc.fee_quote') { + throw new Error('Invalid BTC fee quote kind.'); + } + if (quote.feeAsset !== BITCODE_FEE_ASSET) { + throw new Error('BTC fee quote must use BTC as the fee asset.'); + } + if (quote.sats <= 0n) { + throw new Error('BTC fee quote sats must be positive.'); + } + assertNonEmptyString(quote.quoteId, 'quoteId'); + assertBitcoinNetwork(quote.network); + assertNonEmptyString(quote.measurementRoot, 'measurementRoot'); + assertNonEmptyString(quote.quoteRoot, 'quoteRoot'); + assertNonEmptyString(quote.issuedAt, 'issuedAt'); + assertNonEmptyString(quote.expiresAt, 'expiresAt'); + return quote; +} + +export function assertBtcFeeQuoteActive( + quote: BtcFeeQuote, + at = new Date().toISOString(), +): BtcFeeQuote { + assertBtcFeeQuote(quote); + if (quote.state !== 'quoted' && quote.state !== 'accepted') { + throw new Error(`BTC fee quote is not active: ${quote.state}.`); + } + if (Date.parse(quote.expiresAt) <= Date.parse(at)) { + throw new Error('BTC fee quote is expired.'); + } + return quote; +} + +export function buildWalletSignerSessionRecovery(input: { + session?: WalletSignerSession | null; + requiredCapability?: WalletCapability; + network?: BitcoinNetwork | null; + at?: string; + allowStoredAuthorizedSession?: boolean; +}): WalletSignerSessionRecovery { + const session = input.session || null; + const requiredCapability = input.requiredCapability || 'psbt_sign'; + if (!session) { + return walletRecovery({ + state: 'missing', + requiredCapability, + blocker: 'No wallet signer session is attached.', + nextAction: 'Reconnect Wallet before preparing a BTC fee PSBT.', + }); + } + + const walletSessionId = session.walletSessionId || null; + const walletId = session.walletId || null; + const address = session.address || null; + const network = assertBitcoinNetwork(session.network); + const base = { + walletSessionId, + walletId, + address, + network, + requiredCapability, + }; + + if (session.serverCustody !== false) { + return walletRecovery({ + ...base, + state: 'server_custody_rejected', + blocker: 'Wallet signer session implies server custody.', + nextAction: 'Use a wallet provider session where Bitcode never receives private keys.', + }); + } + + if (input.network && network !== input.network) { + return walletRecovery({ + ...base, + state: 'network_mismatch', + blocker: `Wallet signer session is on ${network}, expected ${input.network}.`, + nextAction: 'Reconnect Wallet on the BTC fee quote network.', + }); + } + + if (!session.capabilities.includes(requiredCapability)) { + return walletRecovery({ + ...base, + state: 'capability_missing', + blocker: `Wallet signer session is missing ${requiredCapability}.`, + nextAction: 'Reconnect Wallet with PSBT signing capability.', + }); + } + + const at = Date.parse(input.at || new Date().toISOString()); + if (session.expiresAt && Date.parse(session.expiresAt) <= at) { + return walletRecovery({ + ...base, + state: 'expired', + blocker: 'Wallet signer session is expired.', + nextAction: 'Reconnect Wallet to restore live signing.', + }); + } + + if (session.state === 'authorized' && session.authorizationProof) { + if (input.allowStoredAuthorizedSession === true) { + return walletRecovery({ + ...base, + state: 'stored_authorized_reconnect_required', + blocker: 'Stored authorization proof exists, but live provider signing is not confirmed.', + nextAction: 'Reconnect the wallet provider before signing the BTC fee PSBT.', + }); + } + + return walletRecovery({ + ...base, + state: 'live_authorized', + blocker: null, + nextAction: 'Prepare or sign the BTC fee PSBT.', + canSign: true, + serverCustody: false, + }); + } + + if (session.state === 'prepared') { + return walletRecovery({ + ...base, + state: 'prepared_authorization_required', + blocker: 'Wallet signer session still needs address authorization.', + nextAction: 'Authorize the Wallet address before preparing a BTC fee PSBT.', + }); + } + + if (session.state === 'authorized') { + return walletRecovery({ + ...base, + state: 'prepared_authorization_required', + blocker: 'Wallet signer session is authorized but missing address authorization proof.', + nextAction: 'Reauthorize the Wallet address before preparing a BTC fee PSBT.', + }); + } + + return walletRecovery({ + ...base, + state: session.state, + blocker: `Wallet signer session is ${session.state}.`, + nextAction: 'Reconnect Wallet to restore live signing.', + }); +} + +export function buildBtcFeeBlockedReadinessReceipt(input: { + blockerId: BtcFeeBlockedReadinessBlockerId; + summary: string; + requiredAction: string; + quoteId?: string | null; + walletSessionId?: string | null; + receiptId?: string | null; + issuedAt?: string; +}): BtcFeeBlockedReadinessReceipt { + return { + kind: 'btc.fee_blocked_readiness', + blockerId: input.blockerId, + summary: assertNonEmptyString(input.summary, 'summary'), + requiredAction: assertNonEmptyString(input.requiredAction, 'requiredAction'), + quoteId: input.quoteId || null, + walletSessionId: input.walletSessionId || null, + receiptId: input.receiptId || null, + noServerCustody: true, + issuedAt: input.issuedAt || new Date().toISOString(), + }; +} + +export function buildBtcFeeOperationPosture(input: { + quote?: BtcFeeQuote | null; + receipt?: BtcFeeTransactionReceipt | null; + payerSession?: WalletSignerSession | null; + at?: string; + allowStoredAuthorizedSession?: boolean; +}): 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 signerRecovery = buildWalletSignerSessionRecovery({ + session: input.payerSession, + network, + at: input.at, + allowStoredAuthorizedSession: input.allowStoredAuthorizedSession, + }); + + if (!signerRecovery.canSign) { + return blockedPosture({ + quote, + receipt, + signerRecovery, + blockerId: signerBlockerId(signerRecovery.state), + summary: signerRecovery.blocker || 'Wallet signer session is not ready.', + requiredAction: signerRecovery.nextAction, + }); + } + + if (!quote) { + return blockedPosture({ + quote, + receipt, + signerRecovery, + blockerId: 'fee-quote', + summary: 'No BTC fee quote is attached.', + requiredAction: 'Create a BTC fee quote before preparing a PSBT.', + }); + } + + try { + assertBtcFeeQuoteActive(quote, input.at); + } catch (error) { + return blockedPosture({ + quote, + receipt, + signerRecovery, + 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.', + }); + } + + if (quote.state !== 'accepted' && !receipt) { + return blockedPosture({ + quote, + receipt, + signerRecovery, + 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.', + }); + } + + if (!receipt) { + return operationPosture({ + phase: 'quoted', + quote, + receipt, + signerRecovery, + canPreparePsbt: true, + canSignPsbt: false, + canBroadcast: false, + canObserveFinality: false, + canSettle: false, + nextAction: 'Prepare the BTC fee PSBT from the accepted quote.', + }); + } + + const receiptPhase = phaseForFinality(receipt.finalityState); + return operationPosture({ + phase: receiptPhase, + quote, + receipt, + signerRecovery, + canPreparePsbt: false, + canSignPsbt: receipt.finalityState === 'prepared', + canBroadcast: receipt.finalityState === 'signed', + canObserveFinality: receipt.finalityState === 'broadcast', + canSettle: receipt.finalityState === 'confirmed', + nextAction: nextActionForReceipt(receipt.finalityState), + }); +} + +function walletRecovery(input: Partial & { + state: WalletSignerSessionRecoveryState; + requiredCapability: WalletCapability; + blocker: string | null; + nextAction: string; +}): WalletSignerSessionRecovery { + return { + state: input.state, + canSign: Boolean(input.canSign), + walletSessionId: input.walletSessionId || null, + walletId: input.walletId || null, + address: input.address || null, + network: input.network || null, + requiredCapability: input.requiredCapability, + serverCustody: input.serverCustody ?? null, + blocker: input.blocker, + nextAction: input.nextAction, + }; +} + +function signerBlockerId( + state: WalletSignerSessionRecoveryState, +): BtcFeeBlockedReadinessBlockerId { + if (state === 'network_mismatch') return 'wallet-network'; + if (state === 'capability_missing') return 'wallet-capability'; + if (state === 'server_custody_rejected') return 'wallet-server-custody'; + return 'wallet-signer-session'; +} + +function blockedPosture(input: { + quote: BtcFeeQuote | null; + receipt: BtcFeeTransactionReceipt | null; + signerRecovery: WalletSignerSessionRecovery; + blockerId: BtcFeeBlockedReadinessBlockerId; + summary: string; + requiredAction: string; +}): BtcFeeOperationPosture { + return operationPosture({ + phase: 'blocked', + quote: input.quote, + receipt: input.receipt, + signerRecovery: input.signerRecovery, + blockedReadiness: buildBtcFeeBlockedReadinessReceipt({ + blockerId: input.blockerId, + summary: input.summary, + requiredAction: input.requiredAction, + quoteId: input.quote?.quoteId, + walletSessionId: input.signerRecovery.walletSessionId, + receiptId: input.receipt?.receiptId, + }), + canPreparePsbt: false, + canSignPsbt: false, + canBroadcast: false, + canObserveFinality: false, + canSettle: false, + nextAction: input.requiredAction, + }); +} + +type BtcFeeOperationPostureDraft = + Omit & { + blockedReadiness?: BtcFeeBlockedReadinessReceipt | null; + }; + +function operationPosture(input: BtcFeeOperationPostureDraft): BtcFeeOperationPosture { + return { + kind: 'btc.fee_operation_posture', + feeAsset: BITCODE_FEE_ASSET, + network: input.quote?.network || input.receipt?.network || input.signerRecovery.network, + noServerCustody: true, + ...input, + blockedReadiness: input.blockedReadiness || null, + }; +} + +function phaseForFinality(finalityState: BtcFeeFinalityState): BtcFeeOperationPhase { + if (finalityState === 'prepared') return 'psbt_ready'; + return finalityState; +} + +function nextActionForReceipt(finalityState: BtcFeeFinalityState): string { + switch (finalityState) { + case 'prepared': + return 'Ask the wallet provider to sign the BTC fee PSBT.'; + case 'signed': + return 'Broadcast the signed BTC transaction through the admitted provider.'; + case 'broadcast': + return 'Observe Bitcoin finality until confirmation, replacement, reorg, or failure is known.'; + case 'confirmed': + return 'Settlement can continue into BTD right transfer and delivery unlock.'; + case 'replaced': + return 'Repair settlement with the replacement transaction or prepare a new quote.'; + case 'reorged': + return 'Pause unlock and reconcile against the reorged transaction observation.'; + case 'failed': + return 'Repair or restart BTC fee settlement from a fresh quote.'; + } +} + +function stableBtcOperationRoot(prefix: string, parts: string[]): string { + const source = parts.join('\u001f'); + let hash = 0x811c9dc5; + for (let index = 0; index < source.length; index += 1) { + hash ^= source.charCodeAt(index); + hash = Math.imul(hash, 0x01000193); + } + return `${prefix}-${(hash >>> 0).toString(16).padStart(8, '0')}`; +} diff --git a/packages/btd/src/index.ts b/packages/btd/src/index.ts index c30942766..8bdcc77a5 100644 --- a/packages/btd/src/index.ts +++ b/packages/btd/src/index.ts @@ -155,6 +155,7 @@ export function buildGenerationBitcodeAccounting( } export * from './bitcoin-fees'; +export * from './btc-fee-operation'; export * from './bitcoin-provider'; export * from './access'; export * from './allocation'; diff --git a/scripts/check-v29-gate3-wallet-signer-btc-operations.mjs b/scripts/check-v29-gate3-wallet-signer-btc-operations.mjs new file mode 100755 index 000000000..3593b401a --- /dev/null +++ b/scripts/check-v29-gate3-wallet-signer-btc-operations.mjs @@ -0,0 +1,250 @@ +#!/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-v29-gate3-wallet-signer-btc-operations.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 3 wallet signer session and BTC fee operation closure.', + ].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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 Gate 3 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-3-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 3 work must occur on version/v29 or v29/gate-3-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'packages/btd/src/btc-fee-operation.ts', + 'packages/btd/src/index.ts', + 'packages/btd/__tests__/btc-fee-operation.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'uapi/app/terminal/terminal-transaction-query.ts', + 'uapi/app/terminal/terminal-transaction-read-model.ts', + 'uapi/app/terminal/terminal-wallet-btc-operation.ts', + 'uapi/app/terminal/TerminalTransactionWalletBtcCard.tsx', + 'uapi/app/terminal/TerminalTransactionDetailSurface.tsx', + 'uapi/tests/terminalWalletBtcOperation.test.ts', + 'uapi/tests/terminalTransactionReadModel.test.ts', + 'uapi/app/terminal/README.md', + 'package.json', + '.github/workflows/bitcode-gate-quality.yml', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 3 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const btdOperation = read(root, 'packages/btd/src/btc-fee-operation.ts'); + const btdIndex = read(root, 'packages/btd/src/index.ts'); + const btdTest = read(root, 'packages/btd/__tests__/btc-fee-operation.test.ts'); + const apiRoute = read(root, 'packages/api/src/routes/btd-crypto.ts'); + const query = read(root, 'uapi/app/terminal/terminal-transaction-query.ts'); + const readModel = read(root, 'uapi/app/terminal/terminal-transaction-read-model.ts'); + const terminalOperation = read(root, 'uapi/app/terminal/terminal-wallet-btc-operation.ts'); + const terminalCard = read(root, 'uapi/app/terminal/TerminalTransactionWalletBtcCard.tsx'); + const detailSurface = read(root, 'uapi/app/terminal/TerminalTransactionDetailSurface.tsx'); + const terminalTest = read(root, 'uapi/tests/terminalWalletBtcOperation.test.ts'); + const readModelTest = read(root, 'uapi/tests/terminalTransactionReadModel.test.ts'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + assertCheck(failures, spec.includes('V29 Wallet/BTC operation canon'), 'V29 SPEC must define the Wallet/BTC operation canon.'); + assertCheck(failures, delta.includes('BtcFeeOperationPosture'), 'V29 DELTA must list Gate 3 operation posture acceptance.'); + assertCheck(failures, notes.includes('Gate 3 working notes'), 'V29 NOTES must carry Gate 3 working notes.'); + assertCheck(failures, parity.includes('## Gate 3 Parity'), 'V29 PARITY must include Gate 3 parity.'); + assertCheck(failures, parity.includes('Gate 3 completion condition'), 'V29 PARITY must include Gate 3 completion condition.'); + + for (const symbol of [ + 'BtcFeeQuote', + 'WalletSignerSessionRecovery', + 'BtcFeeBlockedReadinessReceipt', + 'BtcFeeOperationPosture', + 'buildBtcFeeQuote', + 'advanceBtcFeeQuote', + 'buildWalletSignerSessionRecovery', + 'buildBtcFeeOperationPosture', + 'server_custody_rejected', + 'fee-quote-not-accepted', + ]) { + assertCheck(failures, btdOperation.includes(symbol), `BTD operation primitive is missing ${symbol}.`); + } + assertCheck(failures, btdIndex.includes("export * from './btc-fee-operation'"), 'BTD package must export BTC fee operation primitives.'); + assertCheck( + failures, + btdTest.includes('BTC fee quote lifecycle') && + btdTest.includes('wallet signer recovery') && + btdTest.includes('blocked-readiness') && + btdTest.includes('confirmed settlement posture'), + 'BTD tests must cover quote lifecycle, signer recovery, blocked readiness, and confirmed posture.', + ); + assertCheck( + failures, + apiRoute.includes('operationPosture') && + apiRoute.includes('normalizeBtcFeeQuote') && + apiRoute.includes('buildBtcFeeOperationPosture'), + 'BTC fee route must serialize operation posture and normalize quote carriers.', + ); + assertCheck( + failures, + query.includes("'wallet-btc'") && + readModel.includes("'wallet-btc'") && + readModel.includes('Wallet/BTC') && + readModel.includes('No wallet signer session, BTC fee quote, PSBT, or finality readback is attached yet.'), + 'Terminal query/read model must expose the Wallet/BTC detail section and empty blocker.', + ); + assertCheck( + failures, + terminalOperation.includes('buildTerminalWalletBtcOperationProjection') && + terminalOperation.includes('Server custody') && + terminalOperation.includes('Replacement transaction must be reconciled'), + 'Terminal Wallet/BTC projection must expose state, custody, and replacement blockers.', + ); + assertCheck( + failures, + terminalCard.includes('TerminalTransactionWalletBtcCard') && + terminalCard.includes('Blocked readiness') && + terminalCard.includes('Wallet and BTC payload'), + 'Terminal Wallet/BTC card must render readable blockers and raw audit payload.', + ); + assertCheck( + failures, + detailSurface.includes('TerminalTransactionWalletBtcCard') && + detailSurface.includes("detailSection === 'wallet-btc'"), + 'Detail surface must render the Wallet/BTC section.', + ); + assertCheck( + failures, + terminalTest.includes('confirmed BTC fee settlement') && + terminalTest.includes('replacement') && + terminalTest.includes('missing quote readiness'), + 'Terminal Wallet/BTC tests must cover confirmed and blocked states.', + ); + assertCheck( + failures, + readModelTest.includes("'wallet-btc'") && readModelTest.includes("factFamily: 'wallet'"), + 'Read-model tests must include the Wallet/BTC section.', + ); + assertCheck( + failures, + terminalReadme.includes('Wallet/BTC') && terminalReadme.includes('quote root'), + 'Terminal README must document the Wallet/BTC section.', + ); + assertCheck(failures, packageJson.includes('"check:v29-gate3"'), 'package.json must expose check:v29-gate3.'); + assertCheck( + failures, + gateWorkflow.includes('check-v29-gate3-wallet-signer-btc-operations.mjs'), + 'Gate quality workflow must run the Gate 3 checker.', + ); + assertCheck( + failures, + gateWorkflow.includes('tests/terminalWalletBtcOperation.test.ts') && + gateWorkflow.includes('__tests__/btc-fee-operation.test.ts'), + 'Gate quality workflow must run the Gate 3 focused tests.', + ); + + const versionedSource = execFileSync( + 'find', + ['packages/btd/src', 'uapi/app/terminal', '-name', '*v29*', '-print'], + { + cwd: root, + encoding: 'utf8', + }, + ).trim(); + assertCheck( + failures, + versionedSource.length === 0, + `Gate 3 source identifiers must remain unversioned. Found:\n${versionedSource}`, + ); + + if (failures.length > 0) { + process.stderr.write('V29 Gate 3 wallet signer/BTC operation check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write(`V29 Gate 3 wallet signer/BTC operation 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; +} diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 5bdfa02a7..d5ca92118 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -40,6 +40,10 @@ presenting them as part of Terminal itself. - `terminal-journal-reconciliation.ts` and `TerminalTransactionJournalReconciliationCard.tsx` Selected-activity Journal section owner for ledger observations, database projections, canonical root facts, repair receipts, and drift state. +- `terminal-wallet-btc-operation.ts` and `TerminalTransactionWalletBtcCard.tsx` + Selected-activity Wallet/BTC section owner for signer recovery, fee quote, + PSBT handoff, transaction id, finality, blocked readiness, and no-custody + posture. - `TerminalCommandDeck.tsx` Scenario, projection, branch mode, reset, and flow-guide entry posture. - `TerminalDepositReadWorkbench.tsx` @@ -112,9 +116,14 @@ Former `runId` links are still accepted on read and rewritten on write. Ordinary operators should read the low-detail model first: summary, proof posture, metrics, posture chips, and section availability. Shippables, -identity, closure, proofs, history, journal, activity stream, and console each -declare whether they are available, empty, or blocked. Raw payloads remain audit -material behind expansion, not the normal navigation contract. +identity, Wallet/BTC, closure, proofs, history, journal, activity stream, and +console each declare whether they are available, empty, or blocked. Raw payloads +remain audit material behind expansion, not the normal navigation contract. + +The Wallet/BTC section projects BTC fee operation state without exposing wallet +secrets or protected AssetPack source. It should show quote root, wallet session, +payer wallet, PSBT handoff, txid, state, confirmations, blockers, and server +custody posture as ordinary rows before the operator opens raw ledger payloads. ## Related shared systems diff --git a/uapi/app/terminal/TerminalTransactionDetailSurface.tsx b/uapi/app/terminal/TerminalTransactionDetailSurface.tsx index e3f938e45..0ba956195 100644 --- a/uapi/app/terminal/TerminalTransactionDetailSurface.tsx +++ b/uapi/app/terminal/TerminalTransactionDetailSurface.tsx @@ -23,6 +23,7 @@ import TerminalTransactionHistoryCard from './TerminalTransactionHistoryCard'; import TerminalTransactionIdentityCard from './TerminalTransactionIdentityCard'; import TerminalTransactionJournalReconciliationCard from './TerminalTransactionJournalReconciliationCard'; import TerminalTransactionProofsCard from './TerminalTransactionProofsCard'; +import TerminalTransactionWalletBtcCard from './TerminalTransactionWalletBtcCard'; import { buildTerminalClosureAssetPackCompletion, readTerminalRouteError, @@ -37,6 +38,7 @@ import { buildTerminalTransactionIdentityRows, } from './terminal-transaction-detail'; import { buildTerminalTransactionReadModel } from './terminal-transaction-read-model'; +import { buildTerminalWalletBtcOperationProjection } from './terminal-wallet-btc-operation'; import { jumpToShellSection } from './terminal-shell-reading'; import { useTerminalShellBridge } from './terminal-shell-bridge'; @@ -98,6 +100,7 @@ export default function TerminalTransactionDetailSurface({ const shellReady = Boolean(controls); const showShippables = detailSection === 'shippables'; const showTransaction = detailSection === 'transaction'; + const showWalletBtc = detailSection === 'wallet-btc'; const showClosure = detailSection === 'closure'; const showProofs = detailSection === 'proofs'; const showHistory = detailSection === 'history'; @@ -189,6 +192,10 @@ export default function TerminalTransactionDetailSurface({ () => buildTerminalJournalReconciliation(detail), [detail], ); + const walletBtcOperation = useMemo( + () => buildTerminalWalletBtcOperationProjection({ selectedRun, detail }), + [detail, selectedRun], + ); const writtenAssets = detail?.writtenAssets || null; const deliveryMechanism = detail?.shippables || detail?.deliveryMechanism || null; const mergedAssetPackSurface = @@ -331,6 +338,12 @@ export default function TerminalTransactionDetailSurface({ />
+ {showWalletBtc ? ( +
+ +
+ ) : null} + {showShippables && mergedAssetPackSurface ? (
+
+ + + {operation.blockers.length ? ( +
+

+ Blocked readiness +

+
    + {operation.blockers.map((blocker) => ( +
  • {blocker}
  • + ))} +
+
+ ) : null} + + +
+ + ); +} diff --git a/uapi/app/terminal/terminal-transaction-query.ts b/uapi/app/terminal/terminal-transaction-query.ts index 0239f4426..401210b56 100644 --- a/uapi/app/terminal/terminal-transaction-query.ts +++ b/uapi/app/terminal/terminal-transaction-query.ts @@ -43,6 +43,7 @@ const TERMINAL_ENVIRONMENT_MODE_VALUES: TerminalEnvironmentMode[] = [ export type TerminalTransactionDetailSection = | 'shippables' | 'transaction' + | 'wallet-btc' | 'closure' | 'proofs' | 'history' @@ -52,6 +53,7 @@ export type TerminalTransactionDetailSection = const TRANSACTION_DETAIL_SECTION_VALUES: TerminalTransactionDetailSection[] = [ 'shippables', 'transaction', + 'wallet-btc', 'closure', 'proofs', 'history', diff --git a/uapi/app/terminal/terminal-transaction-read-model.ts b/uapi/app/terminal/terminal-transaction-read-model.ts index d5eeebb75..5f2da13f2 100644 --- a/uapi/app/terminal/terminal-transaction-read-model.ts +++ b/uapi/app/terminal/terminal-transaction-read-model.ts @@ -16,6 +16,7 @@ export type TerminalTransactionSectionAvailability = 'available' | 'empty' | 'bl export type TerminalTransactionFactFamily = | 'delivery' | 'identity' + | 'wallet' | 'settlement' | 'proof' | 'ledger' @@ -86,6 +87,13 @@ const SECTION_DEFINITIONS: Array<{ summary: 'Transaction identity, route selection, repository, participant, and timing facts.', factFamily: 'identity', }, + { + id: 'wallet-btc', + label: 'Wallet/BTC', + targetId: 'terminalTransactionWalletBtc', + summary: 'Wallet signer session, BTC fee quote, PSBT handoff, broadcast, finality, and blocked readiness.', + factFamily: 'wallet', + }, { id: 'closure', label: 'Closure', @@ -217,6 +225,22 @@ function resolveSectionAvailability({ }; } + if (sectionId === 'wallet-btc') { + const hasWalletBtc = + Boolean(detail?.ledgerSettlement?.btcFee) || + Boolean(detail?.ledgerSettlement?.btcFeeReceiptId) || + Boolean(detail?.ledgerSettlement?.ownershipBoundary); + return { + availability: hasWalletBtc ? 'available' : 'empty', + blocker: hasWalletBtc + ? null + : 'No wallet signer session, BTC fee quote, PSBT, or finality readback is attached yet.', + metricCount: 4, + rowCount: hasWalletBtc ? 8 : 0, + payloadAvailable: hasWalletBtc, + }; + } + if (sectionId === 'closure') { const hasClosure = Boolean(detail?.closureState) || diff --git a/uapi/app/terminal/terminal-wallet-btc-operation.ts b/uapi/app/terminal/terminal-wallet-btc-operation.ts new file mode 100644 index 000000000..7f5fb7e03 --- /dev/null +++ b/uapi/app/terminal/terminal-wallet-btc-operation.ts @@ -0,0 +1,201 @@ +import type { TerminalRunDetailSnapshot, TerminalJsonRecord } from './terminal-transaction-detail-snapshot'; +import type { WorkspaceRun } from './terminal-run-data'; + +export type TerminalWalletBtcOperationState = + | 'not_prepared' + | 'quote_pending' + | 'psbt_ready' + | 'signed' + | 'broadcast' + | 'confirmed' + | 'replaced' + | 'reorged' + | 'failed' + | 'blocked'; + +export interface TerminalWalletBtcOperationProjection { + state: TerminalWalletBtcOperationState; + summary: string; + metrics: Array<{ label: string; value: string }>; + rows: Array<{ label: string; value: string }>; + blockers: string[]; + nextAction: string; + canSettle: boolean; + payload: TerminalJsonRecord; +} + +function asRecord(value: unknown): TerminalJsonRecord | null { + return value && typeof value === 'object' && !Array.isArray(value) + ? (value as TerminalJsonRecord) + : null; +} + +function readString(value: unknown): string | null { + return typeof value === 'string' && value.trim() ? value.trim() : null; +} + +function readBoolean(value: unknown): boolean | null { + return typeof value === 'boolean' ? value : null; +} + +function readNumberLike(value: unknown): string | null { + if (typeof value === 'number' && Number.isFinite(value)) return new Intl.NumberFormat('en-US').format(value); + if (typeof value === 'bigint') return value.toString(); + if (typeof value === 'string' && value.trim()) return value.trim(); + return null; +} + +function readNestedRecord(record: TerminalJsonRecord | null, ...keys: string[]) { + let current: TerminalJsonRecord | null = record; + for (const key of keys) { + current = asRecord(current?.[key]); + } + return current; +} + +function readFinalityState(value: unknown): TerminalWalletBtcOperationState | null { + const normalized = readString(value); + if ( + normalized === 'prepared' || + normalized === 'psbt_ready' || + normalized === 'signed' || + normalized === 'broadcast' || + normalized === 'confirmed' || + normalized === 'replaced' || + normalized === 'reorged' || + normalized === 'failed' || + normalized === 'blocked' || + normalized === 'not_prepared' || + normalized === 'quote_pending' + ) { + return normalized === 'prepared' ? 'psbt_ready' : normalized; + } + return null; +} + +function stateSummary(state: TerminalWalletBtcOperationState) { + switch (state) { + case 'not_prepared': + return 'BTC fee settlement is not prepared for this activity yet.'; + case 'quote_pending': + return 'A BTC fee quote or accepted quote is still needed before PSBT handoff.'; + case 'psbt_ready': + return 'BTC fee PSBT is prepared and waiting for reader wallet signature.'; + case 'signed': + return 'BTC fee PSBT is signed and waiting for broadcast.'; + case 'broadcast': + return 'BTC fee transaction is broadcast and waiting for finality observation.'; + case 'confirmed': + return 'BTC fee transaction is confirmed and can unlock rights transfer and delivery checks.'; + case 'replaced': + return 'BTC fee transaction was replaced; settlement must reconcile before unlock.'; + case 'reorged': + return 'BTC fee transaction was reorged; settlement must pause and repair before unlock.'; + case 'failed': + return 'BTC fee transaction failed; restart or repair settlement before unlock.'; + case 'blocked': + return 'BTC fee settlement is blocked by signer, quote, custody, or finality readiness.'; + } +} + +export function buildTerminalWalletBtcOperationProjection({ + selectedRun, + detail, +}: { + selectedRun: WorkspaceRun; + detail: TerminalRunDetailSnapshot | null; +}): TerminalWalletBtcOperationProjection { + const ledgerSettlement = detail?.ledgerSettlement || null; + const btcFee = ledgerSettlement?.btcFee || null; + const ownershipBoundary = ledgerSettlement?.ownershipBoundary || null; + const boundaryBtcFee = readNestedRecord(ownershipBoundary, 'btcFee'); + const operationPosture = readNestedRecord(btcFee, 'operationPosture'); + const quote = readNestedRecord(operationPosture, 'quote') || readNestedRecord(btcFee, 'quote'); + const signerRecovery = readNestedRecord(operationPosture, 'signerRecovery'); + const finalityState = + readFinalityState(operationPosture?.phase) || + readFinalityState(btcFee?.finalityState) || + readFinalityState(btcFee?.finality_state) || + readFinalityState(boundaryBtcFee?.finalityState) || + (quote ? 'quote_pending' : null); + const state = finalityState || (ledgerSettlement?.btcFeeReceiptId ? 'quote_pending' : 'not_prepared'); + const serverCustody = + readBoolean(btcFee?.serverCustody) ?? + readBoolean(btcFee?.server_custody) ?? + readBoolean(operationPosture?.noServerCustody === false ? true : null); + const txid = readString(btcFee?.txid) || readString(operationPosture?.receipt && asRecord(operationPosture.receipt)?.txid); + const psbt = readString(btcFee?.psbt); + const walletSessionId = + readString(btcFee?.walletSessionId) || + readString(btcFee?.wallet_session_id) || + readString(signerRecovery?.walletSessionId); + const payerWalletId = + readString(btcFee?.payerWalletId) || + readString(btcFee?.payer_wallet_id) || + readString(ledgerSettlement?.readerWalletId) || + readString(signerRecovery?.walletId); + const network = + readString(btcFee?.network) || + readString(boundaryBtcFee?.network) || + readString(operationPosture?.network) || + 'n/a'; + const satsPaid = + readNumberLike(btcFee?.satsPaid) || + readNumberLike(btcFee?.sats_paid) || + readNumberLike(boundaryBtcFee?.satsPaid) || + readNumberLike(quote?.sats) || + 'n/a'; + const confirmations = + readNumberLike(btcFee?.confirmations) || + readNumberLike(operationPosture?.receipt && asRecord(operationPosture.receipt)?.confirmations) || + '0'; + const blockers = [ + readString(operationPosture?.blockedReadiness && asRecord(operationPosture.blockedReadiness)?.summary), + serverCustody === true ? 'Server-custody posture is rejected for BTC fee settlement.' : null, + state === 'replaced' ? 'Replacement transaction must be reconciled before unlock.' : null, + state === 'reorged' ? 'Reorged transaction must be repaired before unlock.' : null, + state === 'failed' ? 'Failed BTC fee transaction must be repaired before unlock.' : null, + state === 'quote_pending' && !quote ? 'Accepted BTC fee quote is missing.' : null, + state === 'not_prepared' ? 'Wallet signer session and accepted BTC fee quote have not prepared a PSBT.' : null, + ].filter((entry): entry is string => Boolean(entry)); + const canSettle = state === 'confirmed' && serverCustody !== true; + const nextAction = + readString(operationPosture?.nextAction) || + (canSettle + ? 'Continue to BTD rights transfer and delivery unlock.' + : blockers[0] || 'Continue the BTC fee operation to confirmation.'); + + return { + state, + summary: stateSummary(state), + metrics: [ + { label: 'BTC state', value: state }, + { label: 'Network', value: network }, + { label: 'Sats', value: satsPaid }, + { label: 'Confirmations', value: confirmations }, + ], + rows: [ + { label: 'Selected activity', value: selectedRun.id }, + { label: 'Receipt', value: readString(ledgerSettlement?.btcFeeReceiptId) || readString(btcFee?.receiptId) || 'n/a' }, + { label: 'Quote root', value: readString(quote?.quoteRoot) || 'n/a' }, + { label: 'Wallet session', value: walletSessionId || 'n/a' }, + { label: 'Payer wallet', value: payerWalletId || 'n/a' }, + { label: 'PSBT handoff', value: psbt ? 'prepared' : 'not attached' }, + { label: 'Transaction id', value: txid || 'n/a' }, + { label: 'Server custody', value: serverCustody === true ? 'rejected' : 'none' }, + { label: 'Next action', value: nextAction }, + ], + blockers, + nextAction, + canSettle, + payload: { + state, + canSettle, + ledgerSettlement, + btcFee, + ownershipBoundary, + operationPosture, + blockers, + }, + }; +} diff --git a/uapi/jest.config.cjs b/uapi/jest.config.cjs index b2bb78224..0a3f4b1eb 100644 --- a/uapi/jest.config.cjs +++ b/uapi/jest.config.cjs @@ -148,6 +148,7 @@ module.exports = { '/tests/terminalTransactionDetailSnapshot.test.ts', '/tests/terminalTransactionQuery.test.ts', '/tests/terminalTransactionReadModel.test.ts', + '/tests/terminalWalletBtcOperation.test.ts', '/tests/terminalCoreNativeSections.test.tsx', '/tests/terminalDepositComposer.test.ts', '/tests/terminalDepositComposerCard.test.tsx', diff --git a/uapi/tests/terminalTransactionReadModel.test.ts b/uapi/tests/terminalTransactionReadModel.test.ts index ecd1387eb..175b2012c 100644 --- a/uapi/tests/terminalTransactionReadModel.test.ts +++ b/uapi/tests/terminalTransactionReadModel.test.ts @@ -78,7 +78,14 @@ const detail: TerminalRunDetailSnapshot = { btcFeeReceiptId: null, depositorWalletId: 'wallet-depositor', readerWalletId: 'wallet-reader', - btcFee: null, + btcFee: { + receiptId: 'btc-fee-1', + finalityState: 'broadcast', + network: 'testnet', + satsPaid: '1200', + walletSessionId: 'wallet-session-1', + serverCustody: false, + }, ownershipBoundary: null, readback: { assetPackRange: true }, journalEntryIds: ['journal-1'], @@ -137,6 +144,11 @@ describe('terminal transaction read model', () => { availability: 'available', factFamily: 'proof', }); + expect(model.sections.find((section) => section.id === 'wallet-btc')).toMatchObject({ + label: 'Wallet/BTC', + availability: 'available', + factFamily: 'wallet', + }); }); it('marks empty and blocked sections explicitly without raw payload dependency', () => { diff --git a/uapi/tests/terminalWalletBtcOperation.test.ts b/uapi/tests/terminalWalletBtcOperation.test.ts new file mode 100644 index 000000000..8bc14a68d --- /dev/null +++ b/uapi/tests/terminalWalletBtcOperation.test.ts @@ -0,0 +1,145 @@ +import { buildTerminalWalletBtcOperationProjection } from '@/app/terminal/terminal-wallet-btc-operation'; +import type { TerminalRunDetailSnapshot } from '@/app/terminal/terminal-transaction-detail-snapshot'; +import type { WorkspaceRun } from '@/app/terminal/terminal-run-data'; + +const selectedRun: WorkspaceRun = { + id: 'tx-wallet-btc-1', + created_at: '2026-05-20T12:00:00.000Z', + type: 'agentic-execution:asset-pack', + status: 'completed', + summary: 'AssetPack preview ready for BTC fee settlement.', + sourceModel: 'execution-history', +}; + +function detailWithBtcFee(finalityState = 'confirmed'): TerminalRunDetailSnapshot { + return { + summary: 'Settlement readback.', + shippables: null, + repoSnapshot: null, + processingStats: { + time: null, + tokenTotal: null, + measuredBtd: null, + btcFeeUsdEquivalent: null, + averageLatencyMs: null, + }, + proofStatus: null, + closureFocus: null, + closureFollowThrough: null, + closureState: null, + ledgerSettlement: { + status: 'settled', + settlementAdmissible: true, + reason: null, + assetPackId: 'asset-pack-1', + btdRange: null, + ledgerAnchorId: 'anchor-1', + btcFeeReceiptId: 'btc-fee-1', + depositorWalletId: 'wallet-depositor', + readerWalletId: 'wallet-reader', + btcFee: { + receiptId: 'btc-fee-1', + finalityState, + network: 'testnet', + satsPaid: '1200', + confirmations: 2, + txid: 'txid-1', + psbt: 'signed-psbt', + walletSessionId: 'wallet-session-1', + payerWalletId: 'wallet-reader', + serverCustody: false, + operationPosture: { + phase: finalityState, + noServerCustody: true, + nextAction: 'Continue to BTD rights transfer and delivery unlock.', + quote: { + quoteId: 'quote-1', + quoteRoot: 'btc-fee-quote-root', + sats: '1200', + }, + signerRecovery: { + state: 'live_authorized', + walletSessionId: 'wallet-session-1', + walletId: 'wallet-reader', + }, + }, + }, + ownershipBoundary: null, + readback: {}, + journalEntryIds: [], + ownershipEventId: 'ownership-1', + readLicenseId: 'license-1', + }, + terminalJournal: null, + bitcodeActivityState: null, + historyItemCount: 0, + eventCount: 0, + }; +} + +describe('Terminal wallet/BTC operation projection', () => { + it('projects confirmed BTC fee settlement as unlock-ready without exposing private custody', () => { + const projection = buildTerminalWalletBtcOperationProjection({ + selectedRun, + detail: detailWithBtcFee(), + }); + + expect(projection).toMatchObject({ + state: 'confirmed', + canSettle: true, + blockers: [], + }); + expect(projection.metrics).toEqual( + expect.arrayContaining([ + { label: 'BTC state', value: 'confirmed' }, + { label: 'Sats', value: '1200' }, + ]), + ); + expect(projection.rows).toEqual( + expect.arrayContaining([ + { label: 'Wallet session', value: 'wallet-session-1' }, + { label: 'Server custody', value: 'none' }, + ]), + ); + }); + + it('surfaces replacement and missing quote readiness as blocked operational detail', () => { + const projection = buildTerminalWalletBtcOperationProjection({ + selectedRun, + detail: { + ...detailWithBtcFee('replaced'), + ledgerSettlement: { + ...detailWithBtcFee('replaced').ledgerSettlement!, + btcFee: { + ...detailWithBtcFee('replaced').ledgerSettlement!.btcFee!, + operationPosture: { + phase: 'replaced', + blockedReadiness: { + summary: 'Replacement transaction must be reconciled.', + }, + }, + }, + }, + }, + }); + + expect(projection.state).toBe('replaced'); + expect(projection.canSettle).toBe(false); + expect(projection.blockers).toEqual( + expect.arrayContaining([ + 'Replacement transaction must be reconciled.', + 'Replacement transaction must be reconciled before unlock.', + ]), + ); + + const missing = buildTerminalWalletBtcOperationProjection({ + selectedRun, + detail: null, + }); + expect(missing).toMatchObject({ + state: 'not_prepared', + canSettle: false, + }); + expect(missing.blockers[0]).toContain('Wallet signer session'); + }); +}); From 845dc718da5f38bad151e905d8a23892bc593337 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Wed, 20 May 2026 15:05:15 -0300 Subject: [PATCH 04/18] Gate 4: Reading pipeline observability (#23) * Gate 4: project Reading pipeline observability Add contract-aware observability inventory and projection for ReadNeedComprehensionSynthesis and ReadFitsFindingSynthesis, stamp sandbox harness stream events with PTRR and ThricifiedGeneration metadata, and surface those fields through the Terminal execution stream UI. Update V29 spec, parity, docs, Gate 4 checker, CI wiring, and focused package/UAPI tests for the Reading telemetry closure criteria. * Gate 4: satisfy UAPI observability typecheck Normalize PTRR step-id parsing so the stricter UAPI TypeScript build receives a concrete string before checking Reading pipeline telemetry step names. Validation: pnpm -C uapi exec tsc --noEmit; pnpm run check:v29-gate4; pnpm --dir uapi exec jest --runTestsByPath tests/terminalPipelineHarnessClient.test.ts tests/pipelineExecutionLogHeader.test.tsx --runInBand; pnpm exec eslint packages/pipelines/asset-pack/src/reading-pipeline-observability.ts uapi/app/terminal/terminal-pipeline-harness-client.ts uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx uapi/components/base/bitcode/execution/pipeline-execution-log.tsx --ext .ts,.tsx; git diff --check --- .github/workflows/bitcode-gate-quality.yml | 2 + BITCODE_SPEC_V29.md | 34 ++ BITCODE_SPEC_V29_DELTA.md | 9 + BITCODE_SPEC_V29_NOTES.md | 14 + BITCODE_SPEC_V29_PARITY_MATRIX.md | 26 +- package.json | 1 + .../src/__tests__/asset-pack-harness.test.ts | 8 + .../pipeline-hosts/src/asset-pack-harness.ts | 52 +- packages/pipelines/asset-pack/package.json | 1 + .../reading-pipeline-observability.test.ts | 170 ++++++ packages/pipelines/asset-pack/src/index.ts | 1 + .../src/reading-pipeline-observability.ts | 507 ++++++++++++++++++ ...9-gate4-reading-pipeline-observability.mjs | 233 ++++++++ uapi/app/terminal/README.md | 7 + .../terminal-pipeline-harness-client.ts | 55 +- .../base/bitcode/execution/README.md | 13 + .../pipeline-execution-log-header.tsx | 36 +- .../execution/pipeline-execution-log.tsx | 125 ++++- .../tests/pipelineExecutionLogHeader.test.tsx | 10 + .../terminalPipelineHarnessClient.test.ts | 60 ++- 20 files changed, 1349 insertions(+), 15 deletions(-) create mode 100644 packages/pipelines/asset-pack/src/__tests__/reading-pipeline-observability.test.ts create mode 100644 packages/pipelines/asset-pack/src/reading-pipeline-observability.ts create mode 100644 scripts/check-v29-gate4-reading-pipeline-observability.mjs diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 3d84605ab..18d874055 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -48,6 +48,7 @@ jobs: node scripts/check-v29-gate1-objectives-and-gating.mjs --skip-branch-check node scripts/check-v29-gate2-terminal-transaction-read-models.mjs --skip-branch-check node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs --skip-branch-check + node scripts/check-v29-gate4-reading-pipeline-observability.mjs --skip-branch-check - name: Validate source casing and imports run: | @@ -65,6 +66,7 @@ jobs: pnpm --filter @bitcode/btd test pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btc-fee-operation.test.ts pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --passWithNoTests --forceExit + pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath src/__tests__/reading-pipeline-observability.test.ts src/__tests__/reading-pipeline-contract.test.ts --runInBand pnpm --filter @bitcode/pipeline-hosts exec jest --config jest.config.cjs --passWithNoTests --forceExit - name: Test staged Reading route and Terminal harness contracts diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index 4f0975226..a00440bd4 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -247,6 +247,40 @@ It may not expose protected AssetPack source, wallet secrets, provider tokens, o - Current validating commands and parity basis: pipeline contract tests, route tests, prompt rendering/audit checks, local live OpenAI validation, and V29 gate checks. - Current accepted boundaries: full-profile async push completion can deepen in V29 gates but cannot bypass source-safe preview or settlement boundaries. +#### V29 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. diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index 25bb6a1c9..1d65a7c81 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -113,6 +113,15 @@ Closure acceptance: Gate 4 owns deep Terminal visibility over `ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis`, including execution, phase, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, output, and typed parse telemetry. +Closure acceptance: + +- `@bitcode/pipeline-asset-pack` exposes a Reading pipeline observability inventory and `ReadingPipelineTelemetryProjection` over the existing Reading pipeline contracts. +- The inventory accounts for both Reading pipelines, 11 phases, 12 PTRR agents, 48 PTRR steps, 144 ThricifiedGenerations, all registered prompt templates, all ThricifiedGeneration prompt ids, and the four Finding Fits tools. +- The Vercel Sandbox harness annotates stream events with pipeline name, phase id, PTRR agent id, PTRR step id, ThricifiedGeneration id, prompt template id, generation prompt ids, tool id, output schema, return type, and prompt/raw/parsed/tool evidence posture. +- Harness evidence includes Reading observability inventory and coverage readback so local/staging failures show exactly which telemetry levels were not observed. +- Terminal converts harness SSE events into the shared execution log shape with contract-aware execution state, summary rows, and expandable metadata for prompt template, interpolated prompt, raw response, parsed typed output, tools, and output schema. +- Gate-quality CI runs the Gate 4 checker plus focused asset-pack, pipeline-host, Terminal harness, and execution-log header tests. + ### Gate 5: AssetPack Disclosure Rights And Preview Depth Gate 5 owns AssetPack range detail, owner-read/licensed-read/denied-state flows, source-safe preview, disclosure policy review, paid unlock state, and protected-source leakage tests. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 8498e5e84..a73028b5f 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -60,6 +60,7 @@ For a simplified reading of V29: 4. **Gate 4: Reading Transaction Recovery And Pipeline Observability** - Make `ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis` execution telemetry fully readable in Terminal at execution, phase, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, raw output, and parsed output levels. + - Acceptance detail: the asset-pack package owns the observability inventory/projection; the sandbox harness stamps live stream events with contract identifiers and coverage; Terminal renders those identifiers in the shared execution stream header, row summary, and expandable metadata. 5. **Gate 5: AssetPack Disclosure Rights And Preview Depth** - Deepen source-safe preview, AssetPack range detail, owner-read/licensed-read/denied state, disclosure policy review, paid unlock, and source-leakage tests. @@ -120,6 +121,19 @@ Accepted Gate 3 posture: - Terminal has a Wallet/BTC detail section so fee readiness is visible before raw ledger payload inspection. - Gate 3 does not implement settlement reconciliation repair; Gate 6 owns drift repair and ledger/database reconciliation action depth. +## Gate 4 working notes + +Gate 4 makes Reading pipeline telemetry readable without changing the underlying execution primitive names. +Execution remains the base primitive, Reading pipelines compose phases, each phase owns PTRR agents, each PTRR agent owns plan/try/refine/retry steps, and each step carries ThricifiedGeneration prompt/output evidence. + +Accepted Gate 4 posture: + +- `reading-pipeline-contract.ts` remains the source of pipeline, phase, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, and return-type contracts. +- `reading-pipeline-observability.ts` projects live stream events onto those contracts and reports observability coverage. +- The sandbox harness records contract-aware telemetry events and stores coverage in exported evidence. +- Terminal's live harness stream shows pipeline, phase id, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, output schema, raw output posture, and parsed typed output posture through the shared execution log components. +- Gate 4 does not implement disclosure-depth unlock, settlement repair, organization authority, or full browser proof; later gates own those slices. + ## Later-version boundaries - V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 42b037d8c..b2032c872 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -51,7 +51,7 @@ No `_legacy/` source is active source truth. | Workflow retargeting | Gate 1 | `.github/workflows/bitcode-gate-quality.yml`, `.github/workflows/bitcode-canon-quality.yml` | drafted | CI checks V28 active / V29 draft posture instead of stale V27/V28 posture. | | Terminal transaction read models | Gate 2 | `uapi/app/terminal/terminal-transaction-read-model.ts`, `uapi/app/terminal/terminal-transaction-query.ts`, `TerminalTransactionWorkspace.tsx`, `TerminalTransactionDetailSurface.tsx`, UAPI tests, Gate 2 checker | drafted | Terminal transaction state is URL-addressable, recoverable, typed, low-detail by default, and expandable without raw JSON as the ordinary operator contract. | | Wallet signer/BTC operations | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, BTC fee route, Terminal Wallet/BTC detail section, BTD and UAPI tests, Gate 3 checker | drafted | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | -| Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack`, `packages/pipeline-hosts`, Terminal stream components | pending | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt telemetry is complete and readable. | +| Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack/src/reading-pipeline-observability.ts`, `packages/pipeline-hosts/src/asset-pack-harness.ts`, Terminal stream components, Gate 4 checker | drafted | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt/raw-output/parsed-output telemetry is contract-projected, complete, and readable. | | AssetPack disclosure rights | Gate 5 | BTD access primitives, AssetPack preview UI, disclosure policy tests | pending | Source-safe preview and paid unlock are proven without source leakage. | | Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, Terminal repair UI | pending | Ledger, database, and metaphysical state drift is visible and repairable. | | Organization permission authority | Gate 7 | access policy, org holdings, MCP/ChatGPT gates, Terminal permission UI | pending | Registry-derived roles, holdings, and read-license authority govern actions. | @@ -69,6 +69,7 @@ No `_legacy/` source is active source truth. | Gate 1 script | `pnpm run check:v29-gate1` fails closed on stale posture or missing gates | drafted | | Gate 2 read model | `pnpm run check:v29-gate2` proves typed route-owned Terminal transaction reading | drafted | | Gate 3 wallet/BTC operation | `pnpm run check:v29-gate3` proves quote lifecycle, signer recovery, blocked readiness, API posture, and Terminal Wallet/BTC detail | drafted | +| Gate 4 Reading observability | `pnpm run check:v29-gate4` proves contract-aware Reading stream telemetry and Terminal rendering | drafted | | Product implementation gates | Gates 3-9 close remaining Terminal transaction depth with tests and docs | pending | | Promotion gate | Gate 10 closes generated proof and promotion automation | pending | @@ -139,3 +140,26 @@ Gate 2 is complete when Terminal selected transaction state rewrites recoverable ## Gate 3 completion condition Gate 3 is complete when package primitives model BTC quotes, signer recovery, operation posture, and blocked readiness; API responses serialize operation posture; Terminal has a Wallet/BTC route-owned detail section; focused package and UAPI tests pass; `check:v29-gate3` passes; CI invokes the checker and tests; docs name the implemented source surfaces; and the gate branch is committed and pushed for review into `version/v29`. + +## Gate 4 Parity + +| Requirement | Source evidence | Current V29 judgment | +| --- | --- | --- | +| Reading pipeline contracts remain the source of truth | `reading-pipeline-contract.ts`, contract tests | drafted | +| Observability inventory covers both Reading pipelines and all contract levels | `reading-pipeline-observability.ts`, observability tests | drafted | +| Live sandbox harness stamps stream events with contract ids and output posture | `packages/pipeline-hosts/src/asset-pack-harness.ts`, harness tests | drafted | +| Harness evidence exports inventory and coverage readback | `readingPipelineObservabilityInventory`, `readingPipelineObservabilityCoverage`, harness tests | drafted | +| Terminal summaries and execution state expose pipeline, phase, PTRR, ThricifiedGeneration, prompt, tool, and schema fields | `terminal-pipeline-harness-client.ts`, Terminal harness tests | drafted | +| Shared execution log header renders contract-aware identifiers without raw JSON first | `pipeline-execution-log-header.tsx`, header tests | drafted | +| Gate 4 checker is wired to package scripts and CI | `scripts/check-v29-gate4-reading-pipeline-observability.mjs`, `package.json`, gate workflow | drafted | + +## Gate 4 accepted boundaries + +- Gate 4 does not add a new execution primitive; it projects existing execution, pipeline, PTRR, and ThricifiedGeneration primitives. +- Gate 4 does not expose protected AssetPack source before settlement. +- Gate 4 does not close disclosure-depth unlock, settlement repair, organization authority, or full browser proof. +- Gate 4 does not add versioned API routes or source identifiers. + +## Gate 4 completion condition + +Gate 4 is complete when Reading pipeline observability is package-owned, stream events are contract-projected in the sandbox harness, Terminal renders the projection through shared execution components, focused package and UAPI tests pass, `check:v29-gate4` passes, CI invokes the checker and tests, docs name the implemented source surfaces, and the gate branch is committed and pushed for review into `version/v29`. diff --git a/package.json b/package.json index b3169f58a..440b8b456 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ "check:v29-gate1": "node scripts/check-v29-gate1-objectives-and-gating.mjs", "check:v29-gate2": "node scripts/check-v29-gate2-terminal-transaction-read-models.mjs", "check:v29-gate3": "node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs", + "check:v29-gate4": "node scripts/check-v29-gate4-reading-pipeline-observability.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/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts b/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts index 72e552da7..23bcf85c1 100644 --- a/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts +++ b/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts @@ -187,6 +187,14 @@ describe('asset-pack sandbox harness plan', () => { expect(source).toContain('rawModelResponsePresent'); expect(source).toContain('parsedTypedOutputPresent'); expect(source).toContain('inferenceAudit'); + expect(source).toContain('buildReadingPipelineObservabilityInventory'); + expect(source).toContain('resolveReadingPipelineTelemetryProjection'); + expect(source).toContain('summarizeReadingPipelineObservabilityCoverage'); + expect(source).toContain('readingPipelineTelemetry'); + expect(source).toContain('ptrrStepId'); + expect(source).toContain('thricifiedGenerationId'); + expect(source).toContain('outputSchema'); + expect(source).toContain('readingPipelineObservabilityCoverage'); expect(source).toContain('Pipeline produced '); expect(source).toContain('sourceSafePreview,'); expect(source).toContain('protectedSourceUnlock'); diff --git a/packages/pipeline-hosts/src/asset-pack-harness.ts b/packages/pipeline-hosts/src/asset-pack-harness.ts index 7485bc4e7..13e1bff06 100644 --- a/packages/pipeline-hosts/src/asset-pack-harness.ts +++ b/packages/pipeline-hosts/src/asset-pack-harness.ts @@ -392,6 +392,9 @@ let checkpointTimer = null; let heartbeatTimer = null; let checkpointInFlight = Promise.resolve(); let lastCheckpointAt = 0; +let readingPipelineObservabilityInventory = null; +let resolveReadingPipelineTelemetryProjectionFn = null; +let summarizeReadingPipelineObservabilityCoverageFn = null; function normalizeResultState(candidate) { return ['worthy_fit', 'no_worthy_fit', 'blocked_readiness'].includes(candidate) @@ -532,6 +535,15 @@ function summarizeStreamEvent(event) { parsedTypedOutput: summarizeInspectableValue(data.parsedTypedOutput ?? data.parsed ?? null), } : null; + const readingPipelineTelemetry = resolveReadingPipelineTelemetryProjectionFn + ? resolveReadingPipelineTelemetryProjectionFn({ + ...event, + data: { + ...(data || {}), + telemetryEvent: event, + }, + }) + : null; return { type: 'pipeline-stream-event', stage: stageForStreamEvent(event), @@ -558,6 +570,19 @@ function summarizeStreamEvent(event) { parsedTypedOutputPresent: Boolean(data?.parsedTypedOutput || data?.parsed), inferenceAudit: llmAudit, inspectable: summarizeLlmInspectable(event, event?.data ?? null), + readingPipelineTelemetry, + pipelineName: readingPipelineTelemetry?.pipelineName || null, + phaseId: readingPipelineTelemetry?.phaseId || null, + agentId: readingPipelineTelemetry?.agentId || null, + ptrrStepId: readingPipelineTelemetry?.ptrrStepId || null, + ptrrStepName: readingPipelineTelemetry?.ptrrStepName || null, + thricifiedGenerationId: readingPipelineTelemetry?.thricifiedGenerationId || null, + thricifiedFailsafe: readingPipelineTelemetry?.thricifiedFailsafe || null, + promptTemplateId: readingPipelineTelemetry?.promptTemplateId || null, + generationPromptIds: readingPipelineTelemetry?.generationPromptIds || null, + toolId: readingPipelineTelemetry?.toolId || null, + outputSchema: readingPipelineTelemetry?.outputSchema || null, + returnType: readingPipelineTelemetry?.returnType || null, }; } @@ -672,6 +697,10 @@ function checkpointEvidence(reason) { output, error, execution: execution ? summarizeExecution(execution) : null, + readingPipelineObservabilityInventory, + readingPipelineObservabilityCoverage: summarizeReadingPipelineObservabilityCoverageFn + ? summarizeReadingPipelineObservabilityCoverageFn(events) + : null, events, startedAt, checkpointAt: new Date().toISOString(), @@ -1523,7 +1552,16 @@ try { manifestRoot = createHash('sha256').update(JSON.stringify(manifest)).digest('hex'); userId = process.env.BITCODE_PIPELINE_USER_ID || manifest.deposit?.userId || DEFAULT_USER_ID; const [ - { assetPackPipeline, acceptReadNeed, buildAssetPackSourceSafePreview, isAcceptedReadNeed, synthesizeReadNeedForPipelineInput }, + { + assetPackPipeline, + acceptReadNeed, + buildAssetPackSourceSafePreview, + buildReadingPipelineObservabilityInventory, + isAcceptedReadNeed, + resolveReadingPipelineTelemetryProjection, + summarizeReadingPipelineObservabilityCoverage, + synthesizeReadNeedForPipelineInput, + }, { enablePipelineStreaming, factoryPipelineExecution }, { applyAssetPackSettlementUnlockToPreview, buildAssetPackSettlementUnlock }, ] = await Promise.all([ @@ -1531,6 +1569,9 @@ try { import('../../packages/pipelines-generics/src/index'), import('../../packages/btd/src/settlement'), ]); + readingPipelineObservabilityInventory = buildReadingPipelineObservabilityInventory(); + resolveReadingPipelineTelemetryProjectionFn = resolveReadingPipelineTelemetryProjection; + summarizeReadingPipelineObservabilityCoverageFn = summarizeReadingPipelineObservabilityCoverage; execution = factoryPipelineExecution('asset_pack', undefined, { pipelineName: 'asset_pack', family: 'asset_pack', @@ -1709,6 +1750,9 @@ try { settlementAdmissible: ledgerSettlement.settlementAdmissible, assetPackId: ledgerSettlement.assetPackId || null, }); + const readingPipelineObservabilityCoverage = summarizeReadingPipelineObservabilityCoverageFn + ? summarizeReadingPipelineObservabilityCoverageFn(events) + : null; const evidence = { schema: 'bitcode.pipeline-harness.evidence', @@ -1730,6 +1774,8 @@ try { shippables: output?.shippables || null, ledgerSettlement: output.ledgerSettlement, execution: summarizeExecution(execution), + readingPipelineObservabilityInventory, + readingPipelineObservabilityCoverage, events, startedAt, completedAt: new Date().toISOString(), @@ -1774,6 +1820,10 @@ try { output, error, execution: execution ? summarizeExecution(execution) : null, + readingPipelineObservabilityInventory, + readingPipelineObservabilityCoverage: summarizeReadingPipelineObservabilityCoverageFn + ? summarizeReadingPipelineObservabilityCoverageFn(events) + : null, events, startedAt, completedAt: new Date().toISOString(), diff --git a/packages/pipelines/asset-pack/package.json b/packages/pipelines/asset-pack/package.json index 2d8f7f24f..8e6c677a8 100644 --- a/packages/pipelines/asset-pack/package.json +++ b/packages/pipelines/asset-pack/package.json @@ -8,6 +8,7 @@ ".": "./src/index.ts", "./read-need": "./src/read-need.ts", "./reading-pipeline-contract": "./src/reading-pipeline-contract.ts", + "./reading-pipeline-observability": "./src/reading-pipeline-observability.ts", "./depository-search": "./src/depository-search.ts" }, "scripts": { diff --git a/packages/pipelines/asset-pack/src/__tests__/reading-pipeline-observability.test.ts b/packages/pipelines/asset-pack/src/__tests__/reading-pipeline-observability.test.ts new file mode 100644 index 000000000..a4dedf6fd --- /dev/null +++ b/packages/pipelines/asset-pack/src/__tests__/reading-pipeline-observability.test.ts @@ -0,0 +1,170 @@ +import { + READ_FITS_FINDING_SYNTHESIS, + READ_NEED_COMPREHENSION_SYNTHESIS, +} from '../reading-pipeline-contract'; +import { + buildReadingPipelineObservabilityInventory, + resolveReadingPipelineTelemetryProjection, + summarizeReadingPipelineObservabilityCoverage, +} from '../reading-pipeline-observability'; + +describe('Reading pipeline observability projection', () => { + it('indexes the complete Reading pipeline observability inventory', () => { + const inventory = buildReadingPipelineObservabilityInventory(); + + expect(inventory.pipelineNames).toEqual([ + READ_NEED_COMPREHENSION_SYNTHESIS, + READ_FITS_FINDING_SYNTHESIS, + ]); + expect(inventory.telemetryLevels).toEqual([ + 'execution', + 'phase', + 'ptrr-agent', + 'ptrr-step', + 'thricified-generation', + 'prompt', + 'tool', + 'raw-output', + 'parsed-output', + ]); + expect(inventory.totals).toEqual({ + pipelines: 2, + phases: 11, + ptrrAgents: 12, + ptrrSteps: 48, + thricifiedGenerations: 144, + promptTemplates: 5, + thricifiedGenerationPrompts: 432, + tools: 4, + }); + expect(inventory.traceEntries).toHaveLength(48); + }); + + it('projects LLM prompt telemetry onto the precise PTRR and ThricifiedGeneration contract', () => { + const projection = resolveReadingPipelineTelemetryProjection({ + type: 'pipeline-stream-event', + streamEventType: 'store', + namespace: 'llm', + key: 'prompt', + pipelineName: READ_FITS_FINDING_SYNTHESIS, + phaseId: 'ReadFitsFindingSynthesis.implementation', + agentId: 'ReadFitsFindingSynthesis.implementation.asset-pack', + ptrrStepId: 'ReadFitsFindingSynthesis.implementation.asset-pack.try', + thricifiedGenerationId: + 'ReadFitsFindingSynthesis.thricified-generation.implementation.asset-pack.try.prepare-concise-context', + promptTemplatePresent: true, + interpolatedPromptPresent: true, + }); + + expect(projection).toMatchObject({ + pipelineName: READ_FITS_FINDING_SYNTHESIS, + level: 'prompt', + phaseId: 'ReadFitsFindingSynthesis.implementation', + agentId: 'ReadFitsFindingSynthesis.implementation.asset-pack', + ptrrStepId: 'ReadFitsFindingSynthesis.implementation.asset-pack.try', + ptrrStepName: 'try', + thricifiedGenerationId: + 'ReadFitsFindingSynthesis.thricified-generation.implementation.asset-pack.try.prepare-concise-context', + thricifiedFailsafe: 'prepare-concise-context', + promptTemplateId: 'ReadFitsFindingSynthesis.prompt.asset-pack-synthesis', + returnType: 'AssetPackSynthesisOutput', + outputSchema: 'AssetPackSynthesisOutput', + evidence: { + promptTemplatePresent: true, + interpolatedPromptPresent: true, + }, + matched: true, + }); + expect(projection.generationPromptIds).toEqual({ + reasonPromptId: + 'ReadFitsFindingSynthesis.prompt.implementation.asset-pack.try.prepare-concise-context.reason', + judgePromptId: + 'ReadFitsFindingSynthesis.prompt.implementation.asset-pack.try.prepare-concise-context.judge', + structuredOutputPromptId: + 'ReadFitsFindingSynthesis.prompt.implementation.asset-pack.try.prepare-concise-context.structured-output', + }); + }); + + it('projects depository tool telemetry onto Finding Fits discovery', () => { + const projection = resolveReadingPipelineTelemetryProjection({ + type: 'pipeline-stream-event', + streamEventType: 'tool-use', + namespace: 'tools', + key: 'result', + tool: 'ReadFitsFindingSynthesis.tool.vector-depository-search', + toolInputPresent: true, + toolOutputPresent: true, + }); + + expect(projection).toMatchObject({ + pipelineName: READ_FITS_FINDING_SYNTHESIS, + level: 'tool', + phaseId: 'ReadFitsFindingSynthesis.discovery', + agentId: 'ReadFitsFindingSynthesis.discovery.finding-fits', + ptrrStepId: 'ReadFitsFindingSynthesis.discovery.finding-fits.try', + ptrrStepName: 'try', + toolId: 'ReadFitsFindingSynthesis.tool.vector-depository-search', + inputType: 'EmbeddingSearchRequest', + outputType: 'EmbeddingSearchResult', + returnType: 'DepositoryFitsResult', + evidence: { + toolInputPresent: true, + toolOutputPresent: true, + }, + matched: true, + }); + }); + + it('summarizes coverage from projected live stream events', () => { + const coverage = summarizeReadingPipelineObservabilityCoverage([ + { + pipelineName: READ_NEED_COMPREHENSION_SYNTHESIS, + }, + { + pipelineName: READ_FITS_FINDING_SYNTHESIS, + phaseId: 'ReadFitsFindingSynthesis.discovery', + }, + { + pipelineName: READ_FITS_FINDING_SYNTHESIS, + agentId: 'ReadFitsFindingSynthesis.discovery.finding-fits', + }, + { + pipelineName: READ_FITS_FINDING_SYNTHESIS, + ptrrStepId: 'ReadFitsFindingSynthesis.discovery.finding-fits.try', + }, + { + pipelineName: READ_FITS_FINDING_SYNTHESIS, + thricifiedGenerationId: + 'ReadFitsFindingSynthesis.thricified-generation.discovery.finding-fits.try.prepare-concise-context', + }, + { + pipelineName: READ_FITS_FINDING_SYNTHESIS, + ptrrStepId: 'ReadFitsFindingSynthesis.implementation.asset-pack.try', + promptTemplatePresent: true, + }, + { + tool: 'ReadFitsFindingSynthesis.tool.lexical-depository-search', + }, + { + pipelineName: READ_FITS_FINDING_SYNTHESIS, + ptrrStepId: 'ReadFitsFindingSynthesis.implementation.asset-pack.try', + rawModelResponsePresent: true, + }, + { + pipelineName: READ_FITS_FINDING_SYNTHESIS, + ptrrStepId: 'ReadFitsFindingSynthesis.implementation.asset-pack.try', + parsedTypedOutputPresent: true, + }, + ]); + + expect(coverage.pipelineNames).toEqual([ + READ_FITS_FINDING_SYNTHESIS, + READ_NEED_COMPREHENSION_SYNTHESIS, + ]); + expect(coverage.missingRequiredLevels).toEqual([]); + expect(coverage.promptTelemetryReady).toBe(true); + expect(coverage.toolTelemetryReady).toBe(true); + expect(coverage.rawOutputTelemetryReady).toBe(true); + expect(coverage.parsedOutputTelemetryReady).toBe(true); + }); +}); diff --git a/packages/pipelines/asset-pack/src/index.ts b/packages/pipelines/asset-pack/src/index.ts index 1c912d9ed..93651ea38 100644 --- a/packages/pipelines/asset-pack/src/index.ts +++ b/packages/pipelines/asset-pack/src/index.ts @@ -270,6 +270,7 @@ export * from './types/AssetPackWrittenAssetType'; export * from './depository-search'; export * from './embedding-config'; export * from './reading-pipeline-contract'; +export * from './reading-pipeline-observability'; export { AssetPackCloneVCSRepositoryAgent } from './agents/setup/asset-pack-clone-vcs-repository-agent'; export { ReadFitsFindingSynthesisReadComprehensionAgent, diff --git a/packages/pipelines/asset-pack/src/reading-pipeline-observability.ts b/packages/pipelines/asset-pack/src/reading-pipeline-observability.ts new file mode 100644 index 000000000..374ef1b36 --- /dev/null +++ b/packages/pipelines/asset-pack/src/reading-pipeline-observability.ts @@ -0,0 +1,507 @@ +import { + READ_FITS_FINDING_SYNTHESIS, + READ_NEED_COMPREHENSION_SYNTHESIS, + READING_PIPELINE_CONTRACTS, + type ReadingPipelineName, + type ReadingPipelinePtrrStepContract, + type ReadingPipelinePtrrStepName, + type ReadingPipelineTelemetryTraceEntry, + type ReadingPipelineThricifiedFailsafe, + type ReadingPipelineToolContract, + listReadingPipelineContractSummaries, + listReadingPipelineTelemetryTrace, +} from './reading-pipeline-contract'; + +export const READING_PIPELINE_TELEMETRY_LEVELS = [ + 'execution', + 'phase', + 'ptrr-agent', + 'ptrr-step', + 'thricified-generation', + 'prompt', + 'tool', + 'raw-output', + 'parsed-output', +] as const; + +export type ReadingPipelineTelemetryLevel = (typeof READING_PIPELINE_TELEMETRY_LEVELS)[number]; + +export type ReadingPipelineTelemetryProjection = { + schema: 'bitcode.reading.pipeline.telemetry.projection'; + pipelineName: ReadingPipelineName | null; + level: ReadingPipelineTelemetryLevel; + phaseId: string | null; + agentId: string | null; + ptrrStepId: string | null; + ptrrStepName: ReadingPipelinePtrrStepName | null; + thricifiedGenerationId: string | null; + thricifiedFailsafe: ReadingPipelineThricifiedFailsafe | null; + promptTemplateId: string | null; + generationPromptIds: { + reasonPromptId: string | null; + judgePromptId: string | null; + structuredOutputPromptId: string | null; + }; + toolId: string | null; + inputType: string | null; + outputType: string | null; + returnType: string | null; + outputSchema: string | null; + stores: string[]; + telemetry: string[]; + evidence: { + promptTemplatePresent: boolean; + interpolatedPromptPresent: boolean; + reasoningPresent: boolean; + judgmentPresent: boolean; + rawModelResponsePresent: boolean; + parsedTypedOutputPresent: boolean; + toolInputPresent: boolean; + toolOutputPresent: boolean; + toolErrorPresent: boolean; + }; + matched: boolean; +}; + +export type ReadingPipelineObservabilityInventory = { + schema: 'bitcode.reading.pipeline.observability.inventory'; + pipelineNames: ReadingPipelineName[]; + telemetryLevels: ReadingPipelineTelemetryLevel[]; + summaries: ReturnType; + totals: { + pipelines: number; + phases: number; + ptrrAgents: number; + ptrrSteps: number; + thricifiedGenerations: number; + promptTemplates: number; + thricifiedGenerationPrompts: number; + tools: number; + }; + traceEntries: ReadingPipelineTelemetryTraceEntry[]; +}; + +export type ReadingPipelineObservabilityCoverage = { + schema: 'bitcode.reading.pipeline.observability.coverage'; + eventCount: number; + matchedEventCount: number; + pipelineNames: ReadingPipelineName[]; + levelCounts: Record; + missingRequiredLevels: ReadingPipelineTelemetryLevel[]; + promptTelemetryReady: boolean; + toolTelemetryReady: boolean; + rawOutputTelemetryReady: boolean; + parsedOutputTelemetryReady: boolean; +}; + +type IndexedTrace = ReadingPipelineTelemetryTraceEntry & { + agentKey: string; + phaseKey: string; + ptrrStep: ReadingPipelinePtrrStepContract | null; +}; + +type ProjectionSource = { + data: Record | null; + executionState: Record | null; + executionPath: string[]; + textCandidates: string[]; + explicitPipelineName: ReadingPipelineName | null; + explicitPhaseId: string | null; + explicitAgentId: string | null; + explicitPtrrStepId: string | null; + explicitThricifiedGenerationId: string | null; + explicitToolId: string | null; +}; + +const TRACE_INDEX: IndexedTrace[] = READING_PIPELINE_CONTRACTS.flatMap((contract) => + listReadingPipelineTelemetryTrace(contract).map((trace) => { + const phaseKey = trace.phaseId.split('.').pop() || trace.phaseId; + const agentKey = trace.agentId.split('.').pop() || trace.agentId; + const phase = contract.phases.find((candidatePhase) => candidatePhase.phaseId === trace.phaseId); + const agent = phase?.agents.find((candidateAgent) => candidateAgent.agentId === trace.agentId); + const ptrrStep = agent?.ptrrSteps.find((candidateStep) => candidateStep.ptrrStepId === trace.ptrrStepId) || null; + return { + ...trace, + phaseKey, + agentKey, + ptrrStep, + }; + }), +); + +const READING_PIPELINE_NAMES = [ + READ_NEED_COMPREHENSION_SYNTHESIS, + READ_FITS_FINDING_SYNTHESIS, +] as const; + +export function buildReadingPipelineObservabilityInventory(): ReadingPipelineObservabilityInventory { + const phases = READING_PIPELINE_CONTRACTS.flatMap((contract) => contract.phases); + const agents = phases.flatMap((phase) => phase.agents); + const ptrrSteps = agents.flatMap((agent) => agent.ptrrSteps); + const thricifiedGenerations = ptrrSteps.flatMap((step) => step.thricifiedGenerations); + const promptTemplateIds = new Set(ptrrSteps.map((step) => step.prompt?.templateId).filter(Boolean)); + const thricifiedGenerationPromptIds = new Set( + thricifiedGenerations.flatMap((generation) => [ + generation.reasonPromptId, + generation.judgePromptId, + generation.structuredOutputPromptId, + ]), + ); + const toolIds = new Set(ptrrSteps.flatMap((step) => step.tools.map((tool) => tool.toolId))); + + return { + schema: 'bitcode.reading.pipeline.observability.inventory', + pipelineNames: [...READING_PIPELINE_NAMES], + telemetryLevels: [...READING_PIPELINE_TELEMETRY_LEVELS], + summaries: listReadingPipelineContractSummaries(), + totals: { + pipelines: READING_PIPELINE_CONTRACTS.length, + phases: phases.length, + ptrrAgents: agents.length, + ptrrSteps: ptrrSteps.length, + thricifiedGenerations: thricifiedGenerations.length, + promptTemplates: promptTemplateIds.size, + thricifiedGenerationPrompts: thricifiedGenerationPromptIds.size, + tools: toolIds.size, + }, + traceEntries: TRACE_INDEX.map(({ agentKey, phaseKey, ptrrStep, ...trace }) => trace), + }; +} + +export function resolveReadingPipelineTelemetryProjection( + eventLike: unknown, +): ReadingPipelineTelemetryProjection { + const source = normalizeProjectionSource(eventLike); + const matchedTrace = findMatchingTrace(source); + const generation = findMatchingThricifiedGeneration(source, matchedTrace); + const tool = findMatchingTool(source, matchedTrace); + const ptrrStep = matchedTrace?.ptrrStep || null; + const pipelineName = source.explicitPipelineName || matchedTrace?.pipelineName || inferPipelineName(source) || null; + const level = resolveTelemetryLevel(source, Boolean(matchedTrace), Boolean(generation), Boolean(tool)); + + return { + schema: 'bitcode.reading.pipeline.telemetry.projection', + pipelineName, + level, + phaseId: source.explicitPhaseId || matchedTrace?.phaseId || null, + agentId: source.explicitAgentId || matchedTrace?.agentId || null, + ptrrStepId: source.explicitPtrrStepId || matchedTrace?.ptrrStepId || null, + ptrrStepName: matchedTrace?.ptrrStepName || stepNameFromId(source.explicitPtrrStepId), + thricifiedGenerationId: + source.explicitThricifiedGenerationId || + generation?.thricifiedGenerationId || + null, + thricifiedFailsafe: generation?.failsafe || failsafeFromId(source.explicitThricifiedGenerationId), + promptTemplateId: valueAsString(source.data?.promptTemplateId) || ptrrStep?.prompt?.templateId || null, + generationPromptIds: { + reasonPromptId: generation?.reasonPromptId || null, + judgePromptId: generation?.judgePromptId || null, + structuredOutputPromptId: generation?.structuredOutputPromptId || null, + }, + toolId: source.explicitToolId || tool?.toolId || null, + inputType: tool?.inputType || matchedTrace?.inputType || null, + outputType: tool?.outputType || matchedTrace?.outputType || null, + returnType: matchedTrace?.returnType || null, + outputSchema: matchedTrace?.outputType || tool?.outputType || matchedTrace?.returnType || null, + stores: matchedTrace?.stores || [], + telemetry: matchedTrace?.telemetry || [], + evidence: { + promptTemplatePresent: booleanFlag(source.data?.promptTemplatePresent) || Boolean(source.data?.promptTemplate), + interpolatedPromptPresent: + booleanFlag(source.data?.interpolatedPromptPresent) || + Boolean(source.data?.interpolatedPrompt || source.data?.messages), + reasoningPresent: booleanFlag(source.data?.reasoningPresent) || Boolean(source.data?.reasoning), + judgmentPresent: booleanFlag(source.data?.judgmentPresent) || Boolean(source.data?.judgment), + rawModelResponsePresent: + booleanFlag(source.data?.rawModelResponsePresent) || + Boolean(source.data?.rawResponse || source.data?.content), + parsedTypedOutputPresent: + booleanFlag(source.data?.parsedTypedOutputPresent) || + booleanFlag(source.data?.parsedOutputPresent) || + Boolean(source.data?.parsedTypedOutput || source.data?.parsed), + toolInputPresent: booleanFlag(source.data?.toolInputPresent) || Boolean(source.data?.input), + toolOutputPresent: booleanFlag(source.data?.toolOutputPresent) || Boolean(source.data?.output), + toolErrorPresent: booleanFlag(source.data?.toolErrorPresent) || Boolean(source.data?.error), + }, + matched: Boolean(pipelineName || matchedTrace || generation || tool), + }; +} + +export function summarizeReadingPipelineObservabilityCoverage( + events: unknown[], +): ReadingPipelineObservabilityCoverage { + const projections = events.map((event) => { + const record = asRecord(event); + return asRecord(record?.readingPipelineTelemetry) || resolveReadingPipelineTelemetryProjection(event); + }); + const levelCounts = Object.fromEntries( + READING_PIPELINE_TELEMETRY_LEVELS.map((level) => [level, 0]), + ) as Record; + const pipelineNames = new Set(); + + for (const projection of projections) { + const level = projection.level as ReadingPipelineTelemetryLevel; + if (READING_PIPELINE_TELEMETRY_LEVELS.includes(level)) { + levelCounts[level] += 1; + } + if (isReadingPipelineName(projection.pipelineName)) { + pipelineNames.add(projection.pipelineName); + } + } + + const missingRequiredLevels = READING_PIPELINE_TELEMETRY_LEVELS.filter( + (level) => levelCounts[level] === 0, + ); + + return { + schema: 'bitcode.reading.pipeline.observability.coverage', + eventCount: events.length, + matchedEventCount: projections.filter((projection) => projection.matched).length, + pipelineNames: [...pipelineNames].sort(), + levelCounts, + missingRequiredLevels, + promptTelemetryReady: levelCounts.prompt > 0, + toolTelemetryReady: levelCounts.tool > 0, + rawOutputTelemetryReady: levelCounts['raw-output'] > 0, + parsedOutputTelemetryReady: levelCounts['parsed-output'] > 0, + }; +} + +function normalizeProjectionSource(eventLike: unknown): ProjectionSource { + const eventRecord = asRecord(eventLike); + const data = asRecord(eventRecord?.data) || eventRecord; + const telemetryEvent = asRecord(data?.telemetryEvent) || null; + const projection = asRecord(data?.readingPipelineTelemetry) || asRecord(eventRecord?.readingPipelineTelemetry); + const normalizedData = { + ...(telemetryEvent || {}), + ...(data || {}), + ...(projection || {}), + }; + const executionState = + asRecord(normalizedData.executionState) || + asRecord(telemetryEvent?.executionState) || + asRecord(data?.executionState); + const executionPath = asStringArray( + normalizedData.executionPath || + telemetryEvent?.executionPath || + data?.executionPath || + executionState?.path, + ); + const explicitToolId = + valueAsString(normalizedData.toolId) || + valueAsString(normalizedData.tool) || + valueAsString(normalizedData.toolName) || + null; + const explicitThricifiedGenerationId = + valueAsString(normalizedData.thricifiedGenerationId) || + valueAsString(normalizedData.generationId) || + valueAsString(executionState?.thricifiedGenerationId) || + null; + const textCandidates = [ + valueAsString(normalizedData.pipelineName), + valueAsString(normalizedData.phaseId), + valueAsString(normalizedData.agentId), + valueAsString(normalizedData.ptrrStepId), + valueAsString(normalizedData.ptrrStepName), + valueAsString(normalizedData.thricifiedGenerationId), + valueAsString(normalizedData.promptTemplateId), + valueAsString(normalizedData.namespace), + valueAsString(normalizedData.key), + valueAsString(normalizedData.stage), + valueAsString(normalizedData.streamEventType), + valueAsString(normalizedData.type), + valueAsString(normalizedData.message), + valueAsString(executionState?.phase), + valueAsString(executionState?.agent), + valueAsString(executionState?.step), + valueAsString(executionState?.generation), + explicitToolId, + explicitThricifiedGenerationId, + ...executionPath, + ].filter(Boolean) as string[]; + + return { + data: normalizedData, + executionState: executionState || null, + executionPath, + textCandidates, + explicitPipelineName: isReadingPipelineName(normalizedData.pipelineName) + ? normalizedData.pipelineName + : inferPipelineName({ textCandidates } as ProjectionSource), + explicitPhaseId: valueAsString(normalizedData.phaseId) || valueAsString(executionState?.phaseId) || null, + explicitAgentId: valueAsString(normalizedData.agentId) || valueAsString(executionState?.agentId) || null, + explicitPtrrStepId: + valueAsString(normalizedData.ptrrStepId) || + valueAsString(executionState?.ptrrStepId) || + null, + explicitThricifiedGenerationId, + explicitToolId, + }; +} + +function findMatchingTrace(source: ProjectionSource): IndexedTrace | null { + if (source.explicitPtrrStepId) { + const directStep = TRACE_INDEX.find((trace) => trace.ptrrStepId === source.explicitPtrrStepId); + if (directStep) return directStep; + } + if (source.explicitAgentId) { + const directAgent = TRACE_INDEX.find((trace) => trace.agentId === source.explicitAgentId); + if (directAgent) return directAgent; + } + if (source.explicitPhaseId) { + const directPhase = TRACE_INDEX.find((trace) => trace.phaseId === source.explicitPhaseId); + if (directPhase) return directPhase; + } + + if (source.explicitToolId) { + const byTool = TRACE_INDEX.find((trace) => trace.toolIds.includes(source.explicitToolId as string)); + if (byTool) return byTool; + } + + const candidateText = normalizeText(source.textCandidates.join(' ')); + const scopedTraces = source.explicitPipelineName + ? TRACE_INDEX.filter((trace) => trace.pipelineName === source.explicitPipelineName) + : TRACE_INDEX; + const byGeneration = source.explicitThricifiedGenerationId + ? scopedTraces.find((trace) => trace.thricifiedGenerationIds.includes(source.explicitThricifiedGenerationId as string)) + : null; + if (byGeneration) return byGeneration; + + return ( + scopedTraces.find((trace) => { + const phaseMatch = + candidateText.includes(normalizeText(trace.phaseId)) || + candidateText.includes(normalizeText(trace.phaseKey)); + const agentMatch = + candidateText.includes(normalizeText(trace.agentId)) || + candidateText.includes(normalizeText(trace.agentKey)) || + candidateText.includes(normalizeText(trace.returnType)); + const stepMatch = + candidateText.includes(normalizeText(trace.ptrrStepId)) || + candidateText.includes(normalizeText(trace.ptrrStepName)); + return phaseMatch && (agentMatch || stepMatch); + }) || + scopedTraces.find((trace) => candidateText.includes(normalizeText(trace.phaseId))) || + null + ); +} + +function findMatchingThricifiedGeneration( + source: ProjectionSource, + trace: IndexedTrace | null, +): IndexedTrace['thricifiedGenerations'][number] | null { + if (!trace) return null; + if (source.explicitThricifiedGenerationId) { + const direct = trace.thricifiedGenerations.find( + (generation) => generation.thricifiedGenerationId === source.explicitThricifiedGenerationId, + ); + if (direct) return direct; + } + const candidateText = normalizeText(source.textCandidates.join(' ')); + return ( + trace.thricifiedGenerations.find((generation) => + candidateText.includes(normalizeText(generation.thricifiedGenerationId)) || + candidateText.includes(normalizeText(generation.failsafe)), + ) || null + ); +} + +function findMatchingTool( + source: ProjectionSource, + trace: IndexedTrace | null, +): ReadingPipelineToolContract | null { + if (!trace) return null; + if (source.explicitToolId) { + return trace.ptrrStep?.tools.find((tool) => tool.toolId === source.explicitToolId) || null; + } + const candidateText = normalizeText(source.textCandidates.join(' ')); + return trace.ptrrStep?.tools.find((tool) => candidateText.includes(normalizeText(tool.toolId))) || null; +} + +function resolveTelemetryLevel( + source: ProjectionSource, + hasTrace: boolean, + hasGeneration: boolean, + hasTool: boolean, +): ReadingPipelineTelemetryLevel { + const data = source.data || {}; + const namespace = String(data.namespace || '').toLowerCase(); + const key = String(data.key || '').toLowerCase(); + const streamEventType = String(data.streamEventType || data.type || '').toLowerCase(); + if ( + booleanFlag(data.parsedTypedOutputPresent) || + booleanFlag(data.parsedOutputPresent) || + key.includes('parsed') + ) { + return 'parsed-output'; + } + if (booleanFlag(data.rawModelResponsePresent) || Boolean(data.rawResponse || data.content)) { + return 'raw-output'; + } + if ( + booleanFlag(data.promptTemplatePresent) || + booleanFlag(data.interpolatedPromptPresent) || + Boolean(data.promptTemplate || data.interpolatedPrompt || data.messages) || + key.includes('prompt') + ) { + return 'prompt'; + } + if (hasTool || streamEventType.includes('tool') || namespace.includes('tool')) return 'tool'; + if (hasGeneration || namespace === 'llm' || streamEventType.includes('generation')) return 'thricified-generation'; + if (source.explicitPtrrStepId) return 'ptrr-step'; + if (source.explicitAgentId) return 'ptrr-agent'; + if (source.explicitPhaseId) return 'phase'; + if (hasTrace) return 'ptrr-step'; + return 'execution'; +} + +function inferPipelineName(source: ProjectionSource): ReadingPipelineName | null { + const text = source.textCandidates.map(normalizeText).join(' '); + for (const pipelineName of READING_PIPELINE_NAMES) { + if (text.includes(normalizeText(pipelineName))) return pipelineName; + } + return null; +} + +function stepNameFromId(value: unknown): ReadingPipelinePtrrStepName | null { + const text = String(value || '').split('.').pop() || ''; + return ['plan', 'try', 'refine', 'retry'].includes(text) + ? (text as ReadingPipelinePtrrStepName) + : null; +} + +function failsafeFromId(value: unknown): ReadingPipelineThricifiedFailsafe | null { + const text = String(value || ''); + if (text.includes('prepare-concise-context')) return 'prepare-concise-context'; + if (text.includes('chunk-then-sum')) return 'chunk-then-sum'; + if (text.includes('stitch-until-complete')) return 'stitch-until-complete'; + return null; +} + +function isReadingPipelineName(value: unknown): value is ReadingPipelineName { + return value === READ_NEED_COMPREHENSION_SYNTHESIS || value === READ_FITS_FINDING_SYNTHESIS; +} + +function asRecord(value: unknown): Record | null { + return value && typeof value === 'object' && !Array.isArray(value) + ? (value as Record) + : null; +} + +function valueAsString(value: unknown): string | null { + return typeof value === 'string' && value.trim() ? value : null; +} + +function asStringArray(value: unknown): string[] { + return Array.isArray(value) + ? value.map((entry) => String(entry)).filter(Boolean) + : []; +} + +function booleanFlag(value: unknown): boolean { + return value === true; +} + +function normalizeText(value: unknown): string { + return String(value || '').toLowerCase().replace(/[^a-z0-9]+/g, ''); +} diff --git a/scripts/check-v29-gate4-reading-pipeline-observability.mjs b/scripts/check-v29-gate4-reading-pipeline-observability.mjs new file mode 100644 index 000000000..48a9624f0 --- /dev/null +++ b/scripts/check-v29-gate4-reading-pipeline-observability.mjs @@ -0,0 +1,233 @@ +#!/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-v29-gate4-reading-pipeline-observability.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 4 Reading pipeline observability closure.', + ].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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 Gate 4 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-4-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 4 work must occur on version/v29 or v29/gate-4-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'packages/pipelines/asset-pack/src/reading-pipeline-contract.ts', + 'packages/pipelines/asset-pack/src/reading-pipeline-observability.ts', + 'packages/pipelines/asset-pack/src/__tests__/reading-pipeline-observability.test.ts', + 'packages/pipeline-hosts/src/asset-pack-harness.ts', + 'packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts', + 'uapi/app/terminal/terminal-pipeline-harness-client.ts', + 'uapi/components/base/bitcode/execution/BitcodeExecutionStreamPanel.tsx', + 'uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx', + 'uapi/components/base/bitcode/execution/pipeline-execution-log.tsx', + 'uapi/tests/terminalPipelineHarnessClient.test.ts', + 'uapi/tests/pipelineExecutionLogHeader.test.tsx', + 'uapi/app/terminal/README.md', + 'uapi/components/base/bitcode/execution/README.md', + 'package.json', + '.github/workflows/bitcode-gate-quality.yml', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 4 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const observability = read(root, 'packages/pipelines/asset-pack/src/reading-pipeline-observability.ts'); + const observabilityTest = read(root, 'packages/pipelines/asset-pack/src/__tests__/reading-pipeline-observability.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 terminalClient = read(root, 'uapi/app/terminal/terminal-pipeline-harness-client.ts'); + const header = read(root, 'uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx'); + const log = read(root, 'uapi/components/base/bitcode/execution/pipeline-execution-log.tsx'); + const terminalTest = read(root, 'uapi/tests/terminalPipelineHarnessClient.test.ts'); + const headerTest = read(root, 'uapi/tests/pipelineExecutionLogHeader.test.tsx'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const executionReadme = read(root, 'uapi/components/base/bitcode/execution/README.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + assertCheck(failures, spec.includes('V29 Reading pipeline observability canon'), 'V29 SPEC must define Reading pipeline observability canon.'); + assertCheck(failures, delta.includes('ReadingPipelineTelemetryProjection'), 'V29 DELTA must name Gate 4 telemetry projection acceptance.'); + assertCheck(failures, notes.includes('Gate 4 working notes'), 'V29 NOTES must carry Gate 4 working notes.'); + assertCheck(failures, parity.includes('## Gate 4 Parity'), 'V29 PARITY must include Gate 4 parity.'); + assertCheck(failures, parity.includes('Gate 4 completion condition'), 'V29 PARITY must include Gate 4 completion condition.'); + + for (const symbol of [ + 'READING_PIPELINE_TELEMETRY_LEVELS', + 'buildReadingPipelineObservabilityInventory', + 'resolveReadingPipelineTelemetryProjection', + 'summarizeReadingPipelineObservabilityCoverage', + 'ReadingPipelineTelemetryProjection', + 'thricifiedGenerationId', + 'promptTemplateId', + 'outputSchema', + 'raw-output', + 'parsed-output', + ]) { + assertCheck(failures, observability.includes(symbol), `Reading observability primitive is missing ${symbol}.`); + } + + assertCheck( + failures, + observabilityTest.includes('thricifiedGenerationPrompts: 432') && + observabilityTest.includes('ReadFitsFindingSynthesis.tool.vector-depository-search') && + observabilityTest.includes('missingRequiredLevels') && + observabilityTest.includes('parsedOutputTelemetryReady'), + 'Reading observability tests must cover inventory, tools, coverage, and parsed-output readiness.', + ); + + assertCheck( + failures, + harness.includes('readingPipelineTelemetry') && + harness.includes('readingPipelineObservabilityInventory') && + harness.includes('readingPipelineObservabilityCoverage') && + harness.includes('resolveReadingPipelineTelemetryProjection') && + harness.includes('summarizeReadingPipelineObservabilityCoverage'), + 'Sandbox harness must stamp stream events with Reading observability projection and export coverage.', + ); + assertCheck( + failures, + harnessTest.includes('readingPipelineTelemetry') && + harnessTest.includes('ptrrStepId') && + harnessTest.includes('thricifiedGenerationId') && + harnessTest.includes('readingPipelineObservabilityCoverage'), + 'Pipeline-host tests must assert Gate 4 harness telemetry fields.', + ); + + assertCheck( + failures, + terminalClient.includes('readingPipelineTelemetry') && + terminalClient.includes('ptrrStepId') && + terminalClient.includes('thricifiedGenerationId') && + terminalClient.includes('promptTemplateId') && + terminalClient.includes('outputSchema') && + terminalClient.includes('inferenceAudit'), + 'Terminal harness client must adapt Reading telemetry projection into execution stream state.', + ); + assertCheck( + failures, + header.includes('pipeline?: string') && + header.includes('ptrrStepId?: string') && + header.includes('outputSchema?: string') && + header.includes('headerMetadataRows'), + 'Execution log header must render contract-aware Reading telemetry identifiers.', + ); + assertCheck( + failures, + log.includes('pipeline?: string') && + log.includes('phaseId?: string') && + log.includes('ptrrStepId?: string') && + log.includes('promptTemplateId?: string') && + log.includes('outputSchema?: string'), + 'Execution log rows must preserve contract-aware Reading telemetry identifiers.', + ); + assertCheck( + failures, + terminalTest.includes('ReadFitsFindingSynthesis.implementation.asset-pack.try') && + terminalTest.includes('ThricifiedGeneration') && + terminalTest.includes('schema AssetPackSynthesisOutput') && + headerTest.includes('ReadFitsFindingSynthesis.discovery') && + headerTest.includes('DepositoryFitsResult'), + 'UAPI tests must cover Terminal summary and header rendering for Reading telemetry.', + ); + assertCheck( + failures, + terminalReadme.includes('live Reading harness stream') && + executionReadme.includes('Reading Pipeline Streams'), + 'Terminal and shared execution docs must describe Reading pipeline streams.', + ); + assertCheck( + failures, + packageJson.includes('"check:v29-gate4"') && + gateWorkflow.includes('check-v29-gate4-reading-pipeline-observability.mjs') && + gateWorkflow.includes('reading-pipeline-observability.test.ts'), + 'Package scripts and gate-quality workflow must invoke Gate 4 checker and focused tests.', + ); + + if (failures.length) { + process.stderr.write('V29 Gate 4 check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V29 Gate 4 Reading pipeline observability check passed.\n'); +} + +main(); diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index d5ca92118..9fee4a1ae 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -125,6 +125,13 @@ secrets or protected AssetPack source. It should show quote root, wallet session payer wallet, PSBT handoff, txid, state, confirmations, blockers, and server custody posture as ordinary rows before the operator opens raw ledger payloads. +The live Reading harness stream projects `ReadNeedComprehensionSynthesis` and +`ReadFitsFindingSynthesis` telemetry into the shared execution panel. Collapsed +rows should identify the pipeline, phase, PTRR step, ThricifiedGeneration, +prompt/tool/schema posture, and result shape. Expanded metadata remains the +place for prompt templates, interpolated prompts, raw model responses, parsed +typed outputs, tool inputs/outputs, and harness evidence coverage. + ## Related shared systems - [../../components/base/bitcode/execution/README.md](../../components/base/bitcode/execution/README.md) diff --git a/uapi/app/terminal/terminal-pipeline-harness-client.ts b/uapi/app/terminal/terminal-pipeline-harness-client.ts index 8348524b6..ed97fbee8 100644 --- a/uapi/app/terminal/terminal-pipeline-harness-client.ts +++ b/uapi/app/terminal/terminal-pipeline-harness-client.ts @@ -274,6 +274,13 @@ function shortIdentifier(value: unknown): string | null { return text.length > 16 ? `${text.slice(0, 12)}...` : text; } +function contractIdentifier(value: unknown, segments = 3): string | null { + const text = stringIdentifier(value); + if (!text) return null; + const parts = text.split('.').filter(Boolean); + return parts.length > segments ? parts.slice(-segments).join('.') : text; +} + function stringIdentifier(value: unknown): string | null { const text = typeof value === 'string' ? value.trim() : ''; return text || null; @@ -345,6 +352,9 @@ function buildHarnessExecutionState(event: TerminalReadFitsFindingSynthesisHarne const data = recordValue(event.data); const telemetryEvent = recordValue(data?.telemetryEvent); const telemetryExecutionState = recordValue(telemetryEvent?.executionState); + const readingTelemetry = + recordValue(telemetryEvent?.readingPipelineTelemetry) || + recordValue(data?.readingPipelineTelemetry); const type = data?.type ? String(data.type) : event.event; const stage = telemetryEvent?.stage || telemetryExecutionState?.phase || type; const streamEventType = telemetryEvent?.streamEventType || telemetryEvent?.type || type; @@ -361,20 +371,34 @@ function buildHarnessExecutionState(event: TerminalReadFitsFindingSynthesisHarne data?.label || 'asset-pack-pipeline-harness', step: + readingTelemetry?.ptrrStepName || telemetryExecutionState?.step || telemetryEvent?.step || streamEventType || type, - failsafe: telemetryExecutionState?.failsafe || telemetryEvent?.failsafe, + pipeline: readingTelemetry?.pipelineName || telemetryEvent?.pipelineName, + phaseId: readingTelemetry?.phaseId || telemetryEvent?.phaseId, + agentId: readingTelemetry?.agentId || telemetryEvent?.agentId, + ptrrStepId: readingTelemetry?.ptrrStepId || telemetryEvent?.ptrrStepId, + ptrrStepName: readingTelemetry?.ptrrStepName || telemetryEvent?.ptrrStepName, + failsafe: + readingTelemetry?.thricifiedFailsafe || + telemetryExecutionState?.failsafe || + telemetryEvent?.failsafe, generation: + readingTelemetry?.thricifiedGenerationId || telemetryExecutionState?.generation || telemetryEvent?.generation || (classifyHarnessLogType(event) === 'generation' ? [namespace, key].filter(Boolean).join('.') || 'model' : undefined), tool: + readingTelemetry?.toolId || telemetryExecutionState?.tool || telemetryEvent?.tool || telemetryEvent?.toolName || (classifyHarnessLogType(event) === 'tool-use' ? type : undefined), + promptTemplateId: readingTelemetry?.promptTemplateId || telemetryEvent?.promptTemplateId, + outputSchema: readingTelemetry?.outputSchema || telemetryEvent?.outputSchema, + returnType: readingTelemetry?.returnType || telemetryEvent?.returnType, }; } @@ -423,6 +447,9 @@ export function buildTerminalReadFitsFindingSynthesisHarnessStreamSnapshot( const timestamp = harnessEventTimestamp(event); const data = recordValue(event.data); const telemetryEvent = recordValue(data?.telemetryEvent); + const readingPipelineTelemetry = + recordValue(telemetryEvent?.readingPipelineTelemetry) || + recordValue(data?.readingPipelineTelemetry); const evidence = recordValue(data?.evidence); runId = @@ -448,6 +475,7 @@ export function buildTerminalReadFitsFindingSynthesisHarnessStreamSnapshot( harnessEvent: event.event, harnessPayload: event.data, telemetryEvent, + readingPipelineTelemetry, inferenceAudit: telemetryEvent?.inferenceAudit || null, }, }, @@ -472,6 +500,9 @@ function summarizeTelemetryArtifactEvent(data: Record): string } const executionState = recordValue(telemetryEvent.executionState); + const readingTelemetry = + recordValue(telemetryEvent.readingPipelineTelemetry) || + recordValue(data.readingPipelineTelemetry); const streamType = String( telemetryEvent.streamEventType || telemetryEvent.type || @@ -492,7 +523,11 @@ function summarizeTelemetryArtifactEvent(data: Record): string const dataKeys = stringList(telemetryEvent.dataKeys, 4); const inspectable = recordValue(telemetryEvent.inspectable); const inspectableKeys = stringList(inspectable?.keys, 4); - const tool = telemetryEvent.tool ? String(telemetryEvent.tool) : null; + const tool = readingTelemetry?.toolId + ? String(readingTelemetry.toolId) + : telemetryEvent.tool + ? String(telemetryEvent.tool) + : null; const toolState = typeof telemetryEvent.toolOk === 'boolean' ? telemetryEvent.toolOk ? 'ok' @@ -511,6 +546,14 @@ function summarizeTelemetryArtifactEvent(data: Record): string const judgment = telemetryEvent.judgmentPresent === true ? 'judgment present' : null; const rawResponse = telemetryEvent.rawModelResponsePresent === true ? 'raw response present' : null; const parsedTypedOutput = telemetryEvent.parsedTypedOutputPresent === true ? 'parsed typed output present' : null; + const pipelineName = readingTelemetry?.pipelineName || telemetryEvent.pipelineName; + const phaseId = readingTelemetry?.phaseId || telemetryEvent.phaseId; + const ptrrStepId = readingTelemetry?.ptrrStepId || telemetryEvent.ptrrStepId; + const thricifiedGenerationId = + readingTelemetry?.thricifiedGenerationId || telemetryEvent.thricifiedGenerationId; + const promptTemplateId = readingTelemetry?.promptTemplateId || telemetryEvent.promptTemplateId; + const outputSchema = readingTelemetry?.outputSchema || telemetryEvent.outputSchema; + const returnType = readingTelemetry?.returnType || telemetryEvent.returnType; const toolDetails = [ telemetryEvent.toolInputPresent === true ? 'input' : null, telemetryEvent.toolOutputPresent === true ? 'output' : null, @@ -522,6 +565,14 @@ function summarizeTelemetryArtifactEvent(data: Record): string namespace || key ? [namespace, key].filter(Boolean).join('.') : null, executionPath ? `path ${executionPath}` : null, runId ? `run ${runId}` : null, + pipelineName ? `pipeline ${String(pipelineName)}` : null, + phaseId ? `phase ${contractIdentifier(phaseId, 2)}` : null, + ptrrStepId ? `PTRR ${contractIdentifier(ptrrStepId, 3)}` : null, + thricifiedGenerationId + ? `ThricifiedGeneration ${contractIdentifier(thricifiedGenerationId, 4)}` + : null, + promptTemplateId ? `prompt ${contractIdentifier(promptTemplateId, 2)}` : null, + outputSchema ? `schema ${String(outputSchema)}` : returnType ? `return ${String(returnType)}` : null, tool ? `tool ${tool}${toolState ? ` ${toolState}` : ''}${toolDetails ? ` ${toolDetails}` : ''}` : null, dataKeys.length ? `data ${dataKeys.join(', ')}` : null, inspectableKeys.length ? `inspectable ${inspectableKeys.join(', ')}` : null, diff --git a/uapi/components/base/bitcode/execution/README.md b/uapi/components/base/bitcode/execution/README.md index 0053d5f37..1e87f0433 100644 --- a/uapi/components/base/bitcode/execution/README.md +++ b/uapi/components/base/bitcode/execution/README.md @@ -32,6 +32,8 @@ The V26 second-gate rule for this layer is simple: - `bitcode-transaction-explainers.ts` - activity/log streams - `BitcodeExecutionStreamPanel.tsx` + - `pipeline-execution-log-header.tsx` + - `pipeline-execution-log.tsx` ## Design goals @@ -42,6 +44,17 @@ The V26 second-gate rule for this layer is simple: - no fallback to raw page-local `
` blocks for important JSON-bearing detail
 - markdown/documentation parity with the active activity-detail and payload carriers during second-gate closure
 
+## Reading Pipeline Streams
+
+The execution stream panel is the shared carrier for live Reading pipeline
+telemetry. Terminal passes contract-aware state for
+`ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis`, including
+pipeline, phase id, PTRR agent id, PTRR step id, ThricifiedGeneration id,
+prompt template id, tool id, output schema, and return type. Collapsed rows must
+remain readable without raw JSON; expanded rows may show the full metadata,
+including prompt templates, interpolated prompts, raw model responses, parsed
+typed outputs, and tool input/output posture.
+
 ## Used by
 
 - [../../../app/terminal/README.md](../../../app/terminal/README.md)
diff --git a/uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx b/uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx
index 76a4e5468..17fa18360 100644
--- a/uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx
+++ b/uapi/components/base/bitcode/execution/pipeline-execution-log-header.tsx
@@ -12,6 +12,15 @@ interface PipelineRunLogHeaderProps {
     failsafe?: FailsafeStep;
     generation?: GenerationStep;
     tool?: string | { name?: string };
+    pipeline?: string;
+    phaseId?: string;
+    agentId?: string;
+    ptrrStepId?: string;
+    ptrrStepName?: string;
+    thricifiedGenerationId?: string;
+    promptTemplateId?: string;
+    outputSchema?: string;
+    returnType?: string;
   };
   isStreamingComplete: boolean;
   generationCount: number;
@@ -40,16 +49,34 @@ export function PipelineExecutionLogHeader({
   const generation = executionState?.generation;
   const tool = executionState?.tool;
   const toolLabel = typeof tool === 'string' ? tool : tool?.name || '';
+  const pipelineLabel = executionState?.pipeline;
+  const ptrrStepLabel = executionState?.ptrrStepId || executionState?.ptrrStepName;
+  const schemaLabel = executionState?.outputSchema || executionState?.returnType;
 
   const formatMeta = (m?: FailsafeStep | string) => {
     const v = String(m || '');
     switch (v) {
       case 'prepare_concise_context': return 'Prepare Context';
+      case 'prepare-concise-context': return 'Prepare Context';
       case 'chunk_then_sum': return 'Chunk Then Sum';
+      case 'chunk-then-sum': return 'Chunk Then Sum';
       case 'stitch_until_complete': return 'Stitch Until Complete';
+      case 'stitch-until-complete': return 'Stitch Until Complete';
       default: return v || 'Meta NA';
     }
   };
+  const compactIdentifier = (value?: string, segments = 3) => {
+    const parts = String(value || '').split('.').filter(Boolean);
+    return parts.length > segments ? parts.slice(-segments).join('.') : parts.join('.') || '';
+  };
+  const headerMetadataRows = [
+    pipelineLabel ? { label: 'pipeline', value: pipelineLabel } : null,
+    executionState?.phaseId ? { label: 'phase id', value: compactIdentifier(executionState.phaseId, 2) } : null,
+    executionState?.agentId ? { label: 'PTRR agent', value: compactIdentifier(executionState.agentId, 3) } : null,
+    ptrrStepLabel ? { label: 'PTRR step', value: compactIdentifier(String(ptrrStepLabel), 3) } : null,
+    schemaLabel ? { label: 'schema', value: String(schemaLabel) } : null,
+    ...metadataRows,
+  ].filter((row): row is { label: string; value: string } => Boolean(row?.value));
 
   return (
     
@@ -79,6 +106,11 @@ export function PipelineExecutionLogHeader({ {agent || "Non Agent"} + {pipelineLabel && ( + + {pipelineLabel} + + )} {/* Show current step if available and different from agent name */} {step && step !== agent && ( @@ -127,9 +159,9 @@ export function PipelineExecutionLogHeader({
- {metadataRows.length ? ( + {headerMetadataRows.length ? (
- {metadataRows.map((row) => ( + {headerMetadataRows.map((row) => (
{ + const parts = String(value || '').split('.').filter(Boolean); + return parts.length > segments ? parts.slice(-segments).join('.') : parts.join('.') || String(value || ''); + }; if (compact) { // Build tag arrays first @@ -1095,18 +1172,42 @@ function renderLogLine( {logLine.phase}
)} + {logLine.pipeline && ( +
+ Pipeline: + {logLine.pipeline} +
+ )} + {logLine.phaseId && ( +
+ Phase ID: + {formatContractId(logLine.phaseId, 2)} +
+ )} {logLine.agent && (
Agent: {logLine.agent}
)} + {logLine.agentId && ( +
+ PTRR Agent: + {formatContractId(logLine.agentId, 3)} +
+ )} {logLine.step && (
Step: {logLine.step}
)} + {logLine.ptrrStepId && ( +
+ PTRR Step: + {formatContractId(logLine.ptrrStepId, 3)} +
+ )} {logLine.failsafe && (
Failsafe: @@ -1119,6 +1220,18 @@ function renderLogLine( {formatMeta(logLine.generation)}
)} + {logLine.promptTemplateId && ( +
+ Prompt: + {formatContractId(logLine.promptTemplateId, 2)} +
+ )} + {(logLine.outputSchema || logLine.returnType) && ( +
+ Schema: + {logLine.outputSchema || logLine.returnType} +
+ )} {logLine.tool && (
Tool: diff --git a/uapi/tests/pipelineExecutionLogHeader.test.tsx b/uapi/tests/pipelineExecutionLogHeader.test.tsx index 788f92b41..a44c2957f 100644 --- a/uapi/tests/pipelineExecutionLogHeader.test.tsx +++ b/uapi/tests/pipelineExecutionLogHeader.test.tsx @@ -14,6 +14,12 @@ describe('PipelineExecutionLogHeader', () => { step: 'try' as any, generation: 'structured-output' as any, tool: 'bitcode.asset-pack.verification', + pipeline: 'ReadFitsFindingSynthesis', + phaseId: 'ReadFitsFindingSynthesis.discovery', + agentId: 'ReadFitsFindingSynthesis.discovery.finding-fits', + ptrrStepId: 'ReadFitsFindingSynthesis.discovery.finding-fits.try', + ptrrStepName: 'try', + outputSchema: 'DepositoryFitsResult', }} isStreamingComplete={false} generationCount={2} @@ -23,5 +29,9 @@ describe('PipelineExecutionLogHeader', () => { ); expect(screen.getByText('bitcode.asset-pack.verification')).toBeTruthy(); + expect(screen.getAllByText('ReadFitsFindingSynthesis').length).toBeGreaterThan(0); + expect(screen.getByText('ReadFitsFindingSynthesis.discovery')).toBeTruthy(); + expect(screen.getByText('discovery.finding-fits.try')).toBeTruthy(); + expect(screen.getByText('DepositoryFitsResult')).toBeTruthy(); }); }); diff --git a/uapi/tests/terminalPipelineHarnessClient.test.ts b/uapi/tests/terminalPipelineHarnessClient.test.ts index f0a62b00f..adabb0f88 100644 --- a/uapi/tests/terminalPipelineHarnessClient.test.ts +++ b/uapi/tests/terminalPipelineHarnessClient.test.ts @@ -298,6 +298,19 @@ describe('terminal pipeline harness client', () => { executionPath: ['asset_pack', 'synthesis', 'thricified-generation'], runId: '2bdcd936-a686-4a10-92e2-9c64cbef4f0e', dataKeys: ['parsed'], + readingPipelineTelemetry: { + pipelineName: 'ReadFitsFindingSynthesis', + level: 'parsed-output', + phaseId: 'ReadFitsFindingSynthesis.implementation', + agentId: 'ReadFitsFindingSynthesis.implementation.asset-pack', + ptrrStepId: 'ReadFitsFindingSynthesis.implementation.asset-pack.try', + ptrrStepName: 'try', + thricifiedGenerationId: + 'ReadFitsFindingSynthesis.thricified-generation.implementation.asset-pack.try.prepare-concise-context', + promptTemplateId: 'ReadFitsFindingSynthesis.prompt.asset-pack-synthesis', + outputSchema: 'AssetPackSynthesisOutput', + returnType: 'AssetPackSynthesisOutput', + }, parsedOutputPresent: true, promptTemplatePresent: true, interpolatedPromptPresent: true, @@ -317,6 +330,12 @@ describe('terminal pipeline harness client', () => { expect(summary).toContain('llm.parsedOutput'); expect(summary).toContain('path asset_pack > synthesis > thricified-generation'); expect(summary).toContain('run 2bdcd936-a68...'); + expect(summary).toContain('pipeline ReadFitsFindingSynthesis'); + expect(summary).toContain('phase ReadFitsFindingSynthesis.implementation'); + expect(summary).toContain('PTRR implementation.asset-pack.try'); + expect(summary).toContain('ThricifiedGeneration implementation.asset-pack.try.prepare-concise-context'); + expect(summary).toContain('prompt prompt.asset-pack-synthesis'); + expect(summary).toContain('schema AssetPackSynthesisOutput'); expect(summary).toContain('inspectable resultState, assetPack'); expect(summary).toContain('prompt template present'); expect(summary).toContain('interpolated prompt present'); @@ -381,6 +400,18 @@ describe('terminal pipeline harness client', () => { agent: 'asset-pack-synthesis-agent', step: 'structured_output', }, + readingPipelineTelemetry: { + pipelineName: 'ReadFitsFindingSynthesis', + phaseId: 'ReadFitsFindingSynthesis.implementation', + agentId: 'ReadFitsFindingSynthesis.implementation.asset-pack', + ptrrStepId: 'ReadFitsFindingSynthesis.implementation.asset-pack.try', + ptrrStepName: 'try', + thricifiedGenerationId: + 'ReadFitsFindingSynthesis.thricified-generation.implementation.asset-pack.try.prepare-concise-context', + promptTemplateId: 'ReadFitsFindingSynthesis.prompt.asset-pack-synthesis', + outputSchema: 'AssetPackSynthesisOutput', + returnType: 'AssetPackSynthesisOutput', + }, inputMessageCount: 2, outputContentLength: 1200, promptTemplatePresent: true, @@ -408,7 +439,17 @@ describe('terminal pipeline harness client', () => { stage: 'setup', namespace: 'tools', key: 'result', - tool: 'bitcode.asset-pack.verification', + tool: 'ReadFitsFindingSynthesis.tool.verification-evidence', + readingPipelineTelemetry: { + pipelineName: 'ReadFitsFindingSynthesis', + phaseId: 'ReadFitsFindingSynthesis.validate', + agentId: 'ReadFitsFindingSynthesis.validate.fit-quality', + ptrrStepId: 'ReadFitsFindingSynthesis.validate.fit-quality.try', + ptrrStepName: 'try', + toolId: 'ReadFitsFindingSynthesis.tool.verification-evidence', + outputSchema: 'AssetPackVerificationEvidenceResult', + returnType: 'ReadyToFinishOutput', + }, executionState: { phase: 'setup', agent: 'bitcode-read-risk-admission', @@ -445,7 +486,14 @@ describe('terminal pipeline harness client', () => { executionState: { phase: 'Implementation', agent: 'asset-pack-synthesis-agent', - step: 'structured_output', + step: 'try', + pipeline: 'ReadFitsFindingSynthesis', + phaseId: 'ReadFitsFindingSynthesis.implementation', + agentId: 'ReadFitsFindingSynthesis.implementation.asset-pack', + ptrrStepId: 'ReadFitsFindingSynthesis.implementation.asset-pack.try', + ptrrStepName: 'try', + promptTemplateId: 'ReadFitsFindingSynthesis.prompt.asset-pack-synthesis', + outputSchema: 'AssetPackSynthesisOutput', }, }, }); @@ -465,7 +513,13 @@ describe('terminal pipeline harness client', () => { phase: 'Setup', agent: 'bitcode-read-risk-admission', step: 'try', - tool: 'bitcode.asset-pack.verification', + tool: 'ReadFitsFindingSynthesis.tool.verification-evidence', + pipeline: 'ReadFitsFindingSynthesis', + phaseId: 'ReadFitsFindingSynthesis.validate', + agentId: 'ReadFitsFindingSynthesis.validate.fit-quality', + ptrrStepId: 'ReadFitsFindingSynthesis.validate.fit-quality.try', + ptrrStepName: 'try', + outputSchema: 'AssetPackVerificationEvidenceResult', }, }, }); From ff2a3b42b5f93520a07448af3631f67c72a7c9b2 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Wed, 20 May 2026 15:38:43 -0300 Subject: [PATCH 05/18] V29 Gate 5: Guard AssetPack disclosure rights (#24) Define package-owned AssetPackDisclosureReview, leakage checks, and source-safe preview persistence for postprocess and sandbox harness evidence. Render disclosure review in Terminal, extend BTD access boundary coverage, document Gate 5 parity, and enforce version/gate-prefixed PR titles in gate CI. --- .github/pull_request_template.md | 11 + .github/workflows/bitcode-gate-quality.yml | 20 ++ AGENTS.md | 1 + BITCODE_SPEC_V29.md | 21 ++ BITCODE_SPEC_V29_DELTA.md | 10 + BITCODE_SPEC_V29_NOTES.md | 17 + BITCODE_SPEC_V29_PARITY_MATRIX.md | 30 +- README.md | 2 + package.json | 1 + packages/btd/__tests__/btd.test.ts | 57 ++++ .../src/__tests__/asset-pack-harness.test.ts | 4 + .../pipeline-hosts/src/asset-pack-harness.ts | 15 + packages/pipelines/asset-pack/package.json | 1 + .../__tests__/asset-pack-disclosure.test.ts | 134 ++++++++ .../src/__tests__/postprocess.test.ts | 12 + .../asset-pack/src/asset-pack-disclosure.ts | 293 ++++++++++++++++++ packages/pipelines/asset-pack/src/index.ts | 1 + .../pipelines/asset-pack/src/postprocess.ts | 31 ++ .../asset-pack/src/types/PipelineSchemas.ts | 3 + ...-v29-gate5-assetpack-disclosure-rights.mjs | 228 ++++++++++++++ .../terminal/TerminalDepositReadWorkbench.tsx | 85 +++++ .../terminal-pipeline-harness-client.ts | 13 + .../terminalPipelineHarnessClient.test.ts | 11 + 23 files changed, 999 insertions(+), 2 deletions(-) create mode 100644 .github/pull_request_template.md create mode 100644 packages/pipelines/asset-pack/src/__tests__/asset-pack-disclosure.test.ts create mode 100644 packages/pipelines/asset-pack/src/asset-pack-disclosure.ts create mode 100644 scripts/check-v29-gate5-assetpack-disclosure-rights.mjs diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..b1cc48f46 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,11 @@ +## 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`. + +## Closure + +- Gate: +- Acceptance criteria closed: +- Tests/checks run: +- Accepted boundaries: diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 18d874055..a7628dbc8 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -38,6 +38,23 @@ jobs: - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Validate gate pull request title + if: github.event_name == 'pull_request' + env: + PR_BASE_REF: ${{ github.base_ref }} + PR_HEAD_REF: ${{ github.head_ref }} + PR_TITLE: ${{ github.event.pull_request.title }} + run: | + if [[ "$PR_BASE_REF" == version/* && "$PR_HEAD_REF" =~ ^v([0-9]+)/gate-([0-9]+)- ]]; then + expected_version="V${BASH_REMATCH[1]}" + expected_gate="${BASH_REMATCH[2]}" + if [[ ! "$PR_TITLE" =~ ^${expected_version}[[:space:]]+Gate[[:space:]]+${expected_gate}:[[:space:]].+ ]]; then + echo "Gate pull request titles must begin with: ${expected_version} Gate ${expected_gate}:" + echo "Observed: ${PR_TITLE}" + exit 1 + fi + fi + - name: Validate draft canon posture run: | test "$(cat BITCODE_SPEC.txt)" = "V28" @@ -49,6 +66,7 @@ jobs: node scripts/check-v29-gate2-terminal-transaction-read-models.mjs --skip-branch-check node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs --skip-branch-check node scripts/check-v29-gate4-reading-pipeline-observability.mjs --skip-branch-check + node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs --skip-branch-check - name: Validate source casing and imports run: | @@ -65,8 +83,10 @@ jobs: run: | pnpm --filter @bitcode/btd test pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btc-fee-operation.test.ts + pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btd.test.ts pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --passWithNoTests --forceExit pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath src/__tests__/reading-pipeline-observability.test.ts src/__tests__/reading-pipeline-contract.test.ts --runInBand + pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath src/__tests__/asset-pack-disclosure.test.ts src/__tests__/postprocess.test.ts src/__tests__/read-need.test.ts --runInBand pnpm --filter @bitcode/pipeline-hosts exec jest --config jest.config.cjs --passWithNoTests --forceExit - name: Test staged Reading route and Terminal harness contracts diff --git a/AGENTS.md b/AGENTS.md index 51603f22d..3354e450e 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -5,6 +5,7 @@ - Do not consider any legacy code. All legacy code is located under `_legacy/`. - Highest caliber software engineering crafstmanship (maintainibility, abstractions, architectures, naming, patterns, comments, documentation, structures, algorithmic and data flow designs, UI/UX, etc.), correctness (specification and implementation precision, reliability, completeness, boundaried, scoped, encapsulated, etc.), and auditable (totalistic proofs systems from static code, build time, runtime, etc. etc. as is Bitcode, tests from unit, integration, E2E, linting and building, etc.). - Do not push work directly to `main`. Create a version base branch for each draft target, such as `version/v28`, then create scoped gate branches from that version branch. Gate branches must be prefixed with the gate number, such as `v28/gate-3-read-fit-workflow` or `v28/gate-8-promotion-proof`. Pull-request each closed gate back into the version branch. Pull-request the version branch into `main` only when all gates are closed and the version is formally promoted as canon. The default branch is protected by the `Bitcode Core Contributions` ruleset and requires pull requests plus verified signatures. +- Gate pull request titles must begin with the uppercase version and gate prefix, followed by a concise topical title, for example `V29 Gate 5: AssetPack Disclosure Rights And Preview Depth`. Version-promotion pull requests must begin with the uppercase version and name canonical promotion. - Once implementation starts on a gate branch, do not stop at partial progress unless blocked by missing external input or explicit user pause. A gate branch is ready to stop only when the gate's acceptance criteria are implemented, specified, tested, documented, committed, pushed, and pull-requested for closure into the version branch. - Treat gate and promotion workflow health as part of gate closure. Gate pull requests into version branches must be green through the maintained gate-quality checks, and repository-wide canon-quality checks must remain greenable during draft work. Version pull requests into `main` must pass the version promotion workflow, which performs promotion-grade validations and commits the standalone `BITCODE_SPEC.txt` pointer change only after those validations pass. - Keep CI greenable rather than ceremonial. Required application CI uses root pnpm workspace installation and maintained uapi lint/typecheck/build/Jest coverage. Heavy legacy scans such as full DB/browser E2E, Storybook build, super-linter, and advanced CodeQL are opt-in by repository variables until their backing catalogs and service assumptions are maintained for required branch protection. diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index a00440bd4..7d4fdbc2e 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -301,6 +301,27 @@ Failure to observe prompt, raw-output, parsed-output, or tool telemetry in a run - Current validating commands and parity basis: synthesis tests, source-leakage tests, route tests, PR delivery mocks/live checks, and V29 gate checks. - Current accepted boundaries: full mainnet value delivery remains approval-gated. +#### V29 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 `V29 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. diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index 1d65a7c81..f1ea2aa16 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -126,6 +126,16 @@ Closure acceptance: Gate 5 owns AssetPack range detail, owner-read/licensed-read/denied-state flows, source-safe preview, disclosure policy review, paid unlock state, and protected-source leakage tests. +Closure acceptance: + +- `@bitcode/pipeline-asset-pack` exposes `AssetPackDisclosureReview` as the first-class review object between source-safe preview and paid source unlock. +- The disclosure review binds preview id, AssetPack id, BTD read-right state, source visibility, reader action, policy fields, range projection, proof roots, fee quote root, and protected-source leakage review. +- Protected source leakage detection fails closed for source-bearing field names, patch markers, and source-code markers inside pre-settlement preview metadata. +- AssetPack postprocessing and the Vercel Sandbox harness store `assetPackDisclosureReview`, `asset-pack/preview.disclosureReview`, and `asset-pack/preview.disclosureReviewRoot` alongside source-safe preview evidence. +- BTD tests cover owner-read, licensed-read, and denied-state boundaries so paid unlock cannot blur ownership, license, and denial semantics. +- Terminal renders disclosure review as part of the source-safe preview surface with visibility, reader action, policy root, review root, visible/withheld counts, leakage state, and source unlock state before raw evidence. +- Gate-quality CI enforces focused disclosure tests and gate PR titles beginning with the uppercase version and gate prefix, such as `V29 Gate 5: AssetPack Disclosure Rights And Preview Depth`. + ### Gate 6: Settlement Reconciliation And Repair Gate 6 owns ledger/database/metaphysical separation, journal diffing, reconciliation repair actions, proof-root surfacing, settlement conservation drift handling, and delivery recovery. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index a73028b5f..6b608ac2c 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -134,6 +134,23 @@ Accepted Gate 4 posture: - Terminal's live harness stream shows pipeline, phase id, PTRR agent, PTRR step, ThricifiedGeneration, prompt, tool, output schema, raw output posture, and parsed typed output posture through the shared execution log components. - Gate 4 does not implement disclosure-depth unlock, settlement repair, organization authority, or full browser proof; later gates own those slices. +## Gate 5 working notes + +Gate 5 makes AssetPack disclosure a package-owned contract instead of a Terminal-only summary. +The Reading pipeline may synthesize the AssetPack and compute its measurements before payment, but protected source remains withheld until the BTD read-right state and settlement unlock prove that the reader owns or is licensed to read the AssetPack source. + +Accepted Gate 5 posture: + +- `AssetPackSourceSafePreview` remains the pre-payment preview envelope. +- `AssetPackDisclosureReview` binds source visibility, reader action, policy roots, range projection, fee quote root, and protected-source leakage review to that preview. +- Source visibility has distinct `withheld_before_settlement`, `available_after_settlement`, and `denied` states. +- Reader action has distinct `pay_to_unlock`, `read_as_owner`, `read_as_licensee`, and `blocked` states. +- Leakage review scans preview metadata for source-bearing field names, patch markers, and source-code markers and fails closed before the preview is shown. +- Postprocessing and the sandbox harness store disclosure review evidence next to source-safe preview evidence so database/ledger readback can explain paid unlock state without exposing protected source. +- Terminal renders disclosure review as the ordinary Reading preview surface and keeps expandable raw metadata behind the same source-safe boundary. +- Gate pull request titles must carry the uppercase version and gate prefix so gate closure can be audited from GitHub history. +- Gate 5 does not implement reconciliation repair, organization authority, full settlement UI depth, or browser proof; later V29 gates own those slices. + ## Later-version boundaries - V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index b2032c872..37d442f9f 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -52,7 +52,7 @@ No `_legacy/` source is active source truth. | Terminal transaction read models | Gate 2 | `uapi/app/terminal/terminal-transaction-read-model.ts`, `uapi/app/terminal/terminal-transaction-query.ts`, `TerminalTransactionWorkspace.tsx`, `TerminalTransactionDetailSurface.tsx`, UAPI tests, Gate 2 checker | drafted | Terminal transaction state is URL-addressable, recoverable, typed, low-detail by default, and expandable without raw JSON as the ordinary operator contract. | | Wallet signer/BTC operations | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, BTC fee route, Terminal Wallet/BTC detail section, BTD and UAPI tests, Gate 3 checker | drafted | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | | Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack/src/reading-pipeline-observability.ts`, `packages/pipeline-hosts/src/asset-pack-harness.ts`, Terminal stream components, Gate 4 checker | drafted | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt/raw-output/parsed-output telemetry is contract-projected, complete, and readable. | -| AssetPack disclosure rights | Gate 5 | BTD access primitives, AssetPack preview UI, disclosure policy tests | pending | Source-safe preview and paid unlock are proven without source leakage. | +| AssetPack disclosure rights | Gate 5 | `asset-pack-disclosure.ts`, AssetPack postprocess, sandbox harness, BTD access tests, Terminal disclosure review UI, Gate 5 checker | drafted | Source-safe preview and paid unlock are proven without protected-source leakage. | | Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, Terminal repair UI | pending | Ledger, database, and metaphysical state drift is visible and repairable. | | Organization permission authority | Gate 7 | access policy, org holdings, MCP/ChatGPT gates, Terminal permission UI | pending | Registry-derived roles, holdings, and read-license authority govern actions. | | Commercial formalization | Gate 8 | packages/protocol, package tests, import scans, docs | pending | Demonstration-origin commercial internals are package-native and no runtime demo imports remain. | @@ -70,7 +70,8 @@ No `_legacy/` source is active source truth. | Gate 2 read model | `pnpm run check:v29-gate2` proves typed route-owned Terminal transaction reading | drafted | | Gate 3 wallet/BTC operation | `pnpm run check:v29-gate3` proves quote lifecycle, signer recovery, blocked readiness, API posture, and Terminal Wallet/BTC detail | drafted | | Gate 4 Reading observability | `pnpm run check:v29-gate4` proves contract-aware Reading stream telemetry and Terminal rendering | drafted | -| Product implementation gates | Gates 3-9 close remaining Terminal transaction depth with tests and docs | pending | +| Gate 5 AssetPack disclosure | `pnpm run check:v29-gate5` proves source-safe disclosure review, leakage detection, Terminal preview rendering, and PR title enforcement | drafted | +| Product implementation gates | Gates 6-9 close remaining Terminal transaction depth with tests and docs | pending | | Promotion gate | Gate 10 closes generated proof and promotion automation | pending | ## Gate 1 Parity @@ -163,3 +164,28 @@ Gate 3 is complete when package primitives model BTC quotes, signer recovery, op ## Gate 4 completion condition Gate 4 is complete when Reading pipeline observability is package-owned, stream events are contract-projected in the sandbox harness, Terminal renders the projection through shared execution components, focused package and UAPI tests pass, `check:v29-gate4` passes, CI invokes the checker and tests, docs name the implemented source surfaces, and the gate branch is committed and pushed for review into `version/v29`. + +## Gate 5 Parity + +| Requirement | Source evidence | Current V29 judgment | +| --- | --- | --- | +| AssetPack disclosure review is package-owned | `asset-pack-disclosure.ts`, package exports, disclosure tests | drafted | +| Source visibility separates pending, paid, owner, licensee, and denied states | `buildAssetPackDisclosureReview`, BTD access tests | drafted | +| Protected source leakage fails closed before preview display | `reviewAssetPackProtectedSourceLeakage`, `assertAssetPackDisclosureSourceSafe`, disclosure tests | drafted | +| Postprocessing persists disclosure review and review root | `postprocess.ts`, postprocess tests | drafted | +| Sandbox harness stores and exports disclosure review evidence | `packages/pipeline-hosts/src/asset-pack-harness.ts`, harness tests | drafted | +| Terminal preview surface renders disclosure policy before raw evidence | `TerminalDepositReadWorkbench.tsx`, Terminal harness client tests | drafted | +| Gate PR title enforcement is automated | `.github/workflows/bitcode-gate-quality.yml`, PR template, AGENTS/README instructions | drafted | +| Gate 5 checker is wired to package scripts and CI | `scripts/check-v29-gate5-assetpack-disclosure-rights.mjs`, `package.json`, gate workflow | drafted | + +## Gate 5 accepted boundaries + +- Gate 5 does not reveal protected AssetPack source before settlement. +- Gate 5 does not perform settlement reconciliation repair; Gate 6 owns ledger/database drift and repair. +- Gate 5 does not implement organization authority beyond read-right state distinctions; Gate 7 owns registry-derived roles and holdings. +- Gate 5 does not add browser proof or full UX polish; Gate 9 owns that surface. +- Gate 5 does not add versioned API routes or source identifiers. + +## Gate 5 completion condition + +Gate 5 is complete when AssetPack disclosure review is package-owned, postprocess and sandbox harness evidence include source-safe disclosure review roots, protected-source leakage tests fail closed, Terminal renders the disclosure review through the Reading preview surface, gate PR title enforcement is active, focused package and UAPI tests pass, `check:v29-gate5` passes, CI invokes the checker and tests, docs name the implemented source surfaces, and the gate branch is committed and pushed for review into `version/v29`. diff --git a/README.md b/README.md index cede61449..79d8ad57a 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ Use a version branch and gate-numbered branches: implemented, specified, tested, documented, committed, pushed, and ready for 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`. 6. Open the version branch back into `main` only after all gates close and the version is formally promoted as canon. diff --git a/package.json b/package.json index 440b8b456..a45a7a44d 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "check:v29-gate2": "node scripts/check-v29-gate2-terminal-transaction-read-models.mjs", "check:v29-gate3": "node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs", "check:v29-gate4": "node scripts/check-v29-gate4-reading-pipeline-observability.mjs", + "check:v29-gate5": "node scripts/check-v29-gate5-assetpack-disclosure-rights.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/__tests__/btd.test.ts b/packages/btd/__tests__/btd.test.ts index 1fcda9c82..5e5e52799 100644 --- a/packages/btd/__tests__/btd.test.ts +++ b/packages/btd/__tests__/btd.test.ts @@ -257,4 +257,61 @@ describe('registry-derived read access projection', () => { expect(decision.decision).toBe('licensed_read'); }); + + it('keeps denied read decisions explicit for policy mismatch and revoked licenses', () => { + const projection = buildBtdReadAccessProjectionFromRegistryRows({ + assetPackId: 'asset-pack-1', + range: { + asset_pack_id: 'asset-pack-1', + range_start: 10, + range_end_exclusive: 15, + token_count: 5, + access_policy_id: 'policy-1', + access_policy_hash: 'policy-hash', + }, + ownershipRows: [ + { + to_wallet_id: 'wallet-reader', + asset_pack_id: 'asset-pack-1', + range_start: 10, + range_end_exclusive: 15, + access_policy_hash: 'stale-policy-hash', + }, + ], + licenseRows: [ + { + license_id: 'license-1', + wallet_id: 'wallet-reader', + asset_pack_id: 'asset-pack-1', + access_policy_hash: 'policy-hash', + valid_from: '2026-05-01T00:00:00.000Z', + revoked_at: '2026-05-10T00:00:00.000Z', + }, + ], + }); + + expect(evaluateBtdReadAccess({ + walletId: 'wallet-reader', + assetPackId: 'asset-pack-1', + accessPolicy: projection.accessPolicy, + ownershipClaims: [], + licenses: projection.licenses, + at: '2026-05-19T00:00:00.000Z', + })).toMatchObject({ + decision: 'denied', + reason: 'license_revoked', + }); + + expect(evaluateBtdReadAccess({ + walletId: 'wallet-reader', + assetPackId: 'asset-pack-1', + accessPolicy: projection.accessPolicy, + ownershipClaims: projection.ownershipClaims, + licenses: [], + at: '2026-05-19T00:00:00.000Z', + })).toMatchObject({ + decision: 'denied', + reason: 'policy_mismatch', + }); + }); }); diff --git a/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts b/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts index 23bcf85c1..5ba358acc 100644 --- a/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts +++ b/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts @@ -163,6 +163,8 @@ describe('asset-pack sandbox harness plan', () => { expect(source).toContain('pipeline-stream-event'); expect(source).toContain('synthesizeReadNeedForPipelineInput'); expect(source).toContain('buildAssetPackSourceSafePreview'); + expect(source).toContain('buildAssetPackDisclosureReview'); + expect(source).toContain('assertAssetPackDisclosureSourceSafe'); expect(source).toContain('buildAssetPackSettlementUnlock'); expect(source).toContain('applyAssetPackSettlementUnlockToPreview'); expect(source).toContain('acceptedReadNeed: readNeed'); @@ -197,6 +199,8 @@ describe('asset-pack sandbox harness plan', () => { expect(source).toContain('readingPipelineObservabilityCoverage'); expect(source).toContain('Pipeline produced '); expect(source).toContain('sourceSafePreview,'); + expect(source).toContain('assetPackDisclosureReview,'); + expect(source).toContain("execution.store('asset-pack/preview', 'disclosureReview'"); expect(source).toContain('protectedSourceUnlock'); expect(source).toContain("execution.store('asset-pack/settlement', 'unlock'"); expect(source).toContain("execution.store('asset-pack/preview', 'feeQuote'"); diff --git a/packages/pipeline-hosts/src/asset-pack-harness.ts b/packages/pipeline-hosts/src/asset-pack-harness.ts index 13e1bff06..209455009 100644 --- a/packages/pipeline-hosts/src/asset-pack-harness.ts +++ b/packages/pipeline-hosts/src/asset-pack-harness.ts @@ -1555,8 +1555,10 @@ try { { assetPackPipeline, acceptReadNeed, + buildAssetPackDisclosureReview, buildAssetPackSourceSafePreview, buildReadingPipelineObservabilityInventory, + assertAssetPackDisclosureSourceSafe, isAcceptedReadNeed, resolveReadingPipelineTelemetryProjection, summarizeReadingPipelineObservabilityCoverage, @@ -1688,6 +1690,9 @@ try { }); execution.store('asset-pack/preview', 'sourceSafe', sourceSafePreview); execution.store('asset-pack/preview', 'feeQuote', sourceSafePreview.feeQuote); + const sourceSafeDisclosureReview = buildAssetPackDisclosureReview({ preview: sourceSafePreview }); + assertAssetPackDisclosureSourceSafe(sourceSafeDisclosureReview); + execution.store('asset-pack/preview', 'disclosureReview', sourceSafeDisclosureReview); const pipelineResultReasons = Array.isArray(fitResult?.resultReasons) ? fitResult.resultReasons : Array.isArray(depositorySearch?.resultReasons) @@ -1726,12 +1731,21 @@ try { requirePullRequestDelivery: deliveryRequired, }); const settledSourceSafePreview = applyAssetPackSettlementUnlockToPreview(sourceSafePreview, settlementUnlock); + const assetPackDisclosureReview = buildAssetPackDisclosureReview({ + preview: settledSourceSafePreview, + readRightState: settlementUnlock.state, + sourceAvailable: settlementUnlock.sourceAvailable, + reason: settlementUnlock.reason, + }); + assertAssetPackDisclosureSourceSafe(assetPackDisclosureReview); execution.store('asset-pack/preview', 'sourceSafe', settledSourceSafePreview); + execution.store('asset-pack/preview', 'disclosureReview', assetPackDisclosureReview); execution.store('asset-pack/settlement', 'unlock', settlementUnlock); execution.store('asset-pack/settlement', 'readLicenseId', settlementUnlock.readLicenseId); output = { ...(output || {}), sourceSafePreview: settledSourceSafePreview, + assetPackDisclosureReview, ledgerSettlement: { ...ledgerSettlement, protectedSourceUnlock: settlementUnlock, @@ -1768,6 +1782,7 @@ try { fitResult, depositorySearch, sourceSafePreview: settledSourceSafePreview, + assetPackDisclosureReview, assetPackSynthesisArtifacts: output?.assetPackSynthesisArtifacts || null, writtenAssets: output?.writtenAssets || null, deliveryMechanism: output?.deliveryMechanism || null, diff --git a/packages/pipelines/asset-pack/package.json b/packages/pipelines/asset-pack/package.json index 8e6c677a8..a6fedd3cb 100644 --- a/packages/pipelines/asset-pack/package.json +++ b/packages/pipelines/asset-pack/package.json @@ -6,6 +6,7 @@ "types": "src/index.ts", "exports": { ".": "./src/index.ts", + "./asset-pack-disclosure": "./src/asset-pack-disclosure.ts", "./read-need": "./src/read-need.ts", "./reading-pipeline-contract": "./src/reading-pipeline-contract.ts", "./reading-pipeline-observability": "./src/reading-pipeline-observability.ts", diff --git a/packages/pipelines/asset-pack/src/__tests__/asset-pack-disclosure.test.ts b/packages/pipelines/asset-pack/src/__tests__/asset-pack-disclosure.test.ts new file mode 100644 index 000000000..43c93301a --- /dev/null +++ b/packages/pipelines/asset-pack/src/__tests__/asset-pack-disclosure.test.ts @@ -0,0 +1,134 @@ +import { + assertAssetPackDisclosureSourceSafe, + buildAssetPackDisclosureReview, + reviewAssetPackProtectedSourceLeakage, + summarizeAssetPackDisclosureReview, +} from '../asset-pack-disclosure'; +import { + acceptReadNeed, + buildAssetPackSourceSafePreview, + synthesizeReadNeedForPipelineInput, +} from '../read-need'; + +const acceptedNeed = acceptReadNeed( + synthesizeReadNeedForPipelineInput({ + read: { + prompt: 'Find a source-safe AssetPack fit for Terminal settlement proof.', + }, + sourceRevision: { + repositoryFullName: 'engineeredsoftware/ENGI', + branch: 'main', + commit: '31bbc0c5227b6b3aed5d107fd8507d35ec22970a', + }, + }), + '2026-05-20T00:00:00.000Z', +); + +const preview = buildAssetPackSourceSafePreview({ + need: acceptedNeed, + fitResult: { + schema: 'bitcode.asset-pack.fit-result', + resultState: 'worthy_fit', + resultReasons: ['worthy source-bound fit'], + fitDepositAssetIds: ['deposit-1'], + selectedCandidateAssetIds: ['deposit-1'], + queryRoot: 'sha256:query', + rankingRoot: 'sha256:ranking', + searchedAssetCount: 1, + embeddingPolicy: { provider: 'openai', model: 'text-embedding-3-small' }, + selectionTrace: { + selectedCandidates: [ + { + assetId: 'deposit-1', + scores: { finalScore: 0.92 }, + proofEvidence: { proofRoot: 'sha256:proof' }, + }, + ], + fitDeposits: [], + blockedCandidates: [], + candidateRanking: [], + rejectedCandidateCount: 0, + }, + }, + rangeStart: 42, + tokenCount: 7, + pullRequestTarget: 'https://github.com/engineeredsoftware/ENGI/pull/29', + createdAt: '2026-05-20T00:00:00.000Z', +}); + +describe('AssetPack disclosure review', () => { + it('projects source-safe preview policy into a reviewable paid-unlock posture', () => { + const review = buildAssetPackDisclosureReview({ preview }); + + expect(review).toMatchObject({ + schema: 'bitcode.asset-pack.disclosure-review', + assetPackId: preview.assetPackId, + previewId: preview.previewId, + access: { + readRightState: 'pending_settlement', + sourceVisibility: 'withheld_before_settlement', + readerAction: 'pay_to_unlock', + sourceAvailable: false, + }, + policy: { + protectedSourceDisclosure: 'forbidden_before_settlement', + }, + range: { + rangeStart: 42, + rangeEndExclusive: 49, + tokenCount: 7, + }, + }); + expect(review.policy.visibleBeforeSettlement).toContain('BTC quote'); + expect(review.policy.withheldBeforeSettlement).toContain('protected source content'); + expect(review.roots.reviewRoot).toMatch(/^sha256:/); + expect(review.sourceLeakage.protectedSourceDetected).toBe(false); + expect(summarizeAssetPackDisclosureReview(review)).toContain('no protected-source leakage'); + }); + + it('distinguishes owner, licensed, and denied read-right states', () => { + expect(buildAssetPackDisclosureReview({ + preview, + readRightState: 'owner_read', + sourceAvailable: true, + }).access).toMatchObject({ + sourceVisibility: 'available_after_settlement', + readerAction: 'read_as_owner', + }); + expect(buildAssetPackDisclosureReview({ + preview, + readRightState: 'licensed_read', + sourceAvailable: true, + }).access).toMatchObject({ + sourceVisibility: 'available_after_settlement', + readerAction: 'read_as_licensee', + }); + expect(buildAssetPackDisclosureReview({ + preview, + readRightState: 'denied', + sourceAvailable: false, + reason: 'policy mismatch', + }).access).toMatchObject({ + sourceVisibility: 'denied', + readerAction: 'blocked', + reason: 'policy mismatch', + }); + }); + + it('fails closed when preview metadata carries protected source markers', () => { + const leakage = reviewAssetPackProtectedSourceLeakage({ + ...preview, + protectedSourceContent: 'diff --git a/app.ts b/app.ts\n@@ -1 +1 @@\n-secret\n+secret', + }); + + expect(leakage.protectedSourceDetected).toBe(true); + expect(leakage.findings.map((finding) => finding.reason)).toEqual( + expect.arrayContaining(['forbidden_source_field', 'source_patch_marker']), + ); + + expect(() => assertAssetPackDisclosureSourceSafe({ + ...buildAssetPackDisclosureReview({ preview }), + sourceLeakage: leakage, + })).toThrow(/protected source/); + }); +}); diff --git a/packages/pipelines/asset-pack/src/__tests__/postprocess.test.ts b/packages/pipelines/asset-pack/src/__tests__/postprocess.test.ts index a250668fe..b29725d3d 100644 --- a/packages/pipelines/asset-pack/src/__tests__/postprocess.test.ts +++ b/packages/pipelines/asset-pack/src/__tests__/postprocess.test.ts @@ -222,7 +222,19 @@ describe('normalizeAssetPackOutput', () => { 'https://github.com/engineeredsoftware/ENGI/pull/28' ); expect(normalized.feeQuote.quoteRoot).toMatch(/^sha256:/); + expect(normalized.assetPackDisclosureReview).toMatchObject({ + schema: 'bitcode.asset-pack.disclosure-review', + access: { + readRightState: 'pending_settlement', + sourceVisibility: 'withheld_before_settlement', + readerAction: 'pay_to_unlock', + }, + sourceLeakage: { + protectedSourceDetected: false, + }, + }); expect(result.sourceSafePreview?.roots.previewRoot).toMatch(/^sha256:/); + expect(result.assetPackDisclosureReview?.roots.reviewRoot).toMatch(/^sha256:/); expect(result.feeQuote?.finalityState).toBe('preview_not_paid'); expect(exec.get('asset-pack/preview', 'sourceSafe')?.previewId).toBe( normalized.sourceSafePreview.previewId diff --git a/packages/pipelines/asset-pack/src/asset-pack-disclosure.ts b/packages/pipelines/asset-pack/src/asset-pack-disclosure.ts new file mode 100644 index 000000000..0781e450e --- /dev/null +++ b/packages/pipelines/asset-pack/src/asset-pack-disclosure.ts @@ -0,0 +1,293 @@ +import type { + AssetPackReadRightState, + AssetPackSourceSafePreview, +} from './read-need'; + +export type AssetPackSourceVisibility = + | 'withheld_before_settlement' + | 'available_after_settlement' + | 'denied'; + +export type AssetPackDisclosureReaderAction = + | 'pay_to_unlock' + | 'read_as_owner' + | 'read_as_licensee' + | 'blocked'; + +export interface AssetPackProtectedSourceLeakageFinding { + path: string; + reason: 'forbidden_source_field' | 'source_patch_marker' | 'source_code_marker'; + excerpt: string; +} + +export interface AssetPackProtectedSourceLeakageReview { + protectedSourceDetected: boolean; + findingCount: number; + findings: AssetPackProtectedSourceLeakageFinding[]; +} + +export interface AssetPackDisclosureReview { + schema: 'bitcode.asset-pack.disclosure-review'; + assetPackId: string; + previewId: string; + access: { + readRightState: AssetPackReadRightState; + sourceVisibility: AssetPackSourceVisibility; + readerAction: AssetPackDisclosureReaderAction; + sourceAvailable: boolean; + reason: string; + }; + policy: { + accessPolicyId: string; + accessPolicyHash: string; + protectedSourceDisclosure: 'forbidden_before_settlement'; + visibleBeforeSettlement: string[]; + withheldBeforeSettlement: string[]; + }; + range: AssetPackSourceSafePreview['rangeProjection']; + roots: { + previewRoot: string; + proofRoot: string; + sourceManifestRoot: string; + feeQuoteRoot: string; + projectionRoot: string; + reviewRoot: string; + }; + sourceLeakage: AssetPackProtectedSourceLeakageReview; + reviewedAt: string; +} + +const FORBIDDEN_SOURCE_FIELD_NAMES = new Set([ + 'diff', + 'fullassetpackpatch', + 'fullpatch', + 'licensedreadpayload', + 'patch', + 'protectedsource', + 'protectedsourcecontent', + 'sourcebearingmanifestentries', + 'sourcecontent', + 'sourcefiles', + 'sourcepatch', +]); + +const SOURCE_PATCH_MARKERS = [ + /diff --git/u, + /^@@\s+-\d+(?:,\d+)?\s+\+\d+(?:,\d+)?/mu, + /^---\s+a\//mu, + /^\+\+\+\s+b\//mu, +]; + +const SOURCE_CODE_MARKERS = [ + /\bexport\s+(?:async\s+)?function\s+[A-Za-z_$][\w$]*\s*\(/u, + /\b(?:const|let|var)\s+[A-Za-z_$][\w$]*\s*=/u, + /\bclass\s+[A-Za-z_$][\w$]*\b/u, +]; + +export function buildAssetPackDisclosureReview(input: { + preview: AssetPackSourceSafePreview; + readRightState?: AssetPackReadRightState | null; + sourceAvailable?: boolean | null; + reason?: string | null; + reviewedAt?: string; +}): AssetPackDisclosureReview { + const preview = input.preview; + const readRightState = + input.readRightState || + preview.accessPolicy.readRightState || + preview.unlock.state; + const sourceAvailable = input.sourceAvailable ?? preview.unlock.sourceAvailable === true; + const sourceVisibility = resolveSourceVisibility(readRightState, sourceAvailable); + const readerAction = resolveReaderAction(readRightState, sourceAvailable); + const reviewedAt = input.reviewedAt || preview.createdAt; + const sourceLeakage = reviewAssetPackProtectedSourceLeakage(preview); + const reviewRoot = `sha256:${sha256(stableStringify({ + assetPackId: preview.assetPackId, + previewId: preview.previewId, + previewRoot: preview.roots.previewRoot, + accessPolicyHash: preview.accessPolicy.accessPolicyHash, + readRightState, + sourceAvailable, + sourceLeakage, + }))}`; + + return { + schema: 'bitcode.asset-pack.disclosure-review', + assetPackId: preview.assetPackId, + previewId: preview.previewId, + access: { + readRightState, + sourceVisibility, + readerAction, + sourceAvailable, + reason: input.reason || preview.unlock.reason, + }, + policy: { + accessPolicyId: preview.accessPolicy.accessPolicyId, + accessPolicyHash: preview.accessPolicy.accessPolicyHash, + protectedSourceDisclosure: preview.disclosurePolicy.protectedSourceDisclosure, + visibleBeforeSettlement: [...preview.disclosurePolicy.visibleBeforeSettlement], + withheldBeforeSettlement: [...preview.disclosurePolicy.withheldBeforeSettlement], + }, + range: { ...preview.rangeProjection }, + roots: { + previewRoot: preview.roots.previewRoot, + proofRoot: preview.roots.proofRoot, + sourceManifestRoot: preview.roots.sourceManifestRoot, + feeQuoteRoot: preview.feeQuote.quoteRoot, + projectionRoot: preview.rangeProjection.projectionRoot, + reviewRoot, + }, + sourceLeakage, + reviewedAt, + }; +} + +export function assertAssetPackDisclosureSourceSafe( + review: AssetPackDisclosureReview, +): AssetPackDisclosureReview { + if (review.sourceLeakage.protectedSourceDetected) { + const paths = review.sourceLeakage.findings.map((finding) => finding.path).join(', '); + throw new Error(`AssetPack source-safe preview leaked protected source at ${paths}.`); + } + + return review; +} + +export function reviewAssetPackProtectedSourceLeakage( + value: unknown, +): AssetPackProtectedSourceLeakageReview { + const findings: AssetPackProtectedSourceLeakageFinding[] = []; + visitForProtectedSource(value, [], findings); + + return { + protectedSourceDetected: findings.length > 0, + findingCount: findings.length, + findings, + }; +} + +export function summarizeAssetPackDisclosureReview( + review: AssetPackDisclosureReview, +): string { + const leakage = review.sourceLeakage.protectedSourceDetected + ? `${review.sourceLeakage.findingCount} protected-source leakage finding(s)` + : 'no protected-source leakage'; + return [ + `AssetPack ${review.assetPackId}`, + `access ${review.access.readRightState}`, + `source ${review.access.sourceVisibility}`, + `action ${review.access.readerAction}`, + leakage, + ].join('; '); +} + +function resolveSourceVisibility( + readRightState: AssetPackReadRightState, + sourceAvailable: boolean, +): AssetPackSourceVisibility { + if (readRightState === 'denied') return 'denied'; + if (sourceAvailable && (readRightState === 'owner_read' || readRightState === 'licensed_read')) { + return 'available_after_settlement'; + } + return 'withheld_before_settlement'; +} + +function resolveReaderAction( + readRightState: AssetPackReadRightState, + sourceAvailable: boolean, +): AssetPackDisclosureReaderAction { + if (readRightState === 'denied') return 'blocked'; + if (sourceAvailable && readRightState === 'owner_read') return 'read_as_owner'; + if (sourceAvailable && readRightState === 'licensed_read') return 'read_as_licensee'; + return 'pay_to_unlock'; +} + +function visitForProtectedSource( + value: unknown, + path: string[], + findings: AssetPackProtectedSourceLeakageFinding[], +): void { + if (value === null || value === undefined) return; + + if (typeof value === 'string') { + collectStringFindings(value, path, findings); + return; + } + + if (Array.isArray(value)) { + value.forEach((entry, index) => visitForProtectedSource(entry, [...path, String(index)], findings)); + return; + } + + if (typeof value !== 'object') return; + + for (const [key, child] of Object.entries(value as Record)) { + const childPath = [...path, key]; + if (FORBIDDEN_SOURCE_FIELD_NAMES.has(normalizeFieldName(key)) && child !== null && child !== undefined) { + findings.push({ + path: pathLabel(childPath), + reason: 'forbidden_source_field', + excerpt: excerptFor(child), + }); + } + visitForProtectedSource(child, childPath, findings); + } +} + +function collectStringFindings( + value: string, + path: string[], + findings: AssetPackProtectedSourceLeakageFinding[], +): void { + const trimmed = value.trim(); + if (!trimmed) return; + + if (SOURCE_PATCH_MARKERS.some((pattern) => pattern.test(trimmed))) { + findings.push({ + path: pathLabel(path), + reason: 'source_patch_marker', + excerpt: excerptFor(trimmed), + }); + return; + } + + if (SOURCE_CODE_MARKERS.some((pattern) => pattern.test(trimmed))) { + findings.push({ + path: pathLabel(path), + reason: 'source_code_marker', + excerpt: excerptFor(trimmed), + }); + } +} + +function normalizeFieldName(value: string): string { + return value.replace(/[^A-Za-z0-9]/gu, '').toLowerCase(); +} + +function pathLabel(path: string[]): string { + return path.length ? path.join('.') : ''; +} + +function excerptFor(value: unknown): string { + const text = typeof value === 'string' ? value : stableStringify(value); + return text.length > 120 ? `${text.slice(0, 117)}...` : text; +} + +function sha256(value: string): string { + let hash = 0x811c9dc5; + for (let index = 0; index < value.length; index += 1) { + hash ^= value.charCodeAt(index); + hash = Math.imul(hash, 0x01000193); + } + return (hash >>> 0).toString(16).padStart(8, '0'); +} + +function stableStringify(value: unknown): string { + if (value === null || typeof value !== 'object') return JSON.stringify(value); + if (Array.isArray(value)) return `[${value.map(stableStringify).join(',')}]`; + return `{${Object.keys(value as Record) + .sort() + .map((key) => `${JSON.stringify(key)}:${stableStringify((value as Record)[key])}`) + .join(',')}}`; +} diff --git a/packages/pipelines/asset-pack/src/index.ts b/packages/pipelines/asset-pack/src/index.ts index 93651ea38..18942887e 100644 --- a/packages/pipelines/asset-pack/src/index.ts +++ b/packages/pipelines/asset-pack/src/index.ts @@ -269,6 +269,7 @@ export * from './phases'; export * from './types/AssetPackWrittenAssetType'; export * from './depository-search'; export * from './embedding-config'; +export * from './asset-pack-disclosure'; export * from './reading-pipeline-contract'; export * from './reading-pipeline-observability'; export { AssetPackCloneVCSRepositoryAgent } from './agents/setup/asset-pack-clone-vcs-repository-agent'; diff --git a/packages/pipelines/asset-pack/src/postprocess.ts b/packages/pipelines/asset-pack/src/postprocess.ts index 139b60bc6..eaf941d0d 100644 --- a/packages/pipelines/asset-pack/src/postprocess.ts +++ b/packages/pipelines/asset-pack/src/postprocess.ts @@ -9,6 +9,11 @@ import { isAcceptedReadNeed, type AssetPackSourceSafePreview, } from './read-need'; +import { + assertAssetPackDisclosureSourceSafe, + buildAssetPackDisclosureReview, + type AssetPackDisclosureReview, +} from './asset-pack-disclosure'; export function normalizeAssetPackOutput(output: AssetPackOutput, execution: Execution): AssetPackOutput { const enhanced = { ...output }; @@ -80,7 +85,9 @@ export function normalizeAssetPackOutput(output: AssetPackOutput, execution: Exe } const sourceSafePreview = ensureAssetPackSourceSafePreview(execution, enhanced, prUrl); if (sourceSafePreview) { + const assetPackDisclosureReview = ensureAssetPackDisclosureReview(execution, sourceSafePreview); (enhanced as any).sourceSafePreview = sourceSafePreview; + (enhanced as any).assetPackDisclosureReview = assetPackDisclosureReview; (enhanced as any).feeQuote = sourceSafePreview.feeQuote; } if (!enhanced.deliveryMechanism && enhanced.shippable) { @@ -163,6 +170,9 @@ export function buildAssetPackPostprocessedResult( normalized, normalized.deliveryMechanism?.prUrl || normalized.shippable?.prUrl ); + const assetPackDisclosureReview = sourceSafePreview + ? ensureAssetPackDisclosureReview(execution, sourceSafePreview) + : undefined; const shippable = normalized.shippable || normalized.deliveryMechanism; const shippables = normalized.shippables || @@ -205,6 +215,7 @@ export function buildAssetPackPostprocessedResult( ...(sourceSafePreview ? { sourceSafePreview, + assetPackDisclosureReview, feeQuote: sourceSafePreview.feeQuote, } : {}), @@ -287,6 +298,26 @@ function ensureAssetPackSourceSafePreview( return preview; } +function ensureAssetPackDisclosureReview( + execution: Execution, + sourceSafePreview: AssetPackSourceSafePreview, +): AssetPackDisclosureReview { + const storedReview = + findStoredExecutionValue(execution, 'asset-pack/preview', 'disclosureReview') || + findStoredExecutionValue(execution, 'asset-pack', 'disclosureReview'); + if (storedReview?.schema === 'bitcode.asset-pack.disclosure-review') { + return storedReview as AssetPackDisclosureReview; + } + + const review = buildAssetPackDisclosureReview({ preview: sourceSafePreview }); + assertAssetPackDisclosureSourceSafe(review); + try { + execution.store('asset-pack/preview', 'disclosureReview', review as any); + execution.store('asset-pack/preview', 'disclosureReviewRoot', review.roots.reviewRoot); + } catch {} + return review; +} + function firstString(...values: unknown[]): string | null { for (const value of values) { if (typeof value === 'string' && value.trim()) return value.trim(); diff --git a/packages/pipelines/asset-pack/src/types/PipelineSchemas.ts b/packages/pipelines/asset-pack/src/types/PipelineSchemas.ts index 1f7a390e1..70c4a3af2 100644 --- a/packages/pipelines/asset-pack/src/types/PipelineSchemas.ts +++ b/packages/pipelines/asset-pack/src/types/PipelineSchemas.ts @@ -3,6 +3,7 @@ import { AssetPackWrittenAssetType, } from './AssetPackWrittenAssetType'; import type { AssetPackFitResultState, DepositorySearchResult } from '../depository-search'; +import type { AssetPackDisclosureReview } from '../asset-pack-disclosure'; import type { AssetPackSourceSafePreview, ShareToFeeQuote } from '../read-need'; /** @@ -74,6 +75,7 @@ export interface AssetPackOutput { fit?: AssetPackOutput['fitResult']; depositorySearch?: DepositorySearchResult; sourceSafePreview?: AssetPackSourceSafePreview; + assetPackDisclosureReview?: AssetPackDisclosureReview; feeQuote?: ShareToFeeQuote; } @@ -103,6 +105,7 @@ export interface AssetPackPostprocessed { fit?: AssetPackOutput['fitResult']; depositorySearch?: DepositorySearchResult; sourceSafePreview?: AssetPackSourceSafePreview; + assetPackDisclosureReview?: AssetPackDisclosureReview; feeQuote?: ShareToFeeQuote; assetPack?: { read?: string; diff --git a/scripts/check-v29-gate5-assetpack-disclosure-rights.mjs b/scripts/check-v29-gate5-assetpack-disclosure-rights.mjs new file mode 100644 index 000000000..99e542b9f --- /dev/null +++ b/scripts/check-v29-gate5-assetpack-disclosure-rights.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-v29-gate5-assetpack-disclosure-rights.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 5 AssetPack disclosure rights and preview-depth closure.', + ].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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 Gate 5 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-5-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 5 work must occur on version/v29 or v29/gate-5-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'scripts/check-v29-gate5-assetpack-disclosure-rights.mjs', + 'packages/pipelines/asset-pack/src/asset-pack-disclosure.ts', + 'packages/pipelines/asset-pack/src/__tests__/asset-pack-disclosure.test.ts', + 'packages/pipelines/asset-pack/src/postprocess.ts', + 'packages/pipelines/asset-pack/src/__tests__/postprocess.test.ts', + 'packages/pipelines/asset-pack/src/read-need.ts', + 'packages/pipeline-hosts/src/asset-pack-harness.ts', + 'packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts', + 'packages/btd/src/access.ts', + 'packages/btd/src/settlement.ts', + 'packages/btd/__tests__/btd.test.ts', + 'uapi/app/terminal/TerminalDepositReadWorkbench.tsx', + 'uapi/app/terminal/terminal-pipeline-harness-client.ts', + 'uapi/tests/terminalPipelineHarnessClient.test.ts', + 'AGENTS.md', + 'README.md', + '.github/pull_request_template.md', + '.github/workflows/bitcode-gate-quality.yml', + 'package.json', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 5 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const disclosure = read(root, 'packages/pipelines/asset-pack/src/asset-pack-disclosure.ts'); + const disclosureTest = read(root, 'packages/pipelines/asset-pack/src/__tests__/asset-pack-disclosure.test.ts'); + const postprocess = read(root, 'packages/pipelines/asset-pack/src/postprocess.ts'); + const postprocessTest = read(root, 'packages/pipelines/asset-pack/src/__tests__/postprocess.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 btdTest = read(root, 'packages/btd/__tests__/btd.test.ts'); + const terminal = read(root, 'uapi/app/terminal/TerminalDepositReadWorkbench.tsx'); + const terminalClient = read(root, 'uapi/app/terminal/terminal-pipeline-harness-client.ts'); + const terminalClientTest = read(root, 'uapi/tests/terminalPipelineHarnessClient.test.ts'); + const agents = read(root, 'AGENTS.md'); + const readme = read(root, 'README.md'); + const prTemplate = read(root, '.github/pull_request_template.md'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + assertCheck(failures, spec.includes('V29 AssetPack disclosure rights canon'), 'V29 SPEC must define AssetPack disclosure rights canon.'); + assertCheck(failures, delta.includes('AssetPackDisclosureReview'), 'V29 DELTA must name Gate 5 AssetPackDisclosureReview acceptance.'); + assertCheck(failures, notes.includes('Gate 5 working notes'), 'V29 NOTES must carry Gate 5 working notes.'); + assertCheck(failures, parity.includes('## Gate 5 Parity'), 'V29 PARITY must include Gate 5 parity.'); + assertCheck(failures, parity.includes('Gate 5 completion condition'), 'V29 PARITY must include Gate 5 completion condition.'); + + for (const symbol of [ + 'AssetPackDisclosureReview', + 'AssetPackProtectedSourceLeakageReview', + 'buildAssetPackDisclosureReview', + 'assertAssetPackDisclosureSourceSafe', + 'reviewAssetPackProtectedSourceLeakage', + 'withheld_before_settlement', + 'available_after_settlement', + 'pay_to_unlock', + 'read_as_owner', + 'read_as_licensee', + 'blocked', + 'forbidden_source_field', + 'source_patch_marker', + 'source_code_marker', + ]) { + assertCheck(failures, disclosure.includes(symbol), `AssetPack disclosure primitive is missing ${symbol}.`); + } + + assertCheck( + failures, + disclosureTest.includes('pending_settlement') && + disclosureTest.includes('owner_read') && + disclosureTest.includes('licensed_read') && + disclosureTest.includes('denied') && + disclosureTest.includes('protectedSourceContent') && + disclosureTest.includes('diff --git'), + 'AssetPack disclosure tests must cover pending, owner, licensed, denied, and source-leakage states.', + ); + assertCheck( + failures, + postprocess.includes('assetPackDisclosureReview') && + postprocess.includes('disclosureReviewRoot') && + postprocess.includes('assertAssetPackDisclosureSourceSafe') && + postprocessTest.includes('assetPackDisclosureReview'), + 'AssetPack postprocess must persist disclosure review and test the projected result.', + ); + assertCheck( + failures, + harness.includes('assetPackDisclosureReview') && + harness.includes('disclosureReview') && + harness.includes('assertAssetPackDisclosureSourceSafe') && + harnessTest.includes('assetPackDisclosureReview'), + 'Sandbox harness must store/export AssetPack disclosure review evidence and test the generated runner.', + ); + assertCheck( + failures, + btdTest.includes('owner') && + btdTest.includes('licensed-read') && + btdTest.includes('revoked license') && + btdTest.includes('policy mismatch'), + 'BTD tests must cover owner-read, licensed-read, and denied read-right boundaries.', + ); + assertCheck( + failures, + terminal.includes('Disclosure review') && + terminal.includes('sourceVisibility') && + terminal.includes('readerAction') && + terminal.includes('protectedSourceDetected') && + terminalClient.includes('assetPackDisclosureReview') && + terminalClient.includes('leakage') && + terminalClientTest.includes('assetPackDisclosureReview') && + terminalClientTest.includes('leakage none'), + 'Terminal surfaces must render and summarize AssetPack disclosure review evidence.', + ); + assertCheck( + failures, + agents.includes('V29 Gate 5: AssetPack Disclosure Rights And Preview Depth') && + readme.includes('V29 Gate 5: AssetPack Disclosure Rights And Preview Depth') && + prTemplate.includes('V29 Gate N: Concise Topical Title') && + gateWorkflow.includes('Validate gate pull request title'), + 'Repository instructions, PR template, and CI must enforce version/gate-prefixed PR titles.', + ); + assertCheck( + failures, + packageJson.includes('"check:v29-gate5"') && + gateWorkflow.includes('check-v29-gate5-assetpack-disclosure-rights.mjs') && + gateWorkflow.includes('asset-pack-disclosure.test.ts'), + 'Package scripts and gate-quality workflow must invoke Gate 5 checker and focused tests.', + ); + + if (failures.length) { + process.stderr.write('V29 Gate 5 check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V29 Gate 5 AssetPack disclosure rights check passed.\n'); +} + +main(); diff --git a/uapi/app/terminal/TerminalDepositReadWorkbench.tsx b/uapi/app/terminal/TerminalDepositReadWorkbench.tsx index eb3e562a4..ca27d5118 100644 --- a/uapi/app/terminal/TerminalDepositReadWorkbench.tsx +++ b/uapi/app/terminal/TerminalDepositReadWorkbench.tsx @@ -65,6 +65,10 @@ function stringList(value: unknown): string[] { : []; } +function countList(value: unknown): number { + return Array.isArray(value) ? value.length : 0; +} + function numericValue(value: unknown): number | null { return typeof value === 'number' && Number.isFinite(value) ? value : null; } @@ -281,6 +285,14 @@ export default function TerminalDepositReadWorkbench({ return null; }, [harnessEvents]); const sourceSafePreview = objectValue(completedHarnessEvidence?.sourceSafePreview); + const assetPackDisclosureReview = + objectValue(completedHarnessEvidence?.assetPackDisclosureReview) || + objectValue(sourceSafePreview?.disclosureReview); + const disclosureAccess = objectValue(assetPackDisclosureReview?.access); + const disclosurePolicy = objectValue(assetPackDisclosureReview?.policy); + const disclosureLeakage = objectValue(assetPackDisclosureReview?.sourceLeakage); + const disclosureRoots = objectValue(assetPackDisclosureReview?.roots); + const disclosureSourceSafe = disclosureLeakage?.protectedSourceDetected !== true; const ledgerSettlement = objectValue(completedHarnessEvidence?.ledgerSettlement); const previewFeeQuote = objectValue(sourceSafePreview?.feeQuote); const protectedSourceUnlock = @@ -302,6 +314,58 @@ export default function TerminalDepositReadWorkbench({ ? 'review-synthesized-need' : 'request-read'; const currentReadNeed = acceptedReadNeed || readNeed; + const disclosureRows = useMemo( + () => [ + { + label: 'Visibility', + value: textValue(disclosureAccess?.sourceVisibility) || 'withheld before settlement', + }, + { + label: 'Reader action', + value: textValue(disclosureAccess?.readerAction) || 'pay to unlock', + }, + { + label: 'Policy root', + value: + shortIdentifier(disclosurePolicy?.accessPolicyHash) || + shortIdentifier(objectValue(sourceSafePreview?.accessPolicy)?.accessPolicyHash) || + 'pending', + }, + { + label: 'Review root', + value: shortIdentifier(disclosureRoots?.reviewRoot) || 'pending', + }, + { + label: 'Visible facts', + value: `${countList(disclosurePolicy?.visibleBeforeSettlement)} before payment`, + }, + { + label: 'Withheld facts', + value: `${countList(disclosurePolicy?.withheldBeforeSettlement)} until paid`, + }, + { + label: 'Leakage', + value: disclosureLeakage?.protectedSourceDetected === true + ? `${String(disclosureLeakage.findingCount || 'detected')} finding(s)` + : disclosureLeakage + ? 'none detected' + : 'pending', + }, + { + label: 'Source', + value: protectedSourceUnlock?.sourceAvailable === true ? 'available after settlement' : 'withheld', + }, + ], + [ + disclosureAccess?.readerAction, + disclosureAccess?.sourceVisibility, + disclosureLeakage, + disclosurePolicy, + disclosureRoots?.reviewRoot, + protectedSourceUnlock?.sourceAvailable, + sourceSafePreview?.accessPolicy, + ], + ); const readNeedRows = useMemo(() => { if (!currentReadNeed) return []; return [ @@ -759,6 +823,27 @@ export default function TerminalDepositReadWorkbench({
))}
+
+
+
+

Disclosure review

+

+ Measurements, roots, fit ids, fee quote, and policy posture are visible. Protected source stays withheld until the paid read-right unlock is proven. +

+
+ + {disclosureSourceSafe ? 'source-safe' : 'blocked'} + +
+
+ {disclosureRows.map((row) => ( +
+
{row.label}
+
{row.value}
+
+ ))} +
+
diff --git a/uapi/app/terminal/terminal-pipeline-harness-client.ts b/uapi/app/terminal/terminal-pipeline-harness-client.ts index ed97fbee8..51b5b2d7b 100644 --- a/uapi/app/terminal/terminal-pipeline-harness-client.ts +++ b/uapi/app/terminal/terminal-pipeline-harness-client.ts @@ -635,8 +635,11 @@ export function summarizeTerminalReadFitsFindingSynthesisHarnessEvent( const depositorySearch = recordValue(evidence?.depositorySearch); const ledgerSettlement = recordValue(evidence?.ledgerSettlement); const sourceSafePreview = recordValue(evidence?.sourceSafePreview); + const assetPackDisclosureReview = recordValue(evidence?.assetPackDisclosureReview); const feeQuote = recordValue(sourceSafePreview?.feeQuote); const unlock = recordValue(sourceSafePreview?.unlock) || recordValue(ledgerSettlement?.protectedSourceUnlock); + const disclosureAccess = recordValue(assetPackDisclosureReview?.access); + const disclosureLeakage = recordValue(assetPackDisclosureReview?.sourceLeakage); const fitState = String(fitResult?.resultState || evidence?.resultState || 'unknown'); const searchedAssetCount = depositorySearch?.searchedAssetCount; const ledgerStatus = ledgerSettlement?.status @@ -657,6 +660,14 @@ export function summarizeTerminalReadFitsFindingSynthesisHarnessEvent( : unlock?.state ? ` source ${String(unlock.state)}` : null; + const disclosureText = disclosureAccess?.sourceVisibility + ? ` disclosure ${String(disclosureAccess.sourceVisibility)}` + : null; + const leakageText = disclosureLeakage?.protectedSourceDetected === true + ? ` leakage ${String(disclosureLeakage.findingCount || 'detected')}` + : disclosureLeakage + ? ' leakage none' + : null; const searchText = typeof searchedAssetCount === 'number' ? ` searched ${searchedAssetCount} assets` : ' searched asset count unknown'; @@ -668,6 +679,8 @@ export function summarizeTerminalReadFitsFindingSynthesisHarnessEvent( ledgerStatus, feeQuoteText, unlockText, + disclosureText, + leakageText, telemetryText, ].filter(Boolean).join('; ') + '.'; } diff --git a/uapi/tests/terminalPipelineHarnessClient.test.ts b/uapi/tests/terminalPipelineHarnessClient.test.ts index adabb0f88..7165b582d 100644 --- a/uapi/tests/terminalPipelineHarnessClient.test.ts +++ b/uapi/tests/terminalPipelineHarnessClient.test.ts @@ -195,6 +195,15 @@ describe('terminal pipeline harness client', () => { sourceAvailable: true, }, }, + assetPackDisclosureReview: { + access: { + sourceVisibility: 'available_after_settlement', + }, + sourceLeakage: { + protectedSourceDetected: false, + findingCount: 0, + }, + }, }, }, }); @@ -206,6 +215,8 @@ describe('terminal pipeline harness client', () => { expect(summary).toContain('ledger settled'); expect(summary).toContain('fee 546 sats'); expect(summary).toContain('source licensed_read'); + expect(summary).toContain('disclosure available_after_settlement'); + expect(summary).toContain('leakage none'); expect(summary).toContain('telemetry 72 lines'); }); From 347221b452d1c04fa7cfd609207601a9cf6f7390 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Wed, 20 May 2026 17:08:26 -0300 Subject: [PATCH 06/18] V29 Gate 6: Close settlement reconciliation repair (#25) --- .github/workflows/bitcode-gate-quality.yml | 6 + BITCODE_SPEC_V29.md | 37 ++ BITCODE_SPEC_V29_DELTA.md | 10 + BITCODE_SPEC_V29_NOTES.md | 17 + BITCODE_SPEC_V29_PARITY_MATRIX.md | 27 +- package.json | 1 + packages/api/jest.config.cjs | 17 + packages/api/package.json | 2 +- .../src/routes/__tests__/btd-crypto.test.ts | 17 + packages/api/src/routes/btd-crypto.ts | 6 + packages/btd/__tests__/btd.test.ts | 69 ++++ packages/btd/src/reconciliation.ts | 368 +++++++++++++++++- .../src/__tests__/asset-pack-harness.test.ts | 4 + .../pipeline-hosts/src/asset-pack-harness.ts | 113 +++++- ...gate6-settlement-reconciliation-repair.mjs | 224 +++++++++++ uapi/app/terminal/README.md | 9 + ...alTransactionJournalReconciliationCard.tsx | 35 ++ .../terminal-journal-reconciliation.ts | 266 ++++++++++++- .../terminal-transaction-detail-snapshot.ts | 8 + .../terminalJournalReconciliation.test.ts | 70 ++++ .../terminalTransactionDetailCards.test.tsx | 18 + 21 files changed, 1292 insertions(+), 32 deletions(-) create mode 100644 packages/api/jest.config.cjs create mode 100644 scripts/check-v29-gate6-settlement-reconciliation-repair.mjs diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index a7628dbc8..4a78cf43a 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -67,6 +67,7 @@ jobs: node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs --skip-branch-check node scripts/check-v29-gate4-reading-pipeline-observability.mjs --skip-branch-check node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs --skip-branch-check + node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs --skip-branch-check - name: Validate source casing and imports run: | @@ -76,6 +77,7 @@ jobs: - name: Type-check gate packages run: | pnpm --filter @bitcode/btd typecheck + pnpm --filter @bitcode/api build pnpm --filter @bitcode/pipeline-asset-pack typecheck pnpm --filter @bitcode/pipeline-hosts typecheck @@ -84,6 +86,8 @@ jobs: pnpm --filter @bitcode/btd test pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btc-fee-operation.test.ts pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btd.test.ts + pnpm --filter @bitcode/api exec jest --config jest.config.cjs --runTestsByPath src/routes/__tests__/btd-crypto.test.ts --runInBand + pnpm --filter @bitcode/pipeline-hosts exec jest --config jest.config.cjs --runTestsByPath src/__tests__/asset-pack-harness.test.ts --runInBand pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --passWithNoTests --forceExit pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath src/__tests__/reading-pipeline-observability.test.ts src/__tests__/reading-pipeline-contract.test.ts --runInBand pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath src/__tests__/asset-pack-disclosure.test.ts src/__tests__/postprocess.test.ts src/__tests__/read-need.test.ts --runInBand @@ -99,6 +103,8 @@ jobs: tests/terminalTransactionQuery.test.ts \ tests/terminalTransactionReadModel.test.ts \ tests/terminalWalletBtcOperation.test.ts \ + tests/terminalJournalReconciliation.test.ts \ + tests/terminalTransactionDetailCards.test.tsx \ tests/pipelineExecutionLogHeader.test.tsx \ --runInBand diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index 7d4fdbc2e..b76b2610b 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -225,6 +225,43 @@ 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. +## V29 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. + ## V29 canonical subsystem surfaces ### Depositing and asset supply diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index f1ea2aa16..625dd0d11 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -140,6 +140,16 @@ Closure acceptance: Gate 6 owns ledger/database/metaphysical separation, journal diffing, reconciliation repair actions, proof-root surfacing, settlement conservation drift handling, and delivery recovery. +Closure acceptance: + +- `@bitcode/btd` reconciliation reports carry `state`, `driftKindCounts`, `repairActions`, deterministic proof roots, and settlement conservation status while preserving private metaphysical canonical facts. +- Projection repair receipts classify missing database projections, ledger-root mismatches, ledger-finality mismatches, database-only orphan projections, and settlement conservation drift. +- Repair actions use canonical action kinds: retry database readback, project ledger fact, update finality state, quarantine database projection, pause settlement unlock, and recover delivery. +- The Vercel Sandbox pipeline harness records `ledgerDatabaseReconciliation` evidence after settlement/readback and emits reconciliation state plus repair-action counts in telemetry. +- Terminal journal detail renders drift classes, blocking reasons, ledger observed facts, database projected facts, metaphysical canonical facts, Terminal journal entries, repair actions, proof roots, and repair receipts without requiring browser-network inspection. +- Focused BTD, API, pipeline-harness, and Terminal tests prove repair classification, conservation drift blocking, delivery recovery visibility, and proof-root projection. +- `check:v29-gate6` and the gate-quality workflow fail closed when Gate 6 specification, implementation, tests, or workflow wiring is missing. + ### Gate 7: Organization Permissions And Interface Authority Gate 7 owns organization holdings, roles, read-license usage, registry-derived permission decisions, MCP/ChatGPT action authority alignment, and Terminal permission explainers. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 6b608ac2c..3c25ca295 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -151,6 +151,23 @@ Accepted Gate 5 posture: - Gate pull request titles must carry the uppercase version and gate prefix so gate closure can be audited from GitHub history. - Gate 5 does not implement reconciliation repair, organization authority, full settlement UI depth, or browser proof; later V29 gates own those slices. +## Gate 6 working notes + +Gate 6 hardens the settlement truth boundary after source-safe preview and before paid unlock/delivery are treated as admissible. + +Implementation notes: + +- Reconciliation must always separate ledger-observed facts from database-projected facts and private metaphysical canonical facts. +- Metaphysical facts remain private root commitments; they are not rendered as protected source. +- Repair receipts classify drift, while repair actions describe the operational next step. +- Settlement conservation drift is not a warning; it blocks unlock because BTC debit/credit truth must conserve before BTD rights are transferred or source is delivered. +- Delivery recovery is surfaced only after settlement is aligned and delivery evidence exists but the pull-request shippable is not visible in the transaction read model. + +Operator notes: + +- Terminal journal detail is the ordinary repair cockpit for this gate: drift classes, blockers, repair actions, proof roots, journal entries, and repair receipts must be visible without opening network logs. +- Raw payload remains audit material, not the primary operator interface. + ## Later-version boundaries - V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 37d442f9f..30c29eae4 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -53,7 +53,7 @@ No `_legacy/` source is active source truth. | Wallet signer/BTC operations | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, BTC fee route, Terminal Wallet/BTC detail section, BTD and UAPI tests, Gate 3 checker | drafted | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | | Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack/src/reading-pipeline-observability.ts`, `packages/pipeline-hosts/src/asset-pack-harness.ts`, Terminal stream components, Gate 4 checker | drafted | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt/raw-output/parsed-output telemetry is contract-projected, complete, and readable. | | AssetPack disclosure rights | Gate 5 | `asset-pack-disclosure.ts`, AssetPack postprocess, sandbox harness, BTD access tests, Terminal disclosure review UI, Gate 5 checker | drafted | Source-safe preview and paid unlock are proven without protected-source leakage. | -| Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, Terminal repair UI | pending | Ledger, database, and metaphysical state drift is visible and repairable. | +| Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, sandbox harness settlement evidence, Terminal repair UI, Gate 6 checker | drafted | Ledger, database, and metaphysical state drift is classified, proof-rooted, repair-actioned, and visible. | | Organization permission authority | Gate 7 | access policy, org holdings, MCP/ChatGPT gates, Terminal permission UI | pending | Registry-derived roles, holdings, and read-license authority govern actions. | | Commercial formalization | Gate 8 | packages/protocol, package tests, import scans, docs | pending | Demonstration-origin commercial internals are package-native and no runtime demo imports remain. | | Terminal UX quality | Gate 9 | Playwright/Jest/a11y/responsive/browser QA | pending | Complete transaction cockpit is usable by default and inspectable in detail. | @@ -182,6 +182,31 @@ Gate 4 is complete when Reading pipeline observability is package-owned, stream - Gate 5 does not reveal protected AssetPack source before settlement. - Gate 5 does not perform settlement reconciliation repair; Gate 6 owns ledger/database drift and repair. + +## Gate 6 Parity + +Gate 6 closes the settlement reconciliation slice by making drift ordinary data instead of hidden operator guesswork. + +Accepted surfaces: + +- `packages/btd/src/reconciliation.ts` is the canonical reconciliation primitive for ledger observed facts, database projected facts, private metaphysical canonical facts, settlement conservation checks, projection repair receipts, repair actions, drift-kind counts, report state, and proof roots. +- `packages/api/src/routes/btd-crypto.ts` accepts settlement conservation checks and binds reconciliation proof roots into the Terminal journal entry for reconciliation settlements. +- `packages/pipeline-hosts/src/asset-pack-harness.ts` stores `asset-pack/settlement.ledgerDatabaseReconciliation`, includes it in evidence, and streams reconciliation state/repair-action count after ledger readback. +- `uapi/app/terminal/terminal-journal-reconciliation.ts` projects the selected transaction into observed facts, projected facts, canonical facts, drift classes, blocking reasons, repair actions, proof roots, and repair receipts. +- `uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx` renders the above as a low-detail operator surface with raw payload still available behind expansion. + +Accepted failure states: + +- Confirmed ledger facts missing from database projection require operator-approved projection repair. +- Reorged or failed fee/anchor finality blocks settlement unlock. +- Database-only orphan projection blocks until quarantined or matched to a ledger observation. +- BTC fee settlement conservation drift blocks unlock and delivery. +- Post-settlement missing pull-request delivery produces a delivery recovery action without exposing protected source. + +Gate 6 completion condition: + +- `pnpm run check:v29-gate6` passes. +- Focused BTD, API, pipeline-hosts, and UAPI tests prove repair classification, conservation drift, proof roots, and Terminal repair visibility. - Gate 5 does not implement organization authority beyond read-right state distinctions; Gate 7 owns registry-derived roles and holdings. - Gate 5 does not add browser proof or full UX polish; Gate 9 owns that surface. - Gate 5 does not add versioned API routes or source identifiers. diff --git a/package.json b/package.json index a45a7a44d..b85fd78a0 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "check:v29-gate3": "node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs", "check:v29-gate4": "node scripts/check-v29-gate4-reading-pipeline-observability.mjs", "check:v29-gate5": "node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs", + "check:v29-gate6": "node scripts/check-v29-gate6-settlement-reconciliation-repair.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/jest.config.cjs b/packages/api/jest.config.cjs new file mode 100644 index 000000000..d571ce0b3 --- /dev/null +++ b/packages/api/jest.config.cjs @@ -0,0 +1,17 @@ +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + rootDir: '.', + roots: ['/src'], + testMatch: ['/src/**/*.test.ts'], + moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'], + transform: { + '^.+\\.tsx?$': [ + 'ts-jest', + { + tsconfig: '/tsconfig.json', + diagnostics: false, + }, + ], + }, +}; diff --git a/packages/api/package.json b/packages/api/package.json index 21a9ba129..b1aefa1b6 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -6,7 +6,7 @@ "types": "src/index.ts", "scripts": { "build": "tsc --noEmit", - "test": "jest", + "test": "jest --config jest.config.cjs", "dev": "tsc --watch" }, "dependencies": { diff --git a/packages/api/src/routes/__tests__/btd-crypto.test.ts b/packages/api/src/routes/__tests__/btd-crypto.test.ts index a95669d7f..6368d585e 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -762,9 +762,15 @@ describe('BTD crypto API builders', () => { }); expect(settlement.report.blocking).toBe(true); + expect(settlement.report.state).toBe('approval_required'); expect(settlement.report.repairs[0].repairKind).toBe('ledger_finality_state'); + expect(settlement.report.repairs[0].repairActionKind).toBe('update_finality_state'); + expect(settlement.report.proofRoots.repairPlanRoot).toMatch(/^btd-proof-root:repair-plan:/); expect(settlement.report.metaphysicalFacts[0].canonicalRoot).toBe('private-source-root'); expect(settlement.terminalJournalEntry.transactionKind).toBe('ledger_database_reconciliation'); + expect(settlement.terminalJournalEntry.receiptRoots).toContain( + settlement.report.proofRoots.repairPlanRoot, + ); }); it('builds deployment readiness, telemetry, and upgrade settlements', () => { @@ -1230,6 +1236,15 @@ describe('BTD crypto API builders', () => { private: true, }, ], + settlementConservationChecks: [ + { + checkId: 'settlement-conservation-api-1', + expectedDebitSats: 1000, + observedDebitSats: 1000, + expectedCreditSats: 1000, + observedCreditSats: 900, + }, + ], commitToRegistry: true, issuedAt, }), @@ -1240,6 +1255,8 @@ describe('BTD crypto API builders', () => { expect(response.status).toBe(200); expect(body.kind).toBe('btd_ledger_database_reconciliation_settlement'); expect(body.report.blocking).toBe(true); + expect(body.report.state).toBe('blocked'); + expect(body.report.driftKindCounts.settlement_conservation_drift).toBe(1); expect(body.report.metaphysicalFacts[0].canonicalRoot).toBe('private-source-root'); expect(body.committed).toBe(true); expect(insertReconciliationRepair).toHaveBeenCalledWith( diff --git a/packages/api/src/routes/btd-crypto.ts b/packages/api/src/routes/btd-crypto.ts index f158d6004..1e5834cb1 100644 --- a/packages/api/src/routes/btd-crypto.ts +++ b/packages/api/src/routes/btd-crypto.ts @@ -302,6 +302,7 @@ export interface BtdLedgerDatabaseReconciliationInput { ledgerFacts: LedgerObservedFact[]; databaseFacts: DatabaseProjectedFact[]; metaphysicalFacts?: MetaphysicalCanonicalFact[]; + settlementConservationChecks?: Parameters[0]['settlementConservationChecks']; commitToRegistry?: boolean; actorId?: string; issuedAt?: string; @@ -926,6 +927,7 @@ export function buildBtdLedgerDatabaseReconciliationSettlement( ledgerFacts: input.ledgerFacts, databaseFacts: input.databaseFacts, metaphysicalFacts: input.metaphysicalFacts, + settlementConservationChecks: input.settlementConservationChecks, issuedAt: input.issuedAt, }); const terminalJournalEntry = buildTerminalJournalEntry({ @@ -950,6 +952,10 @@ export function buildBtdLedgerDatabaseReconciliationSettlement( 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)), diff --git a/packages/btd/__tests__/btd.test.ts b/packages/btd/__tests__/btd.test.ts index 5e5e52799..026f23efc 100644 --- a/packages/btd/__tests__/btd.test.ts +++ b/packages/btd/__tests__/btd.test.ts @@ -18,6 +18,7 @@ import { calculateMeasuredBtdFromTokens, evaluateBtdReadAccess, listBtdAccessPolicyTemplates, + reconcileLedgerDatabaseProjection, } from '../src'; describe('calculateLlmBtcFeeEstimate', () => { @@ -187,6 +188,74 @@ describe('BTD access policy templates', () => { }); }); +describe('ledger/database reconciliation repair', () => { + it('classifies drift, emits repair actions, and preserves proof roots', () => { + const report = reconcileLedgerDatabaseProjection({ + reconciliationId: 'reconciliation-gate6', + ledgerFacts: [ + { + factId: 'anchor-1', + ledgerRoot: 'ledger-root-1', + finalityState: 'confirmed', + }, + ], + databaseFacts: [ + { + factId: 'anchor-1', + projectedLedgerRoot: 'stale-root', + projectedFinalityState: 'broadcast', + }, + { + factId: 'orphan-projection-1', + projectedLedgerRoot: 'orphan-root', + projectedFinalityState: 'confirmed', + }, + ], + settlementConservationChecks: [ + { + checkId: 'settlement-check-1', + expectedDebitSats: 1000, + observedDebitSats: 1000, + expectedCreditSats: 1000, + observedCreditSats: 900, + feeQuoteRoot: 'fee-quote-root', + paymentReceiptRoot: 'payment-receipt-root', + }, + ], + metaphysicalFacts: [ + { + factId: 'encrypted-source-pointer', + factKind: 'encrypted_storage_pointer', + canonicalRoot: 'encrypted-storage-root', + private: true, + }, + ], + issuedAt: '2026-05-20T12:00:00.000Z', + }); + + expect(report.state).toBe('blocked'); + expect(report.blocking).toBe(true); + expect(report.driftKindCounts).toMatchObject({ + ledger_root_mismatch: 1, + ledger_finality_mismatch: 1, + database_orphan_projection: 1, + settlement_conservation_drift: 1, + }); + expect(report.repairs.map((repair) => repair.repairActionKind)).toEqual( + expect.arrayContaining([ + 'project_ledger_fact', + 'update_finality_state', + 'quarantine_database_projection', + 'pause_settlement_unlock', + ]), + ); + expect(report.repairActions).toHaveLength(report.repairs.length); + expect(report.repairActions.every((action) => action.proofRoot.startsWith('btd-proof-root:'))).toBe(true); + expect(report.proofRoots.repairPlanRoot).toMatch(/^btd-proof-root:repair-plan:/); + expect(report.settlementConservation.status).toBe('drifted'); + }); +}); + describe('registry-derived read access projection', () => { it('maps range, ownership, and read-license rows into owner-read decisions', () => { const projection = buildBtdReadAccessProjectionFromRegistryRows({ diff --git a/packages/btd/src/reconciliation.ts b/packages/btd/src/reconciliation.ts index e3beff973..ff5ed6d4a 100644 --- a/packages/btd/src/reconciliation.ts +++ b/packages/btd/src/reconciliation.ts @@ -4,7 +4,44 @@ export type ProjectionRepairKind = | 'ledger_finality_state' | 'ledger_anchor_root' | 'terminal_post_state' - | 'receipt_root'; + | 'receipt_root' + | 'settlement_conservation' + | 'delivery_recovery'; + +export type ProjectionDriftKind = + | 'missing_database_projection' + | 'ledger_root_mismatch' + | 'ledger_finality_mismatch' + | 'database_orphan_projection' + | 'settlement_conservation_drift'; + +export type ProjectionRepairActionKind = + | 'retry_database_readback' + | 'project_ledger_fact' + | 'update_finality_state' + | 'quarantine_database_projection' + | 'pause_settlement_unlock' + | 'recover_delivery'; + +export type LedgerDatabaseReconciliationState = + | 'aligned' + | 'retryable' + | 'repairable' + | 'approval_required' + | 'blocked'; + +export interface ProjectionRepairAction { + actionId: string; + repairId?: string; + factId: string; + actionKind: ProjectionRepairActionKind; + driftKind: ProjectionDriftKind; + summary: string; + blocking: boolean; + requiresOperatorApproval: boolean; + proofRoot: string; + issuedAt: string; +} export interface LedgerObservedFact { factId: string; @@ -39,16 +76,49 @@ export interface ProjectionRepairReceipt { repairId: string; factId: string; repairKind: ProjectionRepairKind; + driftKind: ProjectionDriftKind; + repairActionKind: ProjectionRepairActionKind; before: string; after: string; blocking: boolean; + requiresOperatorApproval: boolean; + proofRoot: string; issuedAt: string; } +export interface SettlementConservationCheck { + checkId: string; + expectedDebitSats: number; + observedDebitSats: number; + expectedCreditSats: number; + observedCreditSats: number; + feeQuoteRoot?: string; + paymentReceiptRoot?: string; +} + +export interface SettlementConservationProjection { + status: 'not_checked' | 'balanced' | 'drifted'; + checks: SettlementConservationCheck[]; + proofRoot: string; +} + +export interface LedgerDatabaseReconciliationProofRoots { + ledgerObservedRoot: string; + databaseProjectionRoot: string; + metaphysicalCanonicalRoot: string; + repairPlanRoot: string; + settlementConservationRoot: string; +} + export interface LedgerDatabaseReconciliationReport { kind: 'btd.ledger_database_reconciliation'; reconciliationId: string; + state: LedgerDatabaseReconciliationState; repairs: ProjectionRepairReceipt[]; + repairActions: ProjectionRepairAction[]; + driftKindCounts: Record; + proofRoots: LedgerDatabaseReconciliationProofRoots; + settlementConservation: SettlementConservationProjection; metaphysicalFacts: MetaphysicalCanonicalFact[]; blocking: boolean; } @@ -58,11 +128,16 @@ export function reconcileLedgerDatabaseProjection(input: { ledgerFacts: LedgerObservedFact[]; databaseFacts: DatabaseProjectedFact[]; metaphysicalFacts?: MetaphysicalCanonicalFact[]; + 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 metaphysicalFacts = (input.metaphysicalFacts ?? []).map(assertMetaphysicalFact); + const settlementConservationChecks = (input.settlementConservationChecks ?? []).map( + assertSettlementConservationCheck, + ); const repairs: ProjectionRepairReceipt[] = []; const issuedAt = input.issuedAt ?? new Date().toISOString(); @@ -71,55 +146,123 @@ export function reconcileLedgerDatabaseProjection(input: { const projected = databaseByFactId.get(ledgerFact.factId); if (!projected) { - repairs.push({ - kind: 'btd.ledger_database_projection_repair', - repairId: `${reconciliationId}:${ledgerFact.factId}:missing_projection`, + repairs.push(buildRepairReceipt({ + reconciliationId, factId: ledgerFact.factId, + suffix: 'missing_projection', repairKind: 'ledger_anchor_root', + driftKind: 'missing_database_projection', + repairActionKind: 'project_ledger_fact', before: 'missing', after: ledgerFact.ledgerRoot, blocking: true, + requiresOperatorApproval: true, issuedAt, - }); + })); continue; } if (projected.projectedLedgerRoot !== ledgerFact.ledgerRoot) { - repairs.push({ - kind: 'btd.ledger_database_projection_repair', - repairId: `${reconciliationId}:${ledgerFact.factId}:ledger_root`, + repairs.push(buildRepairReceipt({ + reconciliationId, factId: ledgerFact.factId, + suffix: 'ledger_root', repairKind: 'ledger_anchor_root', + driftKind: 'ledger_root_mismatch', + repairActionKind: 'project_ledger_fact', before: projected.projectedLedgerRoot, after: ledgerFact.ledgerRoot, blocking: true, + requiresOperatorApproval: true, issuedAt, - }); + })); } if (projected.projectedFinalityState !== ledgerFact.finalityState) { - repairs.push({ - kind: 'btd.ledger_database_projection_repair', - repairId: `${reconciliationId}:${ledgerFact.factId}:finality`, + const finalityBlocks = + ledgerFact.finalityState === 'confirmed' || + ledgerFact.finalityState === 'reorged' || + ledgerFact.finalityState === 'failed'; + repairs.push(buildRepairReceipt({ + reconciliationId, factId: ledgerFact.factId, + suffix: 'finality', repairKind: 'ledger_finality_state', + driftKind: 'ledger_finality_mismatch', + repairActionKind: + ledgerFact.finalityState === 'reorged' || ledgerFact.finalityState === 'failed' + ? 'pause_settlement_unlock' + : 'update_finality_state', before: projected.projectedFinalityState, after: ledgerFact.finalityState, - blocking: - ledgerFact.finalityState === 'confirmed' || - ledgerFact.finalityState === 'reorged' || - ledgerFact.finalityState === 'failed', + blocking: finalityBlocks, + requiresOperatorApproval: finalityBlocks, issuedAt, - }); + })); } } + for (const databaseFact of input.databaseFacts) { + assertDatabaseFact(databaseFact); + if (ledgerFactIds.has(databaseFact.factId)) continue; + repairs.push(buildRepairReceipt({ + reconciliationId, + factId: databaseFact.factId, + suffix: 'orphan_projection', + repairKind: 'terminal_post_state', + driftKind: 'database_orphan_projection', + repairActionKind: 'quarantine_database_projection', + before: databaseFact.projectedLedgerRoot, + after: 'quarantined_until_ledger_observation', + blocking: true, + requiresOperatorApproval: true, + issuedAt, + })); + } + + for (const check of settlementConservationChecks) { + if (isConservationBalanced(check)) continue; + repairs.push(buildRepairReceipt({ + reconciliationId, + factId: check.checkId, + suffix: 'settlement_conservation', + repairKind: 'settlement_conservation', + driftKind: 'settlement_conservation_drift', + repairActionKind: 'pause_settlement_unlock', + before: conservationSnapshot(check, 'expected'), + after: conservationSnapshot(check, 'observed'), + blocking: true, + requiresOperatorApproval: true, + issuedAt, + })); + } + + const repairActions = repairs.map((repair) => buildRepairAction(repair)); + const driftKindCounts = countDriftKinds(repairs); + const settlementConservation = buildSettlementConservationProjection( + reconciliationId, + settlementConservationChecks, + ); + const proofRoots = { + ledgerObservedRoot: stableProofRoot('ledger-observed', input.ledgerFacts), + databaseProjectionRoot: stableProofRoot('database-projected', input.databaseFacts), + metaphysicalCanonicalRoot: stableProofRoot('metaphysical-canonical', metaphysicalFacts), + repairPlanRoot: stableProofRoot('repair-plan', repairs), + settlementConservationRoot: settlementConservation.proofRoot, + }; + const blocking = repairs.some((repair) => repair.blocking); + return { kind: 'btd.ledger_database_reconciliation', reconciliationId, + state: deriveReconciliationState(repairs), repairs, + repairActions, + driftKindCounts, + proofRoots, + settlementConservation, metaphysicalFacts, - blocking: repairs.some((repair) => repair.blocking), + blocking, }; } @@ -128,6 +271,11 @@ function assertLedgerFact(fact: LedgerObservedFact): void { assertNonEmptyString(fact.ledgerRoot, 'ledgerRoot'); } +function assertDatabaseFact(fact: DatabaseProjectedFact): void { + assertNonEmptyString(fact.factId, 'factId'); + assertNonEmptyString(fact.projectedLedgerRoot, 'projectedLedgerRoot'); +} + function assertMetaphysicalFact(fact: MetaphysicalCanonicalFact): MetaphysicalCanonicalFact { assertNonEmptyString(fact.factId, 'factId'); assertNonEmptyString(fact.factKind, 'factKind'); @@ -141,3 +289,187 @@ function assertMetaphysicalFact(fact: MetaphysicalCanonicalFact): MetaphysicalCa return fact; } + +function assertSettlementConservationCheck( + check: SettlementConservationCheck, +): SettlementConservationCheck { + assertNonEmptyString(check.checkId, 'checkId'); + assertNonNegativeSats(check.expectedDebitSats, 'expectedDebitSats'); + assertNonNegativeSats(check.observedDebitSats, 'observedDebitSats'); + assertNonNegativeSats(check.expectedCreditSats, 'expectedCreditSats'); + assertNonNegativeSats(check.observedCreditSats, 'observedCreditSats'); + if (check.feeQuoteRoot !== undefined) assertNonEmptyString(check.feeQuoteRoot, 'feeQuoteRoot'); + if (check.paymentReceiptRoot !== undefined) { + assertNonEmptyString(check.paymentReceiptRoot, 'paymentReceiptRoot'); + } + return check; +} + +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.`); + } +} + +function buildRepairReceipt(input: { + reconciliationId: string; + factId: string; + suffix: string; + repairKind: ProjectionRepairKind; + driftKind: ProjectionDriftKind; + repairActionKind: ProjectionRepairActionKind; + before: string; + after: string; + blocking: boolean; + requiresOperatorApproval: boolean; + issuedAt: string; +}): ProjectionRepairReceipt { + const repairId = `${input.reconciliationId}:${input.factId}:${input.suffix}`; + return { + kind: 'btd.ledger_database_projection_repair', + repairId, + factId: input.factId, + repairKind: input.repairKind, + driftKind: input.driftKind, + repairActionKind: input.repairActionKind, + before: input.before, + after: input.after, + blocking: input.blocking, + requiresOperatorApproval: input.requiresOperatorApproval, + proofRoot: stableProofRoot('projection-repair', [ + repairId, + input.repairKind, + input.driftKind, + input.before, + input.after, + ]), + issuedAt: input.issuedAt, + }; +} + +function buildRepairAction(repair: ProjectionRepairReceipt): ProjectionRepairAction { + return { + actionId: `${repair.repairId}:action:${repair.repairActionKind}`, + repairId: repair.repairId, + factId: repair.factId, + actionKind: repair.repairActionKind, + driftKind: repair.driftKind, + summary: describeRepairAction(repair), + blocking: repair.blocking, + requiresOperatorApproval: repair.requiresOperatorApproval, + proofRoot: stableProofRoot('projection-repair-action', [ + repair.repairId, + repair.repairActionKind, + repair.proofRoot, + ]), + issuedAt: repair.issuedAt, + }; +} + +function describeRepairAction(repair: ProjectionRepairReceipt): string { + switch (repair.repairActionKind) { + case 'project_ledger_fact': + 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 'quarantine_database_projection': + return `Quarantine database projection ${repair.factId} until a matching ledger observation exists.`; + case 'pause_settlement_unlock': + return `Pause settlement unlock for ${repair.factId} until the drift is reconciled.`; + case 'recover_delivery': + return `Recover post-settlement delivery for ${repair.factId}.`; + case 'retry_database_readback': + return `Retry database readback for ${repair.factId}.`; + } +} + +function countDriftKinds(repairs: ProjectionRepairReceipt[]): Record { + const counts: Record = { + missing_database_projection: 0, + ledger_root_mismatch: 0, + ledger_finality_mismatch: 0, + database_orphan_projection: 0, + settlement_conservation_drift: 0, + }; + for (const repair of repairs) { + counts[repair.driftKind] += 1; + } + return counts; +} + +function deriveReconciliationState( + repairs: ProjectionRepairReceipt[], +): LedgerDatabaseReconciliationState { + if (!repairs.length) return 'aligned'; + if ( + repairs.some( + (repair) => + repair.repairActionKind === 'pause_settlement_unlock' || + repair.driftKind === 'settlement_conservation_drift', + ) + ) { + return 'blocked'; + } + if (repairs.some((repair) => repair.requiresOperatorApproval)) return 'approval_required'; + if (repairs.some((repair) => repair.blocking)) return 'repairable'; + return 'retryable'; +} + +function buildSettlementConservationProjection( + reconciliationId: string, + checks: SettlementConservationCheck[], +): SettlementConservationProjection { + const status = !checks.length + ? 'not_checked' + : checks.every(isConservationBalanced) + ? 'balanced' + : 'drifted'; + return { + status, + checks, + proofRoot: stableProofRoot('settlement-conservation', [reconciliationId, checks]), + }; +} + +function isConservationBalanced(check: SettlementConservationCheck): boolean { + return ( + check.expectedDebitSats === check.observedDebitSats && + check.expectedCreditSats === check.observedCreditSats && + check.observedDebitSats === check.observedCreditSats + ); +} + +function conservationSnapshot( + check: SettlementConservationCheck, + side: 'expected' | 'observed', +): string { + if (side === 'expected') { + return `debit:${check.expectedDebitSats};credit:${check.expectedCreditSats}`; + } + return `debit:${check.observedDebitSats};credit:${check.observedCreditSats}`; +} + +function stableProofRoot(scope: string, value: unknown): string { + return `btd-proof-root:${scope}:${stableHash(stableSerialize(value))}`; +} + +function stableSerialize(value: unknown): string { + if (value === null || value === undefined) return String(value); + 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); +} + +function stableHash(value: string): string { + let hash = 2166136261; + for (let index = 0; index < value.length; index += 1) { + hash ^= value.charCodeAt(index); + hash = Math.imul(hash, 16777619); + } + return (hash >>> 0).toString(16).padStart(8, '0'); +} diff --git a/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts b/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts index 5ba358acc..3c3e60bc4 100644 --- a/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts +++ b/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts @@ -204,6 +204,10 @@ describe('asset-pack sandbox harness plan', () => { expect(source).toContain('protectedSourceUnlock'); 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("execution.store('asset-pack/settlement', 'ledgerDatabaseReconciliation'"); + expect(source).toContain('ledgerDatabaseReconciliation,'); + expect(source).toContain('repairActionCount'); expect(source).toContain('ledgerSettlement,'); }); }); diff --git a/packages/pipeline-hosts/src/asset-pack-harness.ts b/packages/pipeline-hosts/src/asset-pack-harness.ts index 209455009..c8a1a23d1 100644 --- a/packages/pipeline-hosts/src/asset-pack-harness.ts +++ b/packages/pipeline-hosts/src/asset-pack-harness.ts @@ -1499,16 +1499,24 @@ async function settleAssetPackLedger(pipelineResultState) { journalEntryIds, depositorWalletId, readerWalletId, - btcFee: { - network: btcNetwork, - requestedNetwork: requestedBtcNetwork, - satsPaid: btcFeeSats, - finalityState: 'prepared', - serverCustody: false, - }, - ownershipBoundary: settlementOwnershipBoundary({ - status: 'settled', - depositorWalletId, + btcFee: { + network: btcNetwork, + requestedNetwork: requestedBtcNetwork, + satsPaid: btcFeeSats, + finalityState: 'prepared', + serverCustody: false, + }, + proofRoots: { + sourceManifestRoot, + measurementReceiptRoot, + fitReceiptRoot, + proofRoot, + settlementJournalRoot, + accessPolicyHash, + }, + ownershipBoundary: settlementOwnershipBoundary({ + status: 'settled', + depositorWalletId, readerWalletId, btcFeeSats, btcNetwork, @@ -1566,10 +1574,12 @@ try { }, { enablePipelineStreaming, factoryPipelineExecution }, { applyAssetPackSettlementUnlockToPreview, buildAssetPackSettlementUnlock }, + { reconcileLedgerDatabaseProjection }, ] = 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'), ]); readingPipelineObservabilityInventory = buildReadingPipelineObservabilityInventory(); resolveReadingPipelineTelemetryProjectionFn = resolveReadingPipelineTelemetryProjection; @@ -1725,6 +1735,85 @@ try { }); const ledgerSettlement = await settleAssetPackLedger(settlementResultState); + const ledgerDatabaseReconciliation = ledgerSettlement?.assetPackId + ? reconcileLedgerDatabaseProjection({ + reconciliationId: 'harness-reconciliation-' + runId, + ledgerFacts: [ + { + factId: ledgerSettlement.assetPackId, + ledgerRoot: ledgerSettlement.proofRoots?.proofRoot || rootOf({ assetPackId: ledgerSettlement.assetPackId }), + finalityState: ledgerSettlement.status === 'settled' ? 'confirmed' : 'failed', + }, + ...(ledgerSettlement.btcFeeReceiptId + ? [{ + factId: ledgerSettlement.btcFeeReceiptId, + ledgerRoot: rootOf({ + btcFeeReceiptId: ledgerSettlement.btcFeeReceiptId, + satsPaid: ledgerSettlement.btcFee?.satsPaid || 0, + finalityState: ledgerSettlement.btcFee?.finalityState || 'prepared', + }), + finalityState: ledgerSettlement.btcFee?.finalityState || 'prepared', + }] + : []), + ...(ledgerSettlement.ledgerAnchorId + ? [{ + factId: ledgerSettlement.ledgerAnchorId, + ledgerRoot: ledgerSettlement.proofRoots?.settlementJournalRoot || ledgerSettlement.ledgerAnchorId, + finalityState: ledgerSettlement.status === 'settled' ? 'confirmed' : 'failed', + }] + : []), + ], + databaseFacts: [ + ...(ledgerSettlement.readback?.assetPackRange + ? [{ + factId: ledgerSettlement.assetPackId, + projectedLedgerRoot: ledgerSettlement.proofRoots?.proofRoot || rootOf({ assetPackId: ledgerSettlement.assetPackId }), + projectedFinalityState: ledgerSettlement.status === 'settled' ? 'confirmed' : 'failed', + }] + : []), + ...(ledgerSettlement.readback?.btcFeeTransaction && ledgerSettlement.btcFeeReceiptId + ? [{ + factId: ledgerSettlement.btcFeeReceiptId, + projectedLedgerRoot: rootOf({ + btcFeeReceiptId: ledgerSettlement.btcFeeReceiptId, + satsPaid: ledgerSettlement.btcFee?.satsPaid || 0, + finalityState: ledgerSettlement.btcFee?.finalityState || 'prepared', + }), + projectedFinalityState: ledgerSettlement.btcFee?.finalityState || 'prepared', + }] + : []), + ...(ledgerSettlement.readback?.ledgerAnchor && ledgerSettlement.ledgerAnchorId + ? [{ + factId: ledgerSettlement.ledgerAnchorId, + projectedLedgerRoot: ledgerSettlement.proofRoots?.settlementJournalRoot || ledgerSettlement.ledgerAnchorId, + projectedFinalityState: ledgerSettlement.status === 'settled' ? 'confirmed' : 'failed', + }] + : []), + ], + settlementConservationChecks: ledgerSettlement.btcFee + ? [{ + checkId: 'btc-fee-conservation-' + runId, + expectedDebitSats: Number(ledgerSettlement.btcFee.satsPaid || 0), + observedDebitSats: ledgerSettlement.readback?.btcFeeTransaction ? Number(ledgerSettlement.btcFee.satsPaid || 0) : 0, + expectedCreditSats: Number(ledgerSettlement.btcFee.satsPaid || 0), + observedCreditSats: ledgerSettlement.readback?.btcFeeTransaction ? Number(ledgerSettlement.btcFee.satsPaid || 0) : 0, + paymentReceiptRoot: ledgerSettlement.btcFeeReceiptId || undefined, + }] + : [], + metaphysicalFacts: [ + { + factId: 'protected-source-boundary-' + runId, + factKind: 'private_source_metadata', + canonicalRoot: ledgerSettlement.proofRoots?.sourceManifestRoot || manifestRoot || rootOf(manifest.sourceRevision || {}), + receiptRoot: ledgerSettlement.proofRoots?.accessPolicyHash || undefined, + private: true, + }, + ], + }) + : null; + if (ledgerDatabaseReconciliation) { + execution.store('asset-pack/settlement', 'ledgerDatabaseReconciliation', ledgerDatabaseReconciliation); + } const settlementUnlock = buildAssetPackSettlementUnlock({ ledgerSettlement, pullRequestTarget: pullRequestUrl || null, @@ -1749,6 +1838,7 @@ try { ledgerSettlement: { ...ledgerSettlement, protectedSourceUnlock: settlementUnlock, + ledgerDatabaseReconciliation, }, }; resultReasons.push(ledgerSettlement.reason); @@ -1763,6 +1853,8 @@ try { status: ledgerSettlement.status, settlementAdmissible: ledgerSettlement.settlementAdmissible, assetPackId: ledgerSettlement.assetPackId || null, + reconciliationState: ledgerDatabaseReconciliation?.state || null, + repairActionCount: ledgerDatabaseReconciliation?.repairActions?.length || 0, }); const readingPipelineObservabilityCoverage = summarizeReadingPipelineObservabilityCoverageFn ? summarizeReadingPipelineObservabilityCoverageFn(events) @@ -1788,6 +1880,7 @@ try { deliveryMechanism: output?.deliveryMechanism || null, shippables: output?.shippables || null, ledgerSettlement: output.ledgerSettlement, + ledgerDatabaseReconciliation, execution: summarizeExecution(execution), readingPipelineObservabilityInventory, readingPipelineObservabilityCoverage, diff --git a/scripts/check-v29-gate6-settlement-reconciliation-repair.mjs b/scripts/check-v29-gate6-settlement-reconciliation-repair.mjs new file mode 100644 index 000000000..8978364a4 --- /dev/null +++ b/scripts/check-v29-gate6-settlement-reconciliation-repair.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-v29-gate6-settlement-reconciliation-repair.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 6 settlement reconciliation and repair closure.', + ].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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 Gate 6 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-6-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 6 work must occur on version/v29 or v29/gate-6-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'scripts/check-v29-gate6-settlement-reconciliation-repair.mjs', + 'packages/btd/src/reconciliation.ts', + 'packages/btd/__tests__/btd.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'packages/api/jest.config.cjs', + 'packages/api/package.json', + '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/app/terminal/README.md', + 'uapi/tests/terminalJournalReconciliation.test.ts', + 'uapi/tests/terminalTransactionDetailCards.test.tsx', + '.github/workflows/bitcode-gate-quality.yml', + 'package.json', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 6 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const reconciliation = read(root, 'packages/btd/src/reconciliation.ts'); + const btdTest = read(root, 'packages/btd/__tests__/btd.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 apiPackageJson = read(root, 'packages/api/package.json'); + 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 terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const terminalTest = read(root, 'uapi/tests/terminalJournalReconciliation.test.ts'); + const terminalCardTest = read(root, 'uapi/tests/terminalTransactionDetailCards.test.tsx'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + assertCheck(failures, spec.includes('V29 settlement reconciliation repair canon'), 'V29 SPEC must define settlement reconciliation repair canon.'); + assertCheck(failures, delta.includes('Closure acceptance') && delta.includes('repairActions'), 'V29 DELTA must define Gate 6 closure acceptance.'); + assertCheck(failures, notes.includes('Gate 6 working notes'), 'V29 NOTES must carry Gate 6 working notes.'); + assertCheck(failures, parity.includes('## Gate 6 Parity'), 'V29 PARITY must include Gate 6 parity.'); + assertCheck(failures, parity.includes('Gate 6 completion condition'), 'V29 PARITY must include Gate 6 completion condition.'); + + for (const symbol of [ + 'ProjectionDriftKind', + 'ProjectionRepairActionKind', + 'LedgerDatabaseReconciliationState', + 'ProjectionRepairAction', + 'SettlementConservationCheck', + 'LedgerDatabaseReconciliationProofRoots', + 'driftKindCounts', + 'repairActions', + 'proofRoots', + 'settlementConservation', + 'missing_database_projection', + 'ledger_root_mismatch', + 'ledger_finality_mismatch', + 'database_orphan_projection', + 'settlement_conservation_drift', + 'pause_settlement_unlock', + 'recover_delivery', + ]) { + assertCheck(failures, reconciliation.includes(symbol), `BTD reconciliation primitive is missing ${symbol}.`); + } + + assertCheck( + failures, + btdTest.includes('ledger/database reconciliation repair') && + btdTest.includes('settlement_conservation_drift') && + btdTest.includes('repairActions') && + btdTest.includes('proofRoots'), + 'BTD tests must cover Gate 6 repair actions, conservation drift, and proof roots.', + ); + assertCheck( + failures, + apiRoute.includes('settlementConservationChecks') && + apiRoute.includes('report.proofRoots.repairPlanRoot') && + apiTest.includes('settlementConservationChecks') && + apiTest.includes('settlement_conservation_drift') && + apiPackageJson.includes('jest --config jest.config.cjs'), + 'BTD API route/tests must accept conservation checks and bind proof roots.', + ); + assertCheck( + failures, + harness.includes('ledgerDatabaseReconciliation') && + harness.includes("execution.store('asset-pack/settlement', 'ledgerDatabaseReconciliation'") && + harness.includes('repairActionCount') && + harnessTest.includes('ledgerDatabaseReconciliation'), + 'Sandbox harness must persist and test reconciliation report evidence.', + ); + assertCheck( + failures, + terminalProjection.includes('repairActions') && + terminalProjection.includes('proofRoots') && + terminalProjection.includes('driftKindCounts') && + terminalProjection.includes('buildSettlementConservationReason') && + terminalProjection.includes('recover_delivery') && + terminalSnapshot.includes('repairActionKind') && + terminalSnapshot.includes('proofRoot'), + 'Terminal projection/snapshot must include repair actions, proof roots, drift classes, and conservation repair posture.', + ); + assertCheck( + failures, + terminalCard.includes('Drift classes') && + terminalCard.includes('Repair actions') && + terminalCard.includes('Proof roots') && + terminalTest.includes('blocks settlement conservation drift') && + terminalTest.includes('recover_delivery') && + terminalCardTest.includes('Repair actions') && + terminalCardTest.includes('Proof roots') && + terminalReadme.includes('settlement reconciliation repair cockpit'), + 'Terminal UI/docs/tests must expose Gate 6 repair visibility.', + ); + assertCheck( + failures, + packageJson.includes('"check:v29-gate6"') && + gateWorkflow.includes('check-v29-gate6-settlement-reconciliation-repair.mjs') && + gateWorkflow.includes('terminalJournalReconciliation.test.ts') && + gateWorkflow.includes('btd-crypto.test.ts'), + 'Package scripts and gate-quality workflow must invoke Gate 6 checker and focused tests.', + ); + + if (failures.length) { + process.stderr.write('V29 Gate 6 check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V29 Gate 6 settlement reconciliation and repair check passed.\n'); +} + +main(); diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 9fee4a1ae..40961b96b 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -132,6 +132,15 @@ prompt/tool/schema posture, and result shape. Expanded metadata remains the 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 +pull-request delivery surface delivery recovery without exposing protected +AssetPack source before payment. + ## Related shared systems - [../../components/base/bitcode/execution/README.md](../../components/base/bitcode/execution/README.md) diff --git a/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx b/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx index 71bdaef21..518cdb13f 100644 --- a/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx +++ b/uapi/app/terminal/TerminalTransactionJournalReconciliationCard.tsx @@ -55,6 +55,19 @@ export default function TerminalTransactionJournalReconciliationCard({
+ {reconciliation.driftKindCounts.length ? ( +
+

+ Drift classes +

+ +
+ ) : null} + {reconciliation.blockingReasons.length ? (

@@ -95,6 +108,28 @@ export default function TerminalTransactionJournalReconciliationCard({ />

+
+

+ Repair actions +

+ +
+ +
+

+ Proof roots +

+ +
+

Repair receipts diff --git a/uapi/app/terminal/terminal-journal-reconciliation.ts b/uapi/app/terminal/terminal-journal-reconciliation.ts index 1008e89f3..edc1493be 100644 --- a/uapi/app/terminal/terminal-journal-reconciliation.ts +++ b/uapi/app/terminal/terminal-journal-reconciliation.ts @@ -34,6 +34,9 @@ export type TerminalJournalReconciliationSnapshot = { canonicalFacts: TerminalJournalReconciliationFact[]; journalEntries: Array<{ id: string; title: string; summary: string; supportingText?: string }>; repairReceipts: Array<{ id: string; title: string; summary: string; supportingText?: string }>; + repairActions: Array<{ id: string; title: string; summary: string; supportingText?: string }>; + proofRoots: Array<{ id: string; title: string; summary: string; supportingText?: string }>; + driftKindCounts: Array<{ label: string; value: string }>; blockingReasons: string[]; payload: unknown; }; @@ -49,6 +52,13 @@ function asNumber(value: unknown) { return typeof value === 'number' && Number.isFinite(value) ? value : null; } +function asIntegerAmount(value: unknown) { + if (typeof value === 'number' && Number.isInteger(value)) return value; + if (typeof value === 'bigint') return Number(value); + if (typeof value === 'string' && /^[0-9]+$/u.test(value)) return Number(value); + return null; +} + function formatBoolean(value: boolean | undefined) { if (value === true) return 'present'; if (value === false) return 'missing'; @@ -226,8 +236,212 @@ function buildRepairItems(repairs: TerminalReconciliationRepairSnapshot[]) { id: repair.repairId, title: repair.blocking ? `${repair.repairKind} blocks projection` : repair.repairKind, summary: `${repair.factId}: ${repair.beforeValue} -> ${repair.afterValue}`, - supportingText: repair.issuedAt || repair.reconciliationId, + supportingText: + repair.proofRoot || + repair.driftKind || + repair.issuedAt || + repair.reconciliationId, + })); +} + +function deriveDriftKind(repair: TerminalReconciliationRepairSnapshot) { + if (repair.driftKind) return repair.driftKind; + if (repair.beforeValue === 'missing') return 'missing_database_projection'; + if (repair.repairKind.includes('finality')) return 'ledger_finality_mismatch'; + if (repair.repairKind.includes('conservation')) return 'settlement_conservation_drift'; + if (repair.afterValue.includes('quarantined')) return 'database_orphan_projection'; + return 'ledger_root_mismatch'; +} + +function deriveRepairActionKind(repair: TerminalReconciliationRepairSnapshot) { + if (repair.repairActionKind) return repair.repairActionKind; + if (repair.afterValue === 'reorged' || repair.afterValue === 'failed') return 'pause_settlement_unlock'; + if (repair.repairKind.includes('conservation')) return 'pause_settlement_unlock'; + if (repair.beforeValue === 'missing') return 'project_ledger_fact'; + if (repair.repairKind.includes('finality')) return 'update_finality_state'; + if (repair.afterValue.includes('quarantined')) return 'quarantine_database_projection'; + return 'project_ledger_fact'; +} + +function summarizeRepairAction(repair: TerminalReconciliationRepairSnapshot) { + const actionKind = deriveRepairActionKind(repair); + switch (actionKind) { + case 'project_ledger_fact': + return `Project ${repair.factId} from ledger observation into the database projection.`; + case 'update_finality_state': + return `Update ${repair.factId} finality from ${repair.beforeValue} to ${repair.afterValue}.`; + case 'quarantine_database_projection': + return `Quarantine ${repair.factId} until a matching ledger observation is available.`; + case 'pause_settlement_unlock': + return `Pause settlement unlock for ${repair.factId} until this drift is resolved.`; + case 'recover_delivery': + return `Recover delivery for ${repair.factId} after settlement state is aligned.`; + case 'retry_database_readback': + return `Retry database readback for ${repair.factId}.`; + default: + return `Repair ${repair.factId}.`; + } +} + +function buildRepairActions( + settlement: TerminalLedgerSettlementSnapshot | null, + journal: TerminalJournalReadbackSnapshot | null, + detail: TerminalRunDetailSnapshot | null, + observedFacts: TerminalJournalReconciliationFact[], + missingJournalEntryIds: string[], +) { + const actions = (journal?.repairs || []).map((repair) => ({ + id: `${repair.repairId}:${deriveRepairActionKind(repair)}`, + title: deriveRepairActionKind(repair), + summary: summarizeRepairAction(repair), + supportingText: + repair.requiresOperatorApproval || repair.blocking + ? 'operator approval required' + : repair.proofRoot || repair.issuedAt || undefined, })); + + for (const entryId of missingJournalEntryIds) { + actions.push({ + id: `${entryId}:retry_database_readback`, + title: 'retry_database_readback', + summary: `Retry Terminal journal readback for expected entry ${entryId}.`, + supportingText: 'missing journal projection', + }); + } + + for (const readError of journal?.readErrors || []) { + actions.push({ + id: `read-error:${actions.length}`, + title: 'retry_database_readback', + summary: readError, + supportingText: 'readback error', + }); + } + + const readback = settlement?.readback || {}; + const btcFeeFinality = observedFacts.find((entry) => entry.id === 'btc-fee-finality')?.state || 'unknown'; + const anchorFinality = observedFacts.find((entry) => entry.id === 'ledger-anchor-finality')?.state || 'unknown'; + if (anchorFinality === 'confirmed' && readback.ledgerAnchor === false) { + actions.push({ + id: `${settlement?.ledgerAnchorId || 'ledger-anchor'}:project_ledger_fact`, + title: 'project_ledger_fact', + summary: 'Project the confirmed ledger anchor into the database before unlock or delivery continues.', + supportingText: 'operator approval required', + }); + } + if (btcFeeFinality === 'confirmed' && readback.btcFeeTransaction === false) { + actions.push({ + id: `${settlement?.btcFeeReceiptId || 'btc-fee'}:project_ledger_fact`, + title: 'project_ledger_fact', + summary: 'Project the confirmed BTC fee transaction into the database before unlock or delivery continues.', + supportingText: 'operator approval required', + }); + } + if ((journal?.entries.length || 0) > 0 && readback.terminalJournal === false) { + actions.push({ + id: 'terminal-journal:project_ledger_fact', + title: 'project_ledger_fact', + summary: 'Project observed Terminal journal entries into the database readback projection.', + supportingText: 'operator approval required', + }); + } + const conservationReason = buildSettlementConservationReason(settlement, journal); + if (conservationReason) { + actions.push({ + id: `${settlement?.btcFeeReceiptId || 'btc-fee'}:pause_settlement_unlock`, + title: 'pause_settlement_unlock', + summary: conservationReason, + supportingText: 'settlement conservation drift', + }); + } + + if ( + settlement?.status === 'settled' && + settlement.settlementAdmissible === true && + Boolean(detail?.deliveryMechanism) && + !detail?.shippables?.pullRequest?.url + ) { + actions.push({ + id: `${settlement.assetPackId || 'asset-pack'}:recover_delivery`, + title: 'recover_delivery', + summary: 'Settlement is aligned, but pull-request delivery is not visible in the transaction detail.', + supportingText: 'delivery recovery', + }); + } + + return actions; +} + +function buildDriftKindCounts( + repairs: TerminalReconciliationRepairSnapshot[], + missingJournalEntryIds: string[], +) { + const counts = new Map(); + for (const repair of repairs) { + const kind = deriveDriftKind(repair); + counts.set(kind, (counts.get(kind) || 0) + 1); + } + if (missingJournalEntryIds.length) { + counts.set( + 'missing_database_projection', + (counts.get('missing_database_projection') || 0) + missingJournalEntryIds.length, + ); + } + return Array.from(counts.entries()) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([label, value]) => ({ label, value: formatCount(value) })); +} + +function uniqueProofRootItems(entries: Array<{ title: string; root: string; supportingText?: string }>) { + const seen = new Set(); + return entries + .filter((entry) => entry.root && entry.root !== 'n/a') + .filter((entry) => { + if (seen.has(entry.root)) return false; + seen.add(entry.root); + return true; + }) + .map((entry, index) => ({ + id: `${entry.title}:${entry.root}:${index}`, + title: entry.title, + summary: entry.root, + supportingText: entry.supportingText, + })); +} + +function buildProofRoots( + journal: TerminalJournalReadbackSnapshot | null, + canonicalFacts: TerminalJournalReconciliationFact[], +) { + const repairRoots = + journal?.repairs.flatMap((repair) => + repair.proofRoot + ? [{ + title: `${deriveDriftKind(repair)} repair root`, + root: repair.proofRoot, + supportingText: repair.repairId, + }] + : [], + ) || []; + const journalRoots = + journal?.entries.flatMap((entry) => [ + { title: 'pre-state root', root: entry.preStateRoot, supportingText: entry.journalEntryId }, + { title: 'post-state root', root: entry.postStateRoot, supportingText: entry.journalEntryId }, + ...entry.receiptRoots.map((root) => ({ + title: 'receipt root', + root, + supportingText: entry.journalEntryId, + })), + ]) || []; + const canonicalRoots = canonicalFacts + .filter((entry) => entry.state === 'root-bound') + .map((entry) => ({ + title: entry.label, + root: entry.value, + supportingText: entry.source, + })); + + return uniqueProofRootItems([...repairRoots, ...journalRoots, ...canonicalRoots]); } function findMissingExpectedJournalEntries(journal: TerminalJournalReadbackSnapshot | null) { @@ -261,6 +475,10 @@ function buildBlockingReasons( if ((journal?.entries.length || 0) > 0 && readback.terminalJournal === false) { reasons.push('Observed Terminal journal entries contradict the missing journal projection.'); } + const settlementConservationReason = buildSettlementConservationReason(settlement, journal); + if (settlementConservationReason) { + reasons.push(settlementConservationReason); + } for (const repair of journal?.repairs || []) { if (repair.blocking) { reasons.push(`Repair ${repair.repairId} blocks ${repair.factId}.`); @@ -273,6 +491,25 @@ function buildBlockingReasons( return reasons; } +function buildSettlementConservationReason( + settlement: TerminalLedgerSettlementSnapshot | null, + journal: TerminalJournalReadbackSnapshot | null, +) { + const quotedSats = + asIntegerAmount(settlement?.btcFee?.sats) ?? + asIntegerAmount(settlement?.btcFee?.satsPaid) ?? + asIntegerAmount(settlement?.btcFee?.sats_paid); + const feeRow = firstRow(journal?.ledgerRows.btcFeeTransactions); + const observedSats = + asIntegerAmount(feeRow?.sats_paid) ?? + asIntegerAmount(feeRow?.satsPaid) ?? + asIntegerAmount(feeRow?.sats) ?? + null; + + if (quotedSats === null || observedSats === null || quotedSats === observedSats) return null; + return `BTC fee sats do not conserve across settlement quote and database readback (${quotedSats} quoted, ${observedSats} observed).`; +} + function deriveState( settlement: TerminalLedgerSettlementSnapshot | null, journal: TerminalJournalReadbackSnapshot | null, @@ -280,7 +517,15 @@ function deriveState( missingJournalEntryIds: string[], ): TerminalJournalReconciliationState { if (!settlement && !journal) return 'unavailable'; - if (blockingReasons.some((reason) => reason.includes('finality is reorged') || reason.includes('finality is failed') || reason.startsWith('Repair '))) { + if ( + blockingReasons.some( + (reason) => + reason.includes('finality is reorged') || + reason.includes('finality is failed') || + reason.includes('do not conserve') || + reason.startsWith('Repair '), + ) + ) { return 'blocked'; } if (blockingReasons.some((reason) => reason.includes('Confirmed') || reason.includes('Observed Terminal journal'))) { @@ -325,6 +570,15 @@ export function buildTerminalJournalReconciliation( blockingReasons.push(`Missing Terminal journal entries: ${missingJournalEntryIds.join(', ')}`); } const state = deriveState(settlement, journal, blockingReasons, missingJournalEntryIds); + const repairActions = buildRepairActions( + settlement, + journal, + detail, + observedFacts, + missingJournalEntryIds, + ); + const proofRoots = buildProofRoots(journal, canonicalFacts); + const driftKindCounts = buildDriftKindCounts(journal?.repairs || [], missingJournalEntryIds); return { state, @@ -338,12 +592,17 @@ export function buildTerminalJournalReconciliation( { 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: 'Repair actions', value: formatCount(repairActions.length) }, + { label: 'Proof roots', value: formatCount(proofRoots.length) }, ], observedFacts, projectedFacts, canonicalFacts, journalEntries: buildJournalItems(journal?.entries || []), repairReceipts: buildRepairItems(journal?.repairs || []), + repairActions, + proofRoots, + driftKindCounts, blockingReasons, payload: { ledgerSettlement: settlement, @@ -352,6 +611,9 @@ export function buildTerminalJournalReconciliation( projectedFacts, canonicalFacts, missingJournalEntryIds, + repairActions, + proofRoots, + driftKindCounts, blockingReasons, }, }; diff --git a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts index bedcc165c..79dc7f4a1 100644 --- a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts +++ b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts @@ -78,9 +78,13 @@ export type TerminalReconciliationRepairSnapshot = { reconciliationId: string; factId: string; repairKind: string; + driftKind: string | null; + repairActionKind: string | null; beforeValue: string; afterValue: string; blocking: boolean; + requiresOperatorApproval: boolean; + proofRoot: string | null; issuedAt: string | null; raw: TerminalJsonRecord; }; @@ -386,9 +390,13 @@ function coerceRepairReceipt(value: unknown): TerminalReconciliationRepairSnapsh reconciliationId: coerceString(value.reconciliation_id) || coerceString(value.reconciliationId) || 'n/a', factId: coerceString(value.fact_id) || coerceString(value.factId) || 'n/a', repairKind: coerceString(value.repair_kind) || coerceString(value.repairKind) || 'n/a', + driftKind: coerceString(value.drift_kind) || coerceString(value.driftKind), + repairActionKind: coerceString(value.repair_action_kind) || coerceString(value.repairActionKind), beforeValue: coerceString(value.before_value) || coerceString(value.beforeValue) || 'n/a', afterValue: coerceString(value.after_value) || coerceString(value.afterValue) || 'n/a', blocking: Boolean(value.blocking), + requiresOperatorApproval: Boolean(value.requires_operator_approval || value.requiresOperatorApproval), + proofRoot: coerceString(value.proof_root) || coerceString(value.proofRoot), issuedAt: coerceString(value.issued_at) || coerceString(value.issuedAt), raw: value, }; diff --git a/uapi/tests/terminalJournalReconciliation.test.ts b/uapi/tests/terminalJournalReconciliation.test.ts index 6a812aaad..876c8f2c7 100644 --- a/uapi/tests/terminalJournalReconciliation.test.ts +++ b/uapi/tests/terminalJournalReconciliation.test.ts @@ -86,6 +86,10 @@ describe('terminal journal reconciliation', () => { expect(result.projectedFacts.every((fact) => fact.source === 'database_projected')).toBe(true); expect(result.canonicalFacts.every((fact) => fact.source === 'metaphysical_canonical')).toBe(true); 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']), + ); }); it('requires approval when confirmed ledger facts contradict database projection', () => { @@ -139,6 +143,14 @@ describe('terminal journal reconciliation', () => { expect(result.state).toBe('approval_required'); expect(result.blockingReasons).toContain('Confirmed ledger anchor contradicts the missing database projection.'); + expect(result.repairActions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + title: 'project_ledger_fact', + supportingText: 'operator approval required', + }), + ]), + ); }); it('blocks reorged or failed ledger facts and surfaces repair receipts', () => { @@ -170,9 +182,13 @@ describe('terminal journal reconciliation', () => { reconciliationId: 'reconciliation-run-3', factId: 'btc-fee-run-3', repairKind: 'fee_finality_repair', + driftKind: 'ledger_finality_mismatch', + repairActionKind: 'pause_settlement_unlock', beforeValue: 'confirmed', afterValue: 'reorged', blocking: true, + requiresOperatorApproval: true, + proofRoot: 'btd-proof-root:projection-repair:fee-finality', issuedAt: '2026-05-18T12:30:00.000Z', raw: {}, }, @@ -191,6 +207,11 @@ describe('terminal journal reconciliation', () => { expect(result.state).toBe('blocked'); expect(result.repairReceipts[0].title).toBe('fee_finality_repair blocks projection'); + expect(result.repairActions[0]).toMatchObject({ + title: 'pause_settlement_unlock', + supportingText: 'operator approval required', + }); + expect(result.driftKindCounts).toContainEqual({ label: 'ledger_finality_mismatch', value: '1' }); expect(result.blockingReasons).toEqual( expect.arrayContaining([ 'BTC fee finality is reorged; database projection cannot unlock until repaired.', @@ -198,4 +219,53 @@ describe('terminal journal reconciliation', () => { ]), ); }); + + it('blocks settlement conservation drift and surfaces delivery recovery', () => { + const result = buildTerminalJournalReconciliation( + detail({ + ledgerSettlement: { + status: 'settled', + settlementAdmissible: true, + reason: 'fee readback drift', + assetPackId: 'asset-pack-run-4', + btdRange: null, + ledgerAnchorId: 'ledger-anchor-run-4', + btcFeeReceiptId: 'btc-fee-run-4', + depositorWalletId: null, + readerWalletId: null, + btcFee: { finalityState: 'confirmed', sats: 1200 }, + ownershipBoundary: null, + readback: { btcFeeTransaction: true, terminalJournal: true }, + journalEntryIds: [], + ownershipEventId: null, + readLicenseId: 'read-license-run-4', + }, + deliveryMechanism: { pullRequest: null, summary: 'Delivery evidence exists without visible PR.' }, + terminalJournal: { + expectedJournalEntryIds: [], + entries: [], + repairs: [], + ledgerRows: { + assetPackRanges: [], + btcFeeTransactions: [{ receipt_id: 'btc-fee-run-4', finality_state: 'confirmed', sats_paid: '1000' }], + ledgerAnchors: [], + ownershipEvents: [], + readLicenses: [], + }, + readErrors: [], + }, + }), + ); + + expect(result.state).toBe('blocked'); + expect(result.blockingReasons).toContain( + 'BTC fee sats do not conserve across settlement quote and database readback (1200 quoted, 1000 observed).', + ); + expect(result.repairActions).toEqual( + expect.arrayContaining([ + expect.objectContaining({ title: 'pause_settlement_unlock' }), + expect.objectContaining({ title: 'recover_delivery' }), + ]), + ); + }); }); diff --git a/uapi/tests/terminalTransactionDetailCards.test.tsx b/uapi/tests/terminalTransactionDetailCards.test.tsx index 51ed7c526..2b949c0c0 100644 --- a/uapi/tests/terminalTransactionDetailCards.test.tsx +++ b/uapi/tests/terminalTransactionDetailCards.test.tsx @@ -140,6 +140,22 @@ describe('Terminal transaction detail cards', () => { }, ], repairReceipts: [], + repairActions: [ + { + id: 'ledger-anchor-run-1:project_ledger_fact', + title: 'project_ledger_fact', + summary: 'Project the confirmed ledger anchor into the database.', + supportingText: 'operator approval required', + }, + ], + proofRoots: [ + { + id: 'settlement-journal-root:sha256:journal', + title: 'Settlement journal root', + summary: 'sha256:journal', + }, + ], + driftKindCounts: [{ label: 'missing_database_projection', value: '1' }], blockingReasons: ['Confirmed ledger anchor contradicts the missing database projection.'], payload: { observedFacts: ['ledger-anchor-finality'], @@ -156,6 +172,8 @@ describe('Terminal transaction detail cards', () => { expect(screen.getByText('Journal reconciliation')).toBeTruthy(); expect(screen.getByText('Ledger observations and database projections')).toBeTruthy(); expect(screen.getByText('Metaphysical canonical facts')).toBeTruthy(); + expect(screen.getByText('Repair actions')).toBeTruthy(); + expect(screen.getByText('Proof roots')).toBeTruthy(); expect(screen.getAllByText('Structured payload shape').length).toBeGreaterThanOrEqual(3); expect(screen.getAllByText('selection-materialization').length).toBeGreaterThan(0); expect(screen.getAllByText('run-001').length).toBeGreaterThan(0); From 73c62e4b8f20b6fa3a3ca990185a908b46d2a473 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 11:59:10 -0300 Subject: [PATCH 07/18] V29 Gate 7: Close organization interface authority (#26) Adds package-owned BTD organization/interface authority decisions with holdings, read-license usage, source visibility, and proof roots. Wires JSON-safe API/UAPI decisions, MCP required interface authority, ChatGPT App write admission, sandbox harness evidence, and Terminal Authority detail projection. Updates V29 spec/parity/docs, gate-quality CI, Gate 7 checker, lockfile, and focused BTD/API/MCP/ChatGPT/pipeline-host/UAPI coverage. --- .github/workflows/bitcode-gate-quality.yml | 7 + BITCODE_SPEC_V29.md | 34 + BITCODE_SPEC_V29_DELTA.md | 11 + BITCODE_SPEC_V29_NOTES.md | 20 + BITCODE_SPEC_V29_PARITY_MATRIX.md | 38 +- package.json | 1 + .../src/routes/__tests__/btd-crypto.test.ts | 95 +++ packages/api/src/routes/btd-crypto.ts | 74 +++ packages/btd/__tests__/btd.test.ts | 140 +++++ packages/btd/src/authority.ts | 595 ++++++++++++++++++ packages/btd/src/index.ts | 1 + packages/chatgptapp/jest.config.cjs | 1 + packages/chatgptapp/package.json | 4 +- .../chatgptapp/src/__tests__/tools.test.ts | 57 ++ packages/chatgptapp/src/tools.ts | 179 +++++- packages/chatgptapp/tsconfig.json | 3 +- packages/chatgptapp/tsconfig.test.json | 1 + .../src/mcp-server/jest.config.mcp.js | 75 +++ .../src/__tests__/unit/auth.test.ts | 159 +++++ .../src/mcp-server/src/auth/middleware.ts | 130 +++- .../src/mcp-server/src/types/index.ts | 8 + .../src/__tests__/asset-pack-harness.test.ts | 4 + .../pipeline-hosts/src/asset-pack-harness.ts | 49 +- pnpm-lock.yaml | 14 +- ...ate7-organization-permission-authority.mjs | 257 ++++++++ .../organization-interface-authority/route.ts | 3 + uapi/app/terminal/README.md | 8 + .../TerminalTransactionDetailActionBar.tsx | 1 + .../TerminalTransactionDetailSurface.tsx | 13 + ...alTransactionOrganizationAuthorityCard.tsx | 66 ++ .../terminal-organization-authority.ts | 138 ++++ .../terminal/terminal-protocol-projection.ts | 1 + .../terminal-transaction-detail-snapshot.ts | 23 + .../terminal/terminal-transaction-query.ts | 2 + .../terminal-transaction-read-model.ts | 21 + uapi/jest.config.cjs | 1 + .../terminalJournalReconciliation.test.ts | 1 + .../terminalOrganizationAuthority.test.ts | 74 +++ ...erminalTransactionActivitySurface.test.tsx | 1 + uapi/tests/terminalTransactionDetail.test.ts | 1 + .../terminalTransactionDetailCards.test.tsx | 40 ++ .../terminalTransactionDetailSnapshot.test.ts | 23 + .../terminalTransactionReadModel.test.ts | 1 + uapi/tests/terminalWalletBtcOperation.test.ts | 1 + 44 files changed, 2339 insertions(+), 37 deletions(-) create mode 100644 packages/btd/src/authority.ts create mode 100644 packages/executions-mcp/src/mcp-server/jest.config.mcp.js create mode 100644 scripts/check-v29-gate7-organization-permission-authority.mjs create mode 100644 uapi/app/api/btd/organization-interface-authority/route.ts create mode 100644 uapi/app/terminal/TerminalTransactionOrganizationAuthorityCard.tsx create mode 100644 uapi/app/terminal/terminal-organization-authority.ts create mode 100644 uapi/tests/terminalOrganizationAuthority.test.ts diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 4a78cf43a..3c87202f0 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -68,6 +68,7 @@ jobs: node scripts/check-v29-gate4-reading-pipeline-observability.mjs --skip-branch-check node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs --skip-branch-check node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs --skip-branch-check + node scripts/check-v29-gate7-organization-permission-authority.mjs --skip-branch-check - name: Validate source casing and imports run: | @@ -78,6 +79,8 @@ jobs: run: | pnpm --filter @bitcode/btd typecheck pnpm --filter @bitcode/api build + pnpm --dir packages/executions-mcp/src/mcp-server run type-check + pnpm --dir packages/chatgptapp exec tsc --noEmit --pretty false pnpm --filter @bitcode/pipeline-asset-pack typecheck pnpm --filter @bitcode/pipeline-hosts typecheck @@ -87,6 +90,8 @@ jobs: pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btc-fee-operation.test.ts pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btd.test.ts pnpm --filter @bitcode/api exec jest --config jest.config.cjs --runTestsByPath src/routes/__tests__/btd-crypto.test.ts --runInBand + pnpm --dir packages/executions-mcp/src/mcp-server run test:mcp -- --runTestsByPath src/__tests__/unit/auth.test.ts --runInBand + pnpm --dir packages/chatgptapp exec jest --runTestsByPath src/__tests__/tools.test.ts --runInBand pnpm --filter @bitcode/pipeline-hosts exec jest --config jest.config.cjs --runTestsByPath src/__tests__/asset-pack-harness.test.ts --runInBand pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --passWithNoTests --forceExit pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath src/__tests__/reading-pipeline-observability.test.ts src/__tests__/reading-pipeline-contract.test.ts --runInBand @@ -104,7 +109,9 @@ jobs: tests/terminalTransactionReadModel.test.ts \ tests/terminalWalletBtcOperation.test.ts \ tests/terminalJournalReconciliation.test.ts \ + tests/terminalOrganizationAuthority.test.ts \ tests/terminalTransactionDetailCards.test.tsx \ + tests/terminalTransactionDetailSnapshot.test.ts \ tests/pipelineExecutionLogHeader.test.tsx \ --runInBand diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index b76b2610b..26a5e7530 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -369,6 +369,40 @@ Gate PRs into version branches must begin with the uppercase version and gate pr - 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 V29 only when tied to Terminal transaction operation. +#### V29 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. diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index 625dd0d11..a6549ad17 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -154,6 +154,17 @@ Closure acceptance: Gate 7 owns organization holdings, roles, read-license usage, registry-derived permission decisions, MCP/ChatGPT action authority alignment, and Terminal permission explainers. +Closure acceptance: + +- `packages/btd/src/authority.ts` defines the shared organization/interface authority primitive, action requirements, registry holdings/read-license summary, source visibility, and proof roots. +- BTD tests prove organization holdings, active/expired/revoked read-license usage, paid delivery admission, unpaid unlock denial, and unsupported ChatGPT administration denial. +- `packages/api/src/routes/btd-crypto.ts` exposes JSON-safe organization authority decisions and `uapi/app/api/btd/organization-interface-authority/route.ts` binds the route. +- MCP auth can require interface authority after registry-derived owner-read or licensed-read evidence. +- ChatGPT App connected-interface write carriers require explicit confirmation, registry read-access evidence, and organization authority evidence before write execution. +- The sandbox harness emits `organizationAuthority` evidence alongside settlement unlock and ledger/database reconciliation. +- Terminal adds an Authority detail section rendering decision rows, blockers, and proof roots from the same payload. +- `pnpm run check:v29-gate7` passes with focused BTD, API, MCP, ChatGPT App, pipeline-hosts, and UAPI tests. + ### Gate 8: Demonstration-Origin Commercial Formalization Gate 8 owns cleanup of freshly ported demonstration-origin internals into package-native APIs, no demonstration runtime imports, durable package tests, and updated internal/public documentation. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 3c25ca295..1356628cd 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -168,6 +168,26 @@ Operator notes: - Terminal journal detail is the ordinary repair cockpit for this gate: drift classes, blockers, repair actions, proof roots, journal entries, and repair receipts must be visible without opening network logs. - Raw payload remains audit material, not the primary operator interface. +## Gate 7 working notes + +Gate 7 makes organization authority package-owned and interface-shared. + +Accepted Gate 7 posture: + +- BTD authority evaluates Terminal, API, MCP, and ChatGPT App surfaces against the same action requirement table. +- Registry-derived organization holdings and read-license usage are summarized as authority evidence, not aggregate spendable balance. +- Protected-source actions require owner-read or licensed-read access plus settled payment where the action crosses the source boundary. +- ChatGPT App writes remain impossible without explicit user confirmation, read-access evidence, and organization authority evidence. +- MCP can request interface authority after its existing permission and read-access checks. +- Terminal exposes authority as a normal selected-activity detail section with collapsed metrics, blockers, decision rows, proof roots, and raw payload. +- Sandbox harness output carries `organizationAuthority` so staging-testnet Reading runs can be debugged from Terminal. + +Gate 7 completion condition: + +- `pnpm run check:v29-gate7` passes. +- Focused BTD, API, MCP, ChatGPT App, pipeline-hosts, and UAPI tests cover the authority primitive and interface surfaces. +- Spec, delta, notes, parity, Terminal README, package scripts, and gate-quality workflow name the Gate 7 closure surface. + ## Later-version boundaries - V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 30c29eae4..ff8dcf814 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -54,7 +54,7 @@ No `_legacy/` source is active source truth. | Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack/src/reading-pipeline-observability.ts`, `packages/pipeline-hosts/src/asset-pack-harness.ts`, Terminal stream components, Gate 4 checker | drafted | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt/raw-output/parsed-output telemetry is contract-projected, complete, and readable. | | AssetPack disclosure rights | Gate 5 | `asset-pack-disclosure.ts`, AssetPack postprocess, sandbox harness, BTD access tests, Terminal disclosure review UI, Gate 5 checker | drafted | Source-safe preview and paid unlock are proven without protected-source leakage. | | Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, sandbox harness settlement evidence, Terminal repair UI, Gate 6 checker | drafted | Ledger, database, and metaphysical state drift is classified, proof-rooted, repair-actioned, and visible. | -| Organization permission authority | Gate 7 | access policy, org holdings, MCP/ChatGPT gates, Terminal permission UI | pending | Registry-derived roles, holdings, and read-license authority govern actions. | +| Organization permission authority | Gate 7 | `packages/btd/src/authority.ts`, BTD/API/MCP/ChatGPT App tests, sandbox harness authority evidence, Terminal Authority section, Gate 7 checker | drafted | Registry-derived roles, holdings, read-license authority, settlement, confirmation, and interface admission govern actions. | | Commercial formalization | Gate 8 | packages/protocol, package tests, import scans, docs | pending | Demonstration-origin commercial internals are package-native and no runtime demo imports remain. | | Terminal UX quality | Gate 9 | Playwright/Jest/a11y/responsive/browser QA | pending | Complete transaction cockpit is usable by default and inspectable in detail. | | Promotion readiness | Gate 10 | promotion workflow, `.bitcode/v29-*`, `BITCODE_SPEC_V29_PROVEN.md` | pending | `version/v29` can promote to `main` only after all V29 checks pass. | @@ -71,7 +71,8 @@ No `_legacy/` source is active source truth. | Gate 3 wallet/BTC operation | `pnpm run check:v29-gate3` proves quote lifecycle, signer recovery, blocked readiness, API posture, and Terminal Wallet/BTC detail | drafted | | Gate 4 Reading observability | `pnpm run check:v29-gate4` proves contract-aware Reading stream telemetry and Terminal rendering | drafted | | Gate 5 AssetPack disclosure | `pnpm run check:v29-gate5` proves source-safe disclosure review, leakage detection, Terminal preview rendering, and PR title enforcement | drafted | -| Product implementation gates | Gates 6-9 close remaining Terminal transaction depth with tests and docs | pending | +| Gate 7 organization authority | `pnpm run check:v29-gate7` proves shared org/interface authority across BTD, API, MCP, ChatGPT App, harness, and Terminal | drafted | +| Product implementation gates | Gates 8-9 close remaining Terminal transaction depth with tests and docs | pending | | Promotion gate | Gate 10 closes generated proof and promotion automation | pending | ## Gate 1 Parity @@ -207,10 +208,37 @@ Gate 6 completion condition: - `pnpm run check:v29-gate6` passes. - Focused BTD, API, pipeline-hosts, and UAPI tests prove repair classification, conservation drift, proof roots, and Terminal repair visibility. -- Gate 5 does not implement organization authority beyond read-right state distinctions; Gate 7 owns registry-derived roles and holdings. -- Gate 5 does not add browser proof or full UX polish; Gate 9 owns that surface. -- Gate 5 does not add versioned API routes or source identifiers. ## Gate 5 completion condition Gate 5 is complete when AssetPack disclosure review is package-owned, postprocess and sandbox harness evidence include source-safe disclosure review roots, protected-source leakage tests fail closed, Terminal renders the disclosure review through the Reading preview surface, gate PR title enforcement is active, focused package and UAPI tests pass, `check:v29-gate5` passes, CI invokes the checker and tests, docs name the implemented source surfaces, and the gate branch is committed and pushed for review into `version/v29`. + +## Gate 7 Parity + +Gate 7 closes the organization authority slice by making action permission a shared BTD decision instead of interface-local convention. + +Accepted surfaces: + +- `packages/btd/src/authority.ts` is the canonical organization/interface authority primitive for role checks, explicit grants, wallet binding, registry read access, settlement, explicit confirmation, repair approval, source visibility, and authority proof roots. +- `packages/api/src/routes/btd-crypto.ts` and `uapi/app/api/btd/organization-interface-authority/route.ts` expose JSON-safe authority decisions for application routes. +- `packages/executions-mcp/src/mcp-server/src/auth/middleware.ts` can require interface authority after existing permission and BTD read-access checks. +- `packages/chatgptapp/src/tools.ts` requires explicit confirmation, registry read-access evidence, and organization authority evidence before connected-interface writes. +- `packages/pipeline-hosts/src/asset-pack-harness.ts` stores and emits `organizationAuthority` beside settlement unlock and reconciliation evidence. +- `uapi/app/terminal/terminal-organization-authority.ts` and `TerminalTransactionOrganizationAuthorityCard.tsx` project the selected transaction into authority metrics, blockers, decision rows, proof roots, and raw payload. + +Accepted failure states: + +- Missing role, insufficient role, or missing explicit grant blocks authority. +- Missing wallet binding blocks fee payment, source unlock, and delivery when those actions require Reader wallet proof. +- Missing or denied registry read access blocks protected-source unlock and delivery. +- Pending settlement blocks protected-source visibility even when role evidence exists. +- Missing explicit confirmation blocks payment, delivery, repair, and administration actions that cross sensitive boundaries. +- Interfaces may deny actions even when the organization role could authorize them elsewhere. + +Gate 7 completion condition: + +- `pnpm run check:v29-gate7` passes. +- Focused BTD, API, MCP, ChatGPT App, pipeline-hosts, and UAPI tests prove organization holdings, active/expired/revoked license usage, paid delivery admission, unpaid denial, interface denial, connected-interface write gating, harness evidence, and Terminal visibility. +- Gate-quality CI invokes the Gate 7 checker and focused tests. +- Gate 7 does not add broad enterprise RBAC administration beyond Terminal transaction authority; later versions may deepen team policy authoring. +- Gate 7 does not reveal protected source before settlement and does not add versioned API routes or source identifiers. diff --git a/package.json b/package.json index b85fd78a0..1b751773d 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "check:v29-gate4": "node scripts/check-v29-gate4-reading-pipeline-observability.mjs", "check:v29-gate5": "node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs", "check:v29-gate6": "node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs", + "check:v29-gate7": "node scripts/check-v29-gate7-organization-permission-authority.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 6368d585e..8be25a2c5 100644 --- a/packages/api/src/routes/__tests__/btd-crypto.test.ts +++ b/packages/api/src/routes/__tests__/btd-crypto.test.ts @@ -22,6 +22,7 @@ import { buildBtdLedgerDatabaseReconciliationSettlement, buildBtdLicensedReadRevenueSettlement, buildBtdMintDraft, + buildBtdOrganizationInterfaceAuthorityDecision, buildBtdReadAccessDecision, buildBtdTerminalJournalSettlement, buildGetBtdRegistrySnapshotRoute, @@ -33,6 +34,7 @@ import { buildPostBtdLedgerDatabaseReconciliationRoute, buildPostBtdLicensedReadRevenueRoute, buildPostBtdMintDraftRoute, + buildPostBtdOrganizationInterfaceAuthorityRoute, buildPostBtdReadAccessRoute, buildPostBtdTerminalJournalRoute, } from '../btd-crypto'; @@ -463,6 +465,99 @@ describe('BTD crypto API builders', () => { expect((await mismatchResponse.json()).decision.reason).toBe('policy_mismatch'); }); + it('builds organization interface authority decisions with source visibility and proof roots', () => { + const decision = buildBtdOrganizationInterfaceAuthorityDecision({ + actorId: 'user-1', + organizationId: 'org-api-1', + organizationRole: 'admin', + organizationPermissionGrants: ['asset_pack:deliver'], + interfaceSurface: 'mcp', + action: 'deliver_asset_pack', + walletId: 'wallet-reader', + settlementState: 'settled', + confirmed: true, + targetAnchor: 'github:engineeredsoftware/ENGI/pull/42', + readAccessDecision: { + decision: 'owner_read', + accessPolicyHash: 'policy-api-hash', + reason: 'wallet_owns_policy_matching_range', + }, + at: issuedAt, + }); + + expect(decision).toMatchObject({ + routeKind: 'btd_organization_interface_authority_route_decision', + kind: 'btd_organization_interface_authority_decision', + decision: 'allowed', + interfaceSurface: 'mcp', + action: 'deliver_asset_pack', + sourceVisibility: 'protected_source_allowed', + reason: 'role_authorized', + }); + expect(decision.reasons).toEqual(expect.arrayContaining(['owner_read_access_authorized'])); + expect(decision.proofRoots.authorityRoot).toMatch(/^btd-proof-root:organization-interface-authority:/); + }); + + it('returns JSON-safe organization interface authority decisions from the route boundary', async () => { + const route = buildPostBtdOrganizationInterfaceAuthorityRoute({ + resolveAuthenticatedUser: async () => ({ userId: 'user-1' }), + }); + const response = await route( + new Request('https://bitcode.test/api/btd/organization-interface-authority', { + method: 'POST', + body: JSON.stringify({ + organizationId: 'org-api-1', + organizationRole: 'member', + organizationPermissionGrants: ['reading:request_finding_fits'], + interfaceSurface: 'terminal', + action: 'request_finding_fits', + at: issuedAt, + }), + }), + ); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body.routeKind).toBe('btd_organization_interface_authority_route_decision'); + expect(body.decision).toBe('allowed'); + expect(body.sourceVisibility).toBe('source_safe_preview'); + expect(body.satisfied.role).toBe(true); + expect(body.proofRoots.interfaceRoot).toMatch(/^btd-proof-root:interface-authority:/); + }); + + it('keeps organization authority denials explicit at the route boundary', async () => { + const route = buildPostBtdOrganizationInterfaceAuthorityRoute({ + resolveAuthenticatedUser: async () => ({ userId: 'user-1' }), + }); + const response = await route( + new Request('https://bitcode.test/api/btd/organization-interface-authority', { + method: 'POST', + body: JSON.stringify({ + organizationId: 'org-api-1', + organizationRole: 'viewer', + interfaceSurface: 'chatgpt_app', + action: 'deliver_asset_pack', + settlementState: 'pending', + confirmed: false, + at: issuedAt, + }), + }), + ); + const body = await response.json(); + + expect(response.status).toBe(200); + expect(body.decision).toBe('denied'); + expect(body.reasons).toEqual( + expect.arrayContaining([ + 'role_insufficient', + 'wallet_binding_missing', + 'registry_read_access_required', + 'settlement_required', + 'explicit_confirmation_required', + ]), + ); + }); + it('builds licensed-read revenue settlement receipts with holdback and route state', () => { const settlement = buildBtdLicensedReadRevenueSettlement({ actorId: 'user-1', diff --git a/packages/api/src/routes/btd-crypto.ts b/packages/api/src/routes/btd-crypto.ts index 1e5834cb1..7a65ced3f 100644 --- a/packages/api/src/routes/btd-crypto.ts +++ b/packages/api/src/routes/btd-crypto.ts @@ -13,8 +13,13 @@ import { 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, @@ -69,6 +74,7 @@ import { createAssetPackExchangeOrder, createBtdMeasureMintState, createBtdSupplyState, + evaluateBtdOrganizationInterfaceAuthority, evaluateBtdReadAccess, measureProofAddressableSemanticVolume, reviewBtdAncestorEdges, @@ -152,6 +158,27 @@ export interface BtdReadAccessDecision { }; } +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; @@ -610,6 +637,20 @@ export function buildBtdReadAccessDecision( }; } +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 { @@ -1188,6 +1229,37 @@ export function buildPostBtdReadAccessRoute(options: BtdRouteOptions = {}) { }); } +export function buildPostBtdOrganizationInterfaceAuthorityRoute( + options: BtdRouteOptions = {}, +) { + return traceRoute('/btd/organization-interface-authority', async (request: Request) => { + const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( + request, + ); + if (!user) { + return createJsonResponse({ error: 'Unauthorized' }, 401); + } + + let body: BtdOrganizationInterfaceAuthorityInput; + try { + body = await request.json(); + } catch { + return createJsonResponse({ error: 'Invalid JSON body' }, 400); + } + + try { + const decision = buildBtdOrganizationInterfaceAuthorityDecision({ + ...body, + actorId: user.userId, + }); + + return createJsonResponse(toJsonSafe(decision)); + } catch (error) { + return createJsonResponse({ error: toBadRequestMessage(error) }, 400); + } + }); +} + export function buildPostBtdLicensedReadRevenueRoute(options: BtdRouteOptions = {}) { return traceRoute('/btd/licensed-read-revenue', async (request: Request) => { const user = await (options.resolveAuthenticatedUser ?? defaultResolveAuthenticatedUser)( @@ -1558,6 +1630,8 @@ export function buildPostBtdDeploymentReadinessRoute(options: BtdRouteOptions = export const getBtdRegistrySnapshot = buildGetBtdRegistrySnapshotRoute(); export const postBtdMintDraft = buildPostBtdMintDraftRoute(); export const postBtdReadAccess = buildPostBtdReadAccessRoute(); +export const postBtdOrganizationInterfaceAuthority = + buildPostBtdOrganizationInterfaceAuthorityRoute(); export const postBtdLicensedReadRevenue = buildPostBtdLicensedReadRevenueRoute(); export const postBtdAncestryReview = buildPostBtdAncestryReviewRoute(); export const postBtdBtcFeeTransaction = buildPostBtdBtcFeeTransactionRoute(); diff --git a/packages/btd/__tests__/btd.test.ts b/packages/btd/__tests__/btd.test.ts index 026f23efc..760044b8b 100644 --- a/packages/btd/__tests__/btd.test.ts +++ b/packages/btd/__tests__/btd.test.ts @@ -16,9 +16,11 @@ import { buildBtdReadAccessProjectionFromRegistryRows, calculateLlmBtcFeeEstimate, calculateMeasuredBtdFromTokens, + evaluateBtdOrganizationInterfaceAuthority, evaluateBtdReadAccess, listBtdAccessPolicyTemplates, reconcileLedgerDatabaseProjection, + summarizeBtdOrganizationRegistryAuthority, } from '../src'; describe('calculateLlmBtcFeeEstimate', () => { @@ -384,3 +386,141 @@ describe('registry-derived read access projection', () => { }); }); }); + +describe('organization interface authority', () => { + it('summarizes organization holdings and read-license usage from registry rows', () => { + const summary = summarizeBtdOrganizationRegistryAuthority({ + organizationId: 'org-1', + walletIds: ['wallet-owner', 'wallet-reader', 'wallet-reader'], + ownershipRows: [ + { + to_wallet_id: 'wallet-owner', + asset_pack_id: 'asset-pack-1', + range_start: 0, + range_end_exclusive: 7, + }, + ], + readLicenseRows: [ + { + license_id: 'license-active', + wallet_id: 'wallet-reader', + asset_pack_id: 'asset-pack-2', + valid_from: '2026-05-01T00:00:00.000Z', + }, + { + license_id: 'license-expired', + wallet_id: 'wallet-reader', + asset_pack_id: 'asset-pack-3', + valid_from: '2026-04-01T00:00:00.000Z', + expires_at: '2026-05-02T00:00:00.000Z', + }, + { + license_id: 'license-revoked', + wallet_id: 'wallet-reader', + asset_pack_id: 'asset-pack-4', + valid_from: '2026-04-01T00:00:00.000Z', + revoked_at: '2026-05-03T00:00:00.000Z', + }, + ], + at: '2026-05-19T00:00:00.000Z', + }); + + expect(summary).toMatchObject({ + organizationId: 'org-1', + source: 'btd_registry', + walletIds: ['wallet-owner', 'wallet-reader'], + ownedCellCount: 7, + ownedAssetPackIds: ['asset-pack-1'], + readLicenseCount: 3, + activeReadLicenseCount: 1, + expiredReadLicenseCount: 1, + revokedReadLicenseCount: 1, + licensedAssetPackIds: ['asset-pack-2'], + }); + expect(summary.authorityRoot).toMatch(/^btd-proof-root:organization-registry-authority:/); + }); + + it('allows paid AssetPack delivery only with role, wallet, settlement, confirmation, and registry read access', () => { + const decision = evaluateBtdOrganizationInterfaceAuthority({ + actorId: 'user-1', + organizationId: 'org-1', + organizationRole: 'member', + organizationPermissionGrants: ['asset_pack:deliver'], + interfaceSurface: 'chatgpt_app', + action: 'deliver_asset_pack', + walletId: 'wallet-reader', + settlementState: 'settled', + confirmed: true, + readAccessDecision: { + decision: 'licensed_read', + accessPolicyHash: 'policy-hash', + reason: 'wallet_has_valid_policy_matching_license', + }, + targetAnchor: 'github:engineeredsoftware/ENGI/pull/42', + at: '2026-05-19T00:00:00.000Z', + }); + + expect(decision).toMatchObject({ + kind: 'btd_organization_interface_authority_decision', + decision: 'allowed', + interfaceSurface: 'chatgpt_app', + action: 'deliver_asset_pack', + sourceVisibility: 'protected_source_allowed', + satisfied: { + role: true, + permissionGrant: true, + walletBinding: true, + registryReadAccess: true, + settlement: true, + explicitConfirmation: true, + interfaceAction: true, + }, + }); + expect(decision.reasons).toEqual( + expect.arrayContaining([ + 'role_authorized', + 'explicit_permission_grant_authorized', + 'licensed_read_access_authorized', + ]), + ); + expect(decision.proofRoots.authorityRoot).toMatch(/^btd-proof-root:organization-interface-authority:/); + }); + + it('fails closed for unpaid protected-source unlock and unsupported ChatGPT administration', () => { + const unpaidUnlock = evaluateBtdOrganizationInterfaceAuthority({ + actorId: 'user-1', + organizationId: 'org-1', + organizationRole: 'admin', + interfaceSurface: 'terminal', + action: 'unlock_asset_pack_source', + walletId: 'wallet-reader', + settlementState: 'pending', + readAccessDecision: { + decision: 'owner_read', + accessPolicyHash: 'policy-hash', + reason: 'wallet_owns_policy_matching_range', + }, + at: '2026-05-19T00:00:00.000Z', + }); + const chatGptAdmin = evaluateBtdOrganizationInterfaceAuthority({ + actorId: 'user-1', + organizationId: 'org-1', + organizationRole: 'owner', + interfaceSurface: 'chatgpt_app', + action: 'administer_organization', + confirmed: true, + at: '2026-05-19T00:00:00.000Z', + }); + + expect(unpaidUnlock).toMatchObject({ + decision: 'denied', + reason: 'settlement_required', + sourceVisibility: 'blocked', + }); + expect(chatGptAdmin).toMatchObject({ + decision: 'denied', + reason: 'interface_action_not_authorized', + sourceVisibility: 'source_safe_preview', + }); + }); +}); diff --git a/packages/btd/src/authority.ts b/packages/btd/src/authority.ts new file mode 100644 index 000000000..436e07aba --- /dev/null +++ b/packages/btd/src/authority.ts @@ -0,0 +1,595 @@ +import { + assertNonEmptyString, +} from './constants'; +import type { + BtdAccessDecision, + BtdAccessDecisionKind, +} from './access'; + +export type BtdOrganizationRole = 'viewer' | 'member' | 'admin' | 'owner'; + +export type BtdInterfaceAuthoritySurface = + | 'terminal' + | 'api' + | 'mcp' + | 'chatgpt_app'; + +export type BtdOrganizationPermissionAction = + | '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'; + +export type BtdOrganizationAuthorityDecisionKind = 'allowed' | 'denied'; + +export type BtdOrganizationAuthorityReason = + | 'role_authorized' + | 'explicit_permission_grant_authorized' + | 'owner_read_access_authorized' + | 'licensed_read_access_authorized' + | 'role_missing' + | 'role_insufficient' + | 'wallet_binding_missing' + | 'registry_read_access_required' + | 'registry_read_access_denied' + | 'settlement_required' + | 'explicit_confirmation_required' + | 'repair_approval_required' + | 'interface_action_not_authorized'; + +export type BtdSettlementAuthorityState = 'not_required' | 'pending' | 'settled'; +export type BtdRepairApprovalState = 'not_required' | 'required' | 'approved'; +export type BtdSourceVisibilityState = + | 'source_safe_preview' + | 'protected_source_allowed' + | 'blocked'; + +export interface BtdOrganizationRegistryAuthoritySummary { + organizationId: string; + source: 'btd_registry'; + walletIds: string[]; + ownedAssetPackIds: string[]; + ownedCellCount: number; + readLicenseCount: number; + activeReadLicenseCount: number; + expiredReadLicenseCount: number; + revokedReadLicenseCount: number; + licensedAssetPackIds: string[]; + authorityRoot: string; +} + +export interface BtdOrganizationAuthorityActionRequirements { + minimumRole: BtdOrganizationRole; + permissionGrants: string[]; + requiresWalletBinding: boolean; + requiresRegistryReadAccess: boolean; + requiresSettledPayment: boolean; + requiresExplicitConfirmation: boolean; + requiresRepairApproval: boolean; + sourceVisibilityWhenAllowed: BtdSourceVisibilityState; +} + +export interface BtdOrganizationInterfaceAuthorityInput { + actorId: string; + organizationId: string; + organizationRole?: BtdOrganizationRole | null; + organizationPermissionGrants?: string[]; + interfaceSurface: BtdInterfaceAuthoritySurface; + action: BtdOrganizationPermissionAction; + walletId?: string | null; + readAccessDecision?: BtdAccessDecision | null; + settlementState?: BtdSettlementAuthorityState; + confirmed?: boolean; + repairApprovalState?: BtdRepairApprovalState; + targetAnchor?: string | null; + at?: string; +} + +export interface BtdOrganizationInterfaceAuthorityDecision { + kind: 'btd_organization_interface_authority_decision'; + decision: BtdOrganizationAuthorityDecisionKind; + actorId: string; + organizationId: string; + organizationRole: BtdOrganizationRole | null; + interfaceSurface: BtdInterfaceAuthoritySurface; + action: BtdOrganizationPermissionAction; + walletId: string | null; + targetAnchor: string | null; + readAccessDecision: BtdAccessDecision | null; + requirements: BtdOrganizationAuthorityActionRequirements; + satisfied: { + role: boolean; + permissionGrant: boolean; + walletBinding: boolean; + registryReadAccess: boolean; + settlement: boolean; + explicitConfirmation: boolean; + repairApproval: boolean; + interfaceAction: boolean; + }; + reason: BtdOrganizationAuthorityReason; + reasons: BtdOrganizationAuthorityReason[]; + sourceVisibility: BtdSourceVisibilityState; + proofRoots: { + roleRoot: string; + permissionRoot: string; + readAccessRoot: string; + interfaceRoot: string; + authorityRoot: string; + }; + issuedAt: string; +} + +const ROLE_ORDER: Record = { + viewer: 0, + member: 1, + admin: 2, + owner: 3, +}; + +const ACTION_REQUIREMENTS: Record< + BtdOrganizationPermissionAction, + BtdOrganizationAuthorityActionRequirements +> = { + read_transaction: { + minimumRole: 'viewer', + permissionGrants: ['terminal:read', 'activity:read'], + requiresWalletBinding: false, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: false, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + request_read: { + minimumRole: 'member', + permissionGrants: ['reading:request'], + requiresWalletBinding: false, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: false, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + review_need: { + minimumRole: 'member', + permissionGrants: ['reading:review_need'], + requiresWalletBinding: false, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: false, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + request_finding_fits: { + minimumRole: 'member', + permissionGrants: ['reading:request_finding_fits'], + requiresWalletBinding: false, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: false, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + review_asset_pack_preview: { + minimumRole: 'viewer', + permissionGrants: ['asset_pack:review_preview'], + requiresWalletBinding: false, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: false, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + pay_btc_fee: { + minimumRole: 'admin', + permissionGrants: ['settlement:pay_btc_fee'], + requiresWalletBinding: true, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: true, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + unlock_asset_pack_source: { + minimumRole: 'member', + permissionGrants: ['asset_pack:unlock_source'], + requiresWalletBinding: true, + requiresRegistryReadAccess: true, + requiresSettledPayment: true, + requiresExplicitConfirmation: false, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'protected_source_allowed', + }, + deliver_asset_pack: { + minimumRole: 'member', + permissionGrants: ['asset_pack:deliver'], + requiresWalletBinding: true, + requiresRegistryReadAccess: true, + requiresSettledPayment: true, + requiresExplicitConfirmation: true, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'protected_source_allowed', + }, + repair_projection: { + minimumRole: 'admin', + permissionGrants: ['settlement:repair_projection'], + requiresWalletBinding: false, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: true, + requiresRepairApproval: true, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + administer_organization: { + minimumRole: 'owner', + permissionGrants: ['organization:administer'], + requiresWalletBinding: false, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: true, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, +}; + +const SURFACE_ACTIONS: Record< + BtdInterfaceAuthoritySurface, + BtdOrganizationPermissionAction[] +> = { + terminal: [ + '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', + ], + api: [ + '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', + ], + mcp: [ + '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', + ], + chatgpt_app: [ + 'read_transaction', + 'review_asset_pack_preview', + 'deliver_asset_pack', + ], +}; + +export function listBtdOrganizationAuthorityActionRequirements() { + return ACTION_REQUIREMENTS; +} + +export function summarizeBtdOrganizationRegistryAuthority(input: { + organizationId: string; + walletIds?: string[]; + ownershipRows?: Record[]; + readLicenseRows?: Record[]; + at?: string; +}): BtdOrganizationRegistryAuthoritySummary { + const organizationId = assertNonEmptyString(input.organizationId, 'organizationId'); + const walletIds = uniqueStrings(input.walletIds ?? []); + const ownershipRows = input.ownershipRows ?? []; + const readLicenseRows = input.readLicenseRows ?? []; + const at = assertAuthorityDate(input.at ?? new Date().toISOString(), 'at'); + const activeReadLicenseRows = readLicenseRows.filter( + (row) => readLicenseState(row, at) === 'active', + ); + const expiredReadLicenseRows = readLicenseRows.filter( + (row) => readLicenseState(row, at) === 'expired', + ); + const revokedReadLicenseRows = readLicenseRows.filter( + (row) => readLicenseState(row, at) === 'revoked', + ); + const ownedCellCount = ownershipRows.reduce((sum, row) => { + const start = readNumberField(row, 'range_start', 'rangeStart'); + const end = readNumberField(row, 'range_end_exclusive', 'rangeEndExclusive'); + if (typeof start !== 'number' || typeof end !== 'number' || end <= start) return sum; + return sum + (end - start); + }, 0); + const ownedAssetPackIds = uniqueStrings( + ownershipRows.map((row) => readOptionalStringField(row, 'asset_pack_id', 'assetPackId')), + ); + const licensedAssetPackIds = uniqueStrings( + activeReadLicenseRows.map((row) => readOptionalStringField(row, 'asset_pack_id', 'assetPackId')), + ); + const summary = { + organizationId, + source: 'btd_registry', + walletIds, + ownedAssetPackIds, + ownedCellCount, + readLicenseCount: readLicenseRows.length, + activeReadLicenseCount: activeReadLicenseRows.length, + expiredReadLicenseCount: expiredReadLicenseRows.length, + revokedReadLicenseCount: revokedReadLicenseRows.length, + licensedAssetPackIds, + } satisfies Omit; + + return { + ...summary, + authorityRoot: stableProofRoot('organization-registry-authority', summary), + }; +} + +export function evaluateBtdOrganizationInterfaceAuthority( + input: BtdOrganizationInterfaceAuthorityInput, +): BtdOrganizationInterfaceAuthorityDecision { + const actorId = assertNonEmptyString(input.actorId, 'actorId'); + const organizationId = assertNonEmptyString(input.organizationId, 'organizationId'); + const requirements = ACTION_REQUIREMENTS[input.action]; + if (!requirements) { + throw new Error('action must be a known BTD organization permission action.'); + } + const issuedAt = assertAuthorityDate(input.at ?? new Date().toISOString(), 'at').toISOString(); + const organizationRole = input.organizationRole ?? null; + const permissionGrants = uniqueStrings(input.organizationPermissionGrants ?? []); + const walletId = normalizeOptionalString(input.walletId); + const targetAnchor = normalizeOptionalString(input.targetAnchor); + const readAccessDecision = input.readAccessDecision ?? null; + const interfaceAction = SURFACE_ACTIONS[input.interfaceSurface]?.includes(input.action) ?? false; + const role = roleSatisfies(organizationRole, requirements.minimumRole); + const permissionGrant = requirements.permissionGrants.some((grant) => + permissionGrants.includes(grant), + ); + const walletBinding = !requirements.requiresWalletBinding || Boolean(walletId); + const registryReadAccess = + !requirements.requiresRegistryReadAccess || + isAllowedReadAccessDecision(readAccessDecision?.decision); + const settlement = + !requirements.requiresSettledPayment || input.settlementState === 'settled'; + const explicitConfirmation = + !requirements.requiresExplicitConfirmation || input.confirmed === true; + const repairApproval = + !requirements.requiresRepairApproval || input.repairApprovalState === 'approved'; + const reasons: BtdOrganizationAuthorityReason[] = []; + + if (!interfaceAction) reasons.push('interface_action_not_authorized'); + if (!organizationRole) reasons.push('role_missing'); + else if (!role && !permissionGrant) reasons.push('role_insufficient'); + if (requirements.requiresWalletBinding && !walletBinding) reasons.push('wallet_binding_missing'); + if (requirements.requiresRegistryReadAccess && !readAccessDecision) { + reasons.push('registry_read_access_required'); + } else if (requirements.requiresRegistryReadAccess && !registryReadAccess) { + reasons.push('registry_read_access_denied'); + } + if (requirements.requiresSettledPayment && !settlement) reasons.push('settlement_required'); + if (requirements.requiresExplicitConfirmation && !explicitConfirmation) { + reasons.push('explicit_confirmation_required'); + } + if (requirements.requiresRepairApproval && !repairApproval) reasons.push('repair_approval_required'); + + const allowed = + interfaceAction && + (role || permissionGrant) && + walletBinding && + registryReadAccess && + settlement && + explicitConfirmation && + repairApproval; + const successReasons = successAuthorityReasons({ + role, + permissionGrant, + readAccessDecision, + }); + const finalReasons = allowed ? successReasons : reasons; + const decision = allowed ? 'allowed' : 'denied'; + const sourceVisibility = allowed + ? requirements.sourceVisibilityWhenAllowed + : requirements.requiresRegistryReadAccess || requirements.requiresSettledPayment + ? 'blocked' + : 'source_safe_preview'; + const proofRoots = { + roleRoot: stableProofRoot('organization-role', { + organizationId, + actorId, + organizationRole, + permissionGrants, + }), + permissionRoot: stableProofRoot('organization-permission', { + action: input.action, + requirements, + satisfiedByRole: role, + satisfiedByGrant: permissionGrant, + }), + readAccessRoot: stableProofRoot('organization-read-access', readAccessDecision), + interfaceRoot: stableProofRoot('interface-authority', { + interfaceSurface: input.interfaceSurface, + action: input.action, + interfaceAction, + }), + authorityRoot: '', + }; + proofRoots.authorityRoot = stableProofRoot('organization-interface-authority', { + actorId, + organizationId, + organizationRole, + interfaceSurface: input.interfaceSurface, + action: input.action, + decision, + reasons: finalReasons, + sourceVisibility, + targetAnchor, + roleRoot: proofRoots.roleRoot, + permissionRoot: proofRoots.permissionRoot, + readAccessRoot: proofRoots.readAccessRoot, + interfaceRoot: proofRoots.interfaceRoot, + }); + + return { + kind: 'btd_organization_interface_authority_decision', + decision, + actorId, + organizationId, + organizationRole, + interfaceSurface: input.interfaceSurface, + action: input.action, + walletId, + targetAnchor, + readAccessDecision, + requirements, + satisfied: { + role, + permissionGrant, + walletBinding, + registryReadAccess, + settlement, + explicitConfirmation, + repairApproval, + interfaceAction, + }, + reason: finalReasons[0] ?? 'role_authorized', + reasons: finalReasons, + sourceVisibility, + proofRoots, + issuedAt, + }; +} + +function roleSatisfies( + role: BtdOrganizationRole | null, + minimumRole: BtdOrganizationRole, +): boolean { + if (!role) return false; + return ROLE_ORDER[role] >= ROLE_ORDER[minimumRole]; +} + +function isAllowedReadAccessDecision( + decision: BtdAccessDecisionKind | undefined, +): boolean { + return decision === 'owner_read' || decision === 'licensed_read'; +} + +function successAuthorityReasons(input: { + role: boolean; + permissionGrant: boolean; + readAccessDecision: BtdAccessDecision | null; +}): BtdOrganizationAuthorityReason[] { + const reasons: BtdOrganizationAuthorityReason[] = []; + if (input.role) reasons.push('role_authorized'); + if (input.permissionGrant) reasons.push('explicit_permission_grant_authorized'); + if (input.readAccessDecision?.decision === 'owner_read') { + reasons.push('owner_read_access_authorized'); + } + if (input.readAccessDecision?.decision === 'licensed_read') { + reasons.push('licensed_read_access_authorized'); + } + return reasons.length ? reasons : ['role_authorized']; +} + +function readLicenseState( + row: Record, + at: Date, +): 'active' | 'expired' | 'revoked' | 'pending' { + const validFrom = readDateField(row, 'valid_from', 'validFrom'); + const expiresAt = readDateField(row, 'expires_at', 'expiresAt'); + const revokedAt = readDateField(row, 'revoked_at', 'revokedAt'); + + if (revokedAt) return 'revoked'; + if (validFrom && validFrom > at) return 'pending'; + if (expiresAt && expiresAt <= at) return 'expired'; + return 'active'; +} + +function readDateField(row: Record, ...keys: string[]): Date | null { + const value = readOptionalStringField(row, ...keys); + if (!value) return null; + const parsed = new Date(value); + return Number.isNaN(parsed.getTime()) ? null : parsed; +} + +function readNumberField(row: Record, ...keys: string[]): number | null { + for (const key of keys) { + const value = row[key]; + if (typeof value === 'number' && Number.isSafeInteger(value)) return value; + if (typeof value === 'string' && value.trim()) { + const parsed = Number(value); + if (Number.isSafeInteger(parsed)) return parsed; + } + } + return null; +} + +function readOptionalStringField(row: Record, ...keys: string[]): string | null { + for (const key of keys) { + const value = row[key]; + if (typeof value === 'string' && value.trim()) return value.trim(); + } + return null; +} + +function normalizeOptionalString(value: string | null | undefined): string | null { + return typeof value === 'string' && value.trim() ? value.trim() : null; +} + +function uniqueStrings(values: Array): string[] { + return Array.from( + new Set( + values + .map((value) => (typeof value === 'string' ? value.trim() : '')) + .filter(Boolean), + ), + ); +} + +function assertAuthorityDate(value: string, label: string): Date { + const parsed = new Date(assertNonEmptyString(value, label)); + if (Number.isNaN(parsed.getTime())) { + throw new Error(`${label} must be a valid ISO timestamp.`); + } + return parsed; +} + +function stableProofRoot(scope: string, value: unknown): string { + return `btd-proof-root:${scope}:${stableHash(stableSerialize(value))}`; +} + +function stableSerialize(value: unknown): string { + if (value === null || value === undefined) return String(value); + 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); +} + +function stableHash(value: string): string { + let hash = 2166136261; + for (let index = 0; index < value.length; index += 1) { + hash ^= value.charCodeAt(index); + hash = Math.imul(hash, 16777619); + } + return (hash >>> 0).toString(16).padStart(8, '0'); +} diff --git a/packages/btd/src/index.ts b/packages/btd/src/index.ts index 8bdcc77a5..113852887 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 './authority'; export * from './constants'; export * from './deployment-lanes'; export * from './exchange'; diff --git a/packages/chatgptapp/jest.config.cjs b/packages/chatgptapp/jest.config.cjs index 437a99dca..b895a14d5 100644 --- a/packages/chatgptapp/jest.config.cjs +++ b/packages/chatgptapp/jest.config.cjs @@ -1,5 +1,6 @@ const tsJestPreset = require('ts-jest/presets/js-with-ts/jest-preset'); const customModuleNameMapper = { + '^@bitcode/btd$': '/../btd/src/authority.ts', '^@bitcode/tools-generics$': '/src/__stubs__/tools-generics.ts', '^@bitcode/prompts/prompt$': '/../prompts/src/prompt.ts', '^@bitcode/prompts/parts/PromptPart$': '/../prompts/src/parts/PromptPart.ts', diff --git a/packages/chatgptapp/package.json b/packages/chatgptapp/package.json index 24f2397bb..d79e1d5b1 100644 --- a/packages/chatgptapp/package.json +++ b/packages/chatgptapp/package.json @@ -13,6 +13,7 @@ "dependencies": { "@modelcontextprotocol/sdk": "^1.0.0", "zod": "^3.22.4", + "@bitcode/btd": "workspace:*", "@bitcode/tools-generics": "workspace:*", "@bitcode/github": "workspace:*", "@bitcode/vcs": "workspace:*", @@ -28,6 +29,7 @@ "@types/jest": "^29.5.12", "@types/node": "^20.0.0", "jest": "^29.7.0", - "ts-jest": "^29.1.1" + "ts-jest": "^29.1.1", + "typescript": "^5.8.3" } } diff --git a/packages/chatgptapp/src/__tests__/tools.test.ts b/packages/chatgptapp/src/__tests__/tools.test.ts index d78996190..2296f41cf 100644 --- a/packages/chatgptapp/src/__tests__/tools.test.ts +++ b/packages/chatgptapp/src/__tests__/tools.test.ts @@ -24,6 +24,13 @@ const READ_ACCESS = { accessPolicyHash: 'policy-hash', reason: 'wallet_has_valid_policy_matching_license', } as const; +const ORGANIZATION_AUTHORITY = { + organizationId: 'org-1', + organizationRole: 'member', + organizationPermissionGrants: ['asset_pack:deliver'], + walletId: 'wallet-reader', + settlementState: 'settled', +} as const; describe('ChatGPT App tools', () => { beforeEach(() => { @@ -93,6 +100,7 @@ This product delivers voice-first social conversations for builders. expect(tool.meta?.requiresConfirmation).toBe(true); expect((tool.inputSchema as any).required).toContain('confirmed'); expect((tool.inputSchema as any).required).toContain('readAccess'); + expect((tool.inputSchema as any).required).toContain('organizationAuthority'); expect((tool.inputSchema as any).properties.confirmed).toMatchObject({ type: 'boolean', const: true, @@ -100,6 +108,9 @@ This product delivers voice-first social conversations for builders. expect((tool.inputSchema as any).properties.readAccess).toMatchObject({ type: 'object', }); + expect((tool.inputSchema as any).properties.organizationAuthority).toMatchObject({ + type: 'object', + }); } }); @@ -184,6 +195,7 @@ This product delivers voice-first social conversations for builders. request: 'deploy_to_vercel', confirmed: true, readAccess: READ_ACCESS, + organizationAuthority: ORGANIZATION_AUTHORITY, payload: { projectId: 'prj_Yapper', teamId: 'team_bitcode', message: 'Demo deploy' }, } ); @@ -198,6 +210,12 @@ This product delivers voice-first social conversations for builders. outputMeaning: 'asset_pack_delivery_mechanism', targetAnchor: 'vercel:team_bitcode/prj_Yapper', readAccess: READ_ACCESS, + organizationAuthority: expect.objectContaining({ + decision: 'allowed', + interfaceSurface: 'chatgpt_app', + action: 'deliver_asset_pack', + sourceVisibility: 'protected_source_allowed', + }), }); expect((result.result as any).readyState).toBe('BUILDING'); }); @@ -209,6 +227,7 @@ This product delivers voice-first social conversations for builders. operation: 'createRepository', confirmed: true, readAccess: READ_ACCESS, + organizationAuthority: ORGANIZATION_AUTHORITY, accessToken: 'ghp_mock', name: 'bitcode-yapper', description: 'Bitcode source-to-shares terminal companion fixture', @@ -230,6 +249,11 @@ This product delivers voice-first social conversations for builders. outputMeaning: 'asset_pack_delivery_mechanism', targetAnchor: 'github:bitcode-yapper', readAccess: READ_ACCESS, + organizationAuthority: expect.objectContaining({ + decision: 'allowed', + interfaceSurface: 'chatgpt_app', + action: 'deliver_asset_pack', + }), }); }); @@ -250,6 +274,7 @@ This product delivers voice-first social conversations for builders. runTool('use_vercel_write_external_mcp', { request: 'deploy_to_vercel', readAccess: READ_ACCESS, + organizationAuthority: ORGANIZATION_AUTHORITY, payload: { projectId: 'prj_Yapper', teamId: 'team_bitcode', message: 'Demo deploy' }, }) ).rejects.toThrow( @@ -262,11 +287,38 @@ This product delivers voice-first social conversations for builders. runTool('use_vercel_write_external_mcp', { request: 'deploy_to_vercel', confirmed: true, + organizationAuthority: ORGANIZATION_AUTHORITY, payload: { projectId: 'prj_Yapper', teamId: 'team_bitcode', message: 'Demo deploy' }, }) ).rejects.toThrow(/readAccess/); }); + it('rejects ChatGPT App connected-interface writes without organization authority evidence', async () => { + await expect( + runTool('use_vercel_write_external_mcp', { + request: 'deploy_to_vercel', + confirmed: true, + readAccess: READ_ACCESS, + payload: { projectId: 'prj_Yapper', teamId: 'team_bitcode', message: 'Demo deploy' }, + }) + ).rejects.toThrow(/organizationAuthority/); + }); + + it('rejects ChatGPT App connected-interface writes when organization authority is unpaid', async () => { + await expect( + runTool('use_vercel_write_external_mcp', { + request: 'deploy_to_vercel', + confirmed: true, + readAccess: READ_ACCESS, + organizationAuthority: { + ...ORGANIZATION_AUTHORITY, + settlementState: 'pending', + }, + payload: { projectId: 'prj_Yapper', teamId: 'team_bitcode', message: 'Demo deploy' }, + }) + ).rejects.toThrow(/settlement_required/); + }); + it('use_aws_read_external_mcp invokes lambda helper', async () => { const result = await runTool<{ metadata: { provider: string; guidance: string } }>('use_aws_read_external_mcp', { request: 'lambda.invoke', @@ -281,6 +333,7 @@ This product delivers voice-first social conversations for builders. request: 's3.putObject', confirmed: true, readAccess: READ_ACCESS, + organizationAuthority: ORGANIZATION_AUTHORITY, payload: { bucket: 'demo', key: 'config.json', body: '{}' }, }); expect(result.metadata.provider).toBe('aws'); @@ -293,6 +346,10 @@ This product delivers voice-first social conversations for builders. operation: 's3.putObject', targetAnchor: 'aws:s3/demo/config.json', readAccess: READ_ACCESS, + organizationAuthority: expect.objectContaining({ + decision: 'allowed', + interfaceSurface: 'chatgpt_app', + }), }); }); diff --git a/packages/chatgptapp/src/tools.ts b/packages/chatgptapp/src/tools.ts index d9bfd9449..ed39ae621 100644 --- a/packages/chatgptapp/src/tools.ts +++ b/packages/chatgptapp/src/tools.ts @@ -9,6 +9,11 @@ import { awsCloudWatchLogTool, awsDynamoGetItemTool, awsDynamoPutItemTool, awsLa import { simpleSystemTextSearch } from '@bitcode/generic-tools-simple-system-text-search'; import { search as webSearch } from '@bitcode/generic-tools-web-search'; import { generateDigest } from '@bitcode/digest/run'; +import { + evaluateBtdOrganizationInterfaceAuthority, + type BtdOrganizationRole, + type BtdSettlementAuthorityState, +} from '@bitcode/btd'; import { vercelGetDeploymentEventsTool, vercelGetDeploymentTool, @@ -56,6 +61,7 @@ type ChatGptAppWriteAdmissionInput = { operation: string; targetAnchor?: string; readAccess: ChatGptAppReadAccessDecision; + organizationAuthority: ReturnType; }; type ChatGptAppReadAccessDecision = { @@ -66,6 +72,15 @@ type ChatGptAppReadAccessDecision = { reason: string; }; +type ChatGptAppOrganizationAuthorityInput = { + organizationId: string; + organizationRole: BtdOrganizationRole; + organizationPermissionGrants?: string[]; + walletId?: string; + settlementState: BtdSettlementAuthorityState; + repairApprovalState?: 'not_required' | 'required' | 'approved'; +}; + const CHATGPT_APP_READ_ACCESS_VALIDATOR = z.object({ assetPackId: z.string().min(1, 'assetPackId must be provided'), walletId: z.string().min(1, 'walletId must be provided'), @@ -74,6 +89,15 @@ const CHATGPT_APP_READ_ACCESS_VALIDATOR = z.object({ reason: z.string().min(1, 'reason must be provided') }).strict(); +const CHATGPT_APP_ORGANIZATION_AUTHORITY_VALIDATOR = z.object({ + organizationId: z.string().min(1, 'organizationId must be provided'), + organizationRole: z.enum(['viewer', 'member', 'admin', 'owner']), + organizationPermissionGrants: z.array(z.string()).default([]), + walletId: z.string().optional(), + settlementState: z.enum(['not_required', 'pending', 'settled']), + repairApprovalState: z.enum(['not_required', 'required', 'approved']).optional() +}).strict(); + const CHATGPT_APP_READ_ACCESS_SCHEMA = { type: 'object', additionalProperties: false, @@ -103,6 +127,42 @@ const CHATGPT_APP_READ_ACCESS_SCHEMA = { required: ['assetPackId', 'walletId', 'decision', 'accessPolicyHash', 'reason'] }; +const CHATGPT_APP_ORGANIZATION_AUTHORITY_SCHEMA = { + type: 'object', + additionalProperties: false, + properties: { + organizationId: { + type: 'string', + description: 'Organization id whose role and grants authorize the ChatGPT connected-interface write' + }, + organizationRole: { + type: 'string', + enum: ['viewer', 'member', 'admin', 'owner'], + description: 'Registry-derived organization role for the actor' + }, + organizationPermissionGrants: { + type: 'array', + items: { type: 'string' }, + description: 'Optional registry-derived organization permission grants' + }, + walletId: { + type: 'string', + description: 'Wallet id bound to the actor; defaults to readAccess.walletId when omitted' + }, + settlementState: { + type: 'string', + enum: ['not_required', 'pending', 'settled'], + description: 'Settlement state for protected-source delivery' + }, + repairApprovalState: { + type: 'string', + enum: ['not_required', 'required', 'approved'], + description: 'Repair approval state when the write repairs a projection' + } + }, + required: ['organizationId', 'organizationRole', 'settlementState'] +}; + function assertConfirmedConnectedInterfaceWrite(confirmed: unknown): void { if (confirmed !== true) { throw new Error( @@ -128,6 +188,45 @@ function assertChatGptAppReadAccess(readAccess: unknown): ChatGptAppReadAccessDe return parsed.data as ChatGptAppReadAccessDecision; } +function assertChatGptAppOrganizationAuthority( + organizationAuthority: unknown, + input: { + operation: string; + targetAnchor?: string; + readAccess: ChatGptAppReadAccessDecision; + } +) { + const parsed = CHATGPT_APP_ORGANIZATION_AUTHORITY_VALIDATOR.safeParse(organizationAuthority); + if (!parsed.success) { + throw new Error( + 'Bitcode ChatGPT App write admission requires organizationAuthority role, settlement, and registry grant evidence.' + ); + } + + const decision = evaluateBtdOrganizationInterfaceAuthority({ + actorId: 'chatgpt_app_connected_interface', + organizationId: parsed.data.organizationId, + organizationRole: parsed.data.organizationRole, + organizationPermissionGrants: parsed.data.organizationPermissionGrants, + interfaceSurface: 'chatgpt_app', + action: 'deliver_asset_pack', + walletId: parsed.data.walletId ?? input.readAccess.walletId, + readAccessDecision: input.readAccess as any, + settlementState: parsed.data.settlementState, + confirmed: true, + repairApprovalState: parsed.data.repairApprovalState, + targetAnchor: input.targetAnchor ?? input.operation, + }); + + if (decision.decision !== 'allowed') { + throw new Error( + `Bitcode ChatGPT App write admission denied by organization authority: ${decision.reasons.join(', ')}.` + ); + } + + return decision; +} + function buildChatGptAppWriteAdmission(input: ChatGptAppWriteAdmissionInput) { return { admitted: true, @@ -140,7 +239,8 @@ function buildChatGptAppWriteAdmission(input: ChatGptAppWriteAdmissionInput) { connectedInterface: input.connectedInterface, operation: input.operation, targetAnchor: input.targetAnchor, - readAccess: input.readAccess + readAccess: input.readAccess, + organizationAuthority: input.organizationAuthority }; } @@ -720,6 +820,7 @@ const WRITE_CODE_CHANGES_VALIDATOR = z.object({ operation: z.enum(['createRepository', 'createOrUpdateFile']).describe('Write operation to perform'), confirmed: z.literal(true).describe('Explicit user confirmation required before Bitcode ChatGPT App connected-interface writes execute'), readAccess: CHATGPT_APP_READ_ACCESS_VALIDATOR.describe('Registry owner-read or licensed-read evidence required before connected-interface writes execute'), + organizationAuthority: CHATGPT_APP_ORGANIZATION_AUTHORITY_VALIDATOR.describe('Organization role and settlement evidence required before ChatGPT App delivery writes execute'), accessToken: z.string().min(1, 'accessToken must be provided').describe('GitHub access token with repo scope'), owner: z.string().optional().describe('Owner for file operations (required for createOrUpdateFile)'), repo: z.string().optional().describe('Repo for file operations (required for createOrUpdateFile)'), @@ -745,6 +846,12 @@ async function executeWriteCodeChanges(args: z.infer; switch (args.request) { case 'deploy_to_vercel': + targetAnchor = `vercel:${args.payload.teamId ?? 'team_bitcode'}/${args.payload.projectId ?? 'prj_Yapper'}`; + organizationAuthority = assertChatGptAppOrganizationAuthority(args.organizationAuthority, { + operation: args.request, + targetAnchor, + readAccess + }); result = await vercelDeployProjectTool.execute({ projectId: args.payload.projectId ?? 'prj_Yapper', teamId: args.payload.teamId ?? 'team_bitcode', message: args.payload.message }); - targetAnchor = `vercel:${args.payload.teamId ?? 'team_bitcode'}/${args.payload.projectId ?? 'prj_Yapper'}`; guidance = 'Deployment requested—explain the pending status and remind the user to monitor readiness.'; break; case 'buy_domain': + targetAnchor = `vercel:domain/${args.payload.name ?? 'yapper.app'}`; + organizationAuthority = assertChatGptAppOrganizationAuthority(args.organizationAuthority, { + operation: args.request, + targetAnchor, + readAccess + }); result = await vercelBuyDomainTool.execute({ name: args.payload.name ?? 'yapper.app', expectedPrice: args.payload.expectedPrice, @@ -1120,14 +1249,18 @@ async function executeUseVercelWriteExternalMcp(args: z.infer; switch (args.request) { case 's3.putObject': - result = await awsS3PutObjectTool.execute(args.payload as Parameters[0]); targetAnchor = `aws:s3/${String(args.payload.bucket ?? 'bitcode-demo')}/${String(args.payload.key ?? 'config/demo.json')}`; + organizationAuthority = assertChatGptAppOrganizationAuthority(args.organizationAuthority, { + operation: args.request, + targetAnchor, + readAccess + }); + result = await awsS3PutObjectTool.execute(args.payload as Parameters[0]); guidance = 'Uploaded to S3—confirm the path in follow-up so collaborators can fetch it easily.'; break; case 'dynamo.putItem': + targetAnchor = `aws:dynamodb/${String(args.payload.table ?? 'bitcode-demo-table')}`; + organizationAuthority = assertChatGptAppOrganizationAuthority(args.organizationAuthority, { + operation: args.request, + targetAnchor, + readAccess + }); result = await awsDynamoPutItemTool.execute( args.payload as Parameters[0] ); - targetAnchor = `aws:dynamodb/${String(args.payload.table ?? 'bitcode-demo-table')}`; guidance = 'Stored the record in DynamoDB; let’s document the schema impact in PRODUCT.md.'; break; default: @@ -1281,7 +1428,8 @@ async function executeUseAwsWriteExternalMcp(args: z.infer/../../../../', +}); +delete rootMapper['^@bitcode/(.*)$']; + +const explicitMapper = { + '^@bitcode/pipelines-generics$': '/../../../../packages/pipelines-generics/src/index.ts', + '^@bitcode/pipelines-generics/src/llm/dry_running/config$': '/src/__stubs__/dry-run-config.ts', + '^@bitcode/pipelines-generics/src/(.*)$': '/../../../../packages/pipelines-generics/src/$1', + '^@bitcode/pipelines-generics/(.*)$': '/../../../../packages/pipelines-generics/src/$1', + '^@bitcode/pipelines/asset-pack$': '/../../../../packages/pipelines/asset-pack/src/index.ts', + '^@bitcode/agent-generics$': '/../../../../packages/agent-generics/src/index.ts', + '^@bitcode/agent-generics/(.*)$': '/../../../../packages/agent-generics/src/$1', + '^@bitcode/generic-llms$': '/../../../../packages/generic-llms/src/index.ts', + '^@bitcode/generic-llms/(.*)$': '/../../../../packages/generic-llms/src/$1', + '^@bitcode/llm-generics$': '/../../../../packages/llm-generics/src/index.ts', + '^@bitcode/llm-generics/(.*)$': '/../../../../packages/llm-generics/src/$1', + '^@bitcode/execution-generics$': '/../../../../packages/execution-generics/src/index.ts', + '^@bitcode/execution-generics/(.*)$': '/../../../../packages/execution-generics/src/$1', + '^@bitcode/tools-generics$': '/../../../../packages/tools-generics/src/index.ts', + '^@bitcode/tools-generics/(.*)$': '/../../../../packages/tools-generics/src/$1', + '^@bitcode/registry$': '/../../../../packages/registry/src/index.ts', + '^@bitcode/registry/(.*)$': '/../../../../packages/registry/src/$1', + '^@bitcode/prompts$': '/../../../../packages/prompts/src/index.ts', + '^@bitcode/prompts/(.*)$': '/../../../../packages/prompts/src/$1', + '^@bitcode/doc-comment$': '/../../../../packages/doc-comment/src/index.ts', + '^@bitcode/doc-comment/(.*)$': '/../../../../packages/doc-comment/src/$1', + '^@bitcode/vcs-tools$': '/../../../../packages/generic-tools/vcs/src/index.ts', + '^@bitcode/editing$': '/../../../../packages/editing/src/index.ts', + '^@bitcode/editing/(.*)$': '/../../../../packages/editing/src/$1', + '^@bitcode/generic-tools/(.*)/src/(.*)$': '/../../../../packages/generic-tools/$1/src/$2', + '^@bitcode/supabase$': '/../../../../packages/supabase/src/index.ts', + '^@bitcode/supabase/src/ssr/admin$': '/../../../../packages/supabase/src/ssr/admin.ts', + '^@bitcode/supabase/(.*)$': '/../../../../packages/supabase/src/$1', + '^@bitcode/artifacts$': '/../../../../packages/artifacts/src/artifacts.ts', + '^@bitcode/logger$': '/../../../../packages/logger/src/logger.ts', + '^@bitcode/observability$': '/../../../../packages/observability/src/observability.ts', + '^@bitcode/errors$': '/../../../../packages/errors/src/errors.ts', + '^@bitcode/sentry$': '/../../../../packages/sentry/src/sentry.ts', + '^@bitcode/streams$': '/../../../../packages/streams/src/index.ts', + '^@bitcode/orm$': '/../../../../packages/orm/src/index.ts', + '^@bitcode/jira-tools$': '/../../../../packages/jira/src/index.ts', + '^@bitcode/pipeline-recovery$': '/src/__stubs__/pipeline-recovery.ts', + '^@bitcode/mcp-server$': '/src/index.ts', +}; + +module.exports = { + preset: 'ts-jest', + testEnvironment: 'node', + rootDir: '.', + setupFilesAfterEnv: ['/src/__tests__/setup/mcpTestSetup.ts'], + testMatch: ['/src/__tests__/**/*.test.ts'], + transform: { + '^.+\\.tsx?$': [ + 'ts-jest', + { + tsconfig: '/tsconfig.test.json', + diagnostics: false, + }, + ], + }, + moduleNameMapper: { + ...explicitMapper, + ...rootMapper, + }, + modulePathIgnorePatterns: ['/dist'], + testTimeout: 30000, +}; 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 16adafc64..ad917521e 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 @@ -354,6 +354,165 @@ describe('Authentication Middleware', () => { statusCode: 403 }); }); + + it('admits MCP delivery only when organization authority and registry read access agree', async () => { + mockGetByKeyHash.mockResolvedValue({ + id: 'key123', + user_id: 'user123', + name: 'Bitcode Test Key', + scopes: ['resources:read'], + expires_at: null + }); + mockUpdateLastUsed.mockResolvedValue(undefined); + mockGetById + .mockResolvedValueOnce({ + id: 'user123', + email: 'operator@example.com', + full_name: 'Bitcode Operator', + organization_id: 'org123' + }) + .mockResolvedValueOnce({ + id: 'org123', + name: 'Bitcode Labs', + slug: 'bitcode-labs' + }); + mockGetMembership.mockResolvedValue({ + role: 'member', + permissions: { + resources: ['read'], + asset_pack: ['deliver'] + } + }); + mockGetProfileByUserId.mockResolvedValue({ + wallet_binding: { + address: 'wallet-reader', + status: 'verified' + } + }); + mockReadBtdHoldingAmount.mockResolvedValue(0); + mockGetAssetPackRange.mockResolvedValue({ + asset_pack_id: 'asset-pack-1', + range_start: 0, + range_end_exclusive: 5, + token_count: 5, + access_policy_id: 'policy-1', + access_policy_hash: 'policy-hash' + }); + mockListOwnershipClaims.mockResolvedValue([]); + mockListReadLicenses.mockResolvedValue([ + { + license_id: 'license-1', + wallet_id: 'wallet-reader', + asset_pack_id: 'asset-pack-1', + access_policy_hash: 'policy-hash', + valid_from: '2026-05-01T00:00:00.000Z' + } + ]); + + const result = await authenticateMCPRequest('Bearer key_test123', { + requireOrganization: true, + requiredPermissions: { resources: ['read'] }, + requiredReadAccess: { + assetPackId: 'asset-pack-1', + at: '2026-05-19T00:00:00.000Z' + }, + requiredInterfaceAuthority: { + action: 'deliver_asset_pack', + settlementState: 'settled', + confirmed: true, + targetAnchor: 'github:engineeredsoftware/ENGI/pull/42', + at: '2026-05-19T00:00:00.000Z' + } + }); + + expect(result.success).toBe(true); + expect(result.context?.interfaceAuthority).toEqual([ + expect.objectContaining({ + interfaceSurface: 'mcp', + action: 'deliver_asset_pack', + decision: 'allowed', + sourceVisibility: 'protected_source_allowed' + }) + ]); + }); + + it('rejects MCP delivery when interface authority is missing settlement and confirmation', async () => { + mockGetByKeyHash.mockResolvedValue({ + id: 'key123', + user_id: 'user123', + name: 'Bitcode Test Key', + scopes: ['resources:read'], + expires_at: null + }); + mockUpdateLastUsed.mockResolvedValue(undefined); + mockGetById + .mockResolvedValueOnce({ + id: 'user123', + email: 'operator@example.com', + full_name: 'Bitcode Operator', + organization_id: 'org123' + }) + .mockResolvedValueOnce({ + id: 'org123', + name: 'Bitcode Labs', + slug: 'bitcode-labs' + }); + mockGetMembership.mockResolvedValue({ + role: 'member', + permissions: { + resources: ['read'], + asset_pack: ['deliver'] + } + }); + mockGetProfileByUserId.mockResolvedValue({ + wallet_binding: { + address: 'wallet-reader', + status: 'verified' + } + }); + mockReadBtdHoldingAmount.mockResolvedValue(0); + mockGetAssetPackRange.mockResolvedValue({ + asset_pack_id: 'asset-pack-1', + range_start: 0, + range_end_exclusive: 5, + token_count: 5, + access_policy_id: 'policy-1', + access_policy_hash: 'policy-hash' + }); + mockListOwnershipClaims.mockResolvedValue([]); + mockListReadLicenses.mockResolvedValue([ + { + license_id: 'license-1', + wallet_id: 'wallet-reader', + asset_pack_id: 'asset-pack-1', + access_policy_hash: 'policy-hash', + valid_from: '2026-05-01T00:00:00.000Z' + } + ]); + + const result = await authenticateMCPRequest('Bearer key_test123', { + requireOrganization: true, + requiredPermissions: { resources: ['read'] }, + requiredReadAccess: { + assetPackId: 'asset-pack-1', + at: '2026-05-19T00:00:00.000Z' + }, + requiredInterfaceAuthority: { + action: 'deliver_asset_pack', + settlementState: 'pending', + confirmed: false, + at: '2026-05-19T00:00:00.000Z' + } + }); + + expect(result.success).toBe(false); + expect(result.error).toMatchObject({ + code: 'INSUFFICIENT_INTERFACE_AUTHORITY', + statusCode: 403 + }); + expect(result.error?.message).toContain('settlement_required'); + expect(result.error?.message).toContain('explicit_confirmation_required'); + }); }); describe('validatePermissions', () => { diff --git a/packages/executions-mcp/src/mcp-server/src/auth/middleware.ts b/packages/executions-mcp/src/mcp-server/src/auth/middleware.ts index 8b1f7f399..e9215efae 100644 --- a/packages/executions-mcp/src/mcp-server/src/auth/middleware.ts +++ b/packages/executions-mcp/src/mcp-server/src/auth/middleware.ts @@ -25,8 +25,12 @@ import { } from '@bitcode/orm'; import { buildBtdReadAccessProjectionFromRegistryRows, + evaluateBtdOrganizationInterfaceAuthority, evaluateBtdReadAccess, + type BtdOrganizationPermissionAction, + type BtdRepairApprovalState, type BtdAccessDecisionKind, + type BtdSettlementAuthorityState, } from '@bitcode/btd'; import type { MCPAuthContext } from '../types'; import * as crypto from 'crypto'; @@ -62,6 +66,7 @@ export interface MCPAuthOptions { */ minimumBtdHolding?: number; requiredReadAccess?: MCPReadAccessRequirement | MCPReadAccessRequirement[]; + requiredInterfaceAuthority?: MCPInterfaceAuthorityRequirement | MCPInterfaceAuthorityRequirement[]; } export interface MCPReadAccessRequirement { @@ -71,6 +76,15 @@ export interface MCPReadAccessRequirement { at?: string; } +export interface MCPInterfaceAuthorityRequirement { + action: BtdOrganizationPermissionAction; + targetAnchor?: string; + settlementState?: BtdSettlementAuthorityState; + confirmed?: boolean; + repairApprovalState?: BtdRepairApprovalState; + at?: string; +} + type MCPWalletProfileSource = UserProfile & Record; export const authCache = new LRUCache(10000); @@ -199,6 +213,7 @@ export async function authenticateMCPRequest( btdBalance: 0, walletId: walletBinding?.address ?? undefined, btdReadAccess: [], + interfaceAuthority: [], mcpCredentials: {} } as MCPAuthContext; @@ -341,9 +356,17 @@ async function validateAuthenticatedContext( return readAccessResult; } + const interfaceAuthorityResult = validateRequiredInterfaceAuthority( + readAccessResult.context ?? context, + options, + ); + if (!interfaceAuthorityResult.success) { + return interfaceAuthorityResult; + } + return { success: true, - context: readAccessResult.context ?? context + context: interfaceAuthorityResult.context ?? readAccessResult.context ?? context }; } @@ -443,6 +466,111 @@ function normalizeReadAccessRequirements( return Array.isArray(input) ? input : [input]; } +function validateRequiredInterfaceAuthority( + context: MCPAuthContext, + options: MCPAuthOptions, +): AuthResult { + const requirements = normalizeInterfaceAuthorityRequirements(options.requiredInterfaceAuthority); + if (requirements.length === 0) { + return { success: true, context }; + } + + if (!context.organizationId) { + return { + success: false, + error: { + code: 'ORGANIZATION_AUTHORITY_REQUIRED', + message: 'MCP interface authority requires an organization-scoped actor.', + statusCode: 403, + }, + }; + } + + const authorityDecisions = []; + for (const requirement of requirements) { + const readAccess = firstAllowedReadAccess(context); + const decision = evaluateBtdOrganizationInterfaceAuthority({ + actorId: context.userId, + organizationId: context.organizationId, + organizationRole: context.organizationRole, + organizationPermissionGrants: flattenOrganizationPermissionGrants(context), + interfaceSurface: 'mcp', + action: requirement.action, + walletId: context.walletId, + readAccessDecision: readAccess + ? { + decision: readAccess.decision, + accessPolicyHash: readAccess.accessPolicyHash, + reason: readAccess.reason as any, + } + : null, + settlementState: requirement.settlementState, + confirmed: requirement.confirmed, + repairApprovalState: requirement.repairApprovalState, + targetAnchor: requirement.targetAnchor, + at: requirement.at, + }); + + authorityDecisions.push({ + interfaceSurface: 'mcp' as const, + action: requirement.action, + decision: decision.decision, + reason: decision.reason, + authorityRoot: decision.proofRoots.authorityRoot, + sourceVisibility: decision.sourceVisibility, + }); + + if (decision.decision !== 'allowed') { + return { + success: false, + error: { + code: 'INSUFFICIENT_INTERFACE_AUTHORITY', + message: `MCP interface authority denied ${requirement.action}: ${decision.reasons.join(', ')}.`, + statusCode: 403, + }, + }; + } + } + + return { + success: true, + context: { + ...context, + interfaceAuthority: [...(context.interfaceAuthority ?? []), ...authorityDecisions], + }, + }; +} + +function normalizeInterfaceAuthorityRequirements( + input: MCPAuthOptions['requiredInterfaceAuthority'], +): MCPInterfaceAuthorityRequirement[] { + if (!input) { + return []; + } + + return Array.isArray(input) ? input : [input]; +} + +function firstAllowedReadAccess(context: MCPAuthContext) { + return context.btdReadAccess?.find( + (decision) => decision.decision === 'owner_read' || decision.decision === 'licensed_read', + ) ?? null; +} + +function flattenOrganizationPermissionGrants(context: MCPAuthContext): string[] { + const grants = [...(context.scopes ?? [])]; + const organizationPermissions = context.organizationPermissions ?? {}; + for (const [resource, permissions] of Object.entries(organizationPermissions)) { + if (!Array.isArray(permissions)) continue; + for (const permission of permissions) { + if (typeof permission === 'string' && permission.trim()) { + grants.push(`${resource}:${permission.trim()}`); + } + } + } + return Array.from(new Set(grants)); +} + function getMissingPermissions( context: MCPAuthContext, requiredPermissions: MCPAuthOptions['requiredPermissions'] = {} diff --git a/packages/executions-mcp/src/mcp-server/src/types/index.ts b/packages/executions-mcp/src/mcp-server/src/types/index.ts index 752e019ac..8a3a672c0 100644 --- a/packages/executions-mcp/src/mcp-server/src/types/index.ts +++ b/packages/executions-mcp/src/mcp-server/src/types/index.ts @@ -70,6 +70,14 @@ export interface MCPAuthContext { reason: string; accessPolicyHash: string; }>; + interfaceAuthority?: Array<{ + interfaceSurface: 'mcp'; + action: string; + decision: 'allowed' | 'denied'; + reason: string; + authorityRoot: string; + sourceVisibility: string; + }>; btdBalance: number; mcpCredentials: Record; } diff --git a/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts b/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts index 3c3e60bc4..7ae39d76d 100644 --- a/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts +++ b/packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts @@ -206,6 +206,10 @@ describe('asset-pack sandbox harness plan', () => { expect(source).toContain("execution.store('asset-pack/preview', 'feeQuote'"); expect(source).toContain('reconcileLedgerDatabaseProjection'); expect(source).toContain("execution.store('asset-pack/settlement', 'ledgerDatabaseReconciliation'"); + expect(source).toContain("execution.store('asset-pack/settlement', 'organizationAuthority'"); + expect(source).toContain('organizationAuthorityDecision'); + expect(source).toContain('organizationAuthorityRoot'); + expect(source).toContain('organizationAuthority,'); expect(source).toContain('ledgerDatabaseReconciliation,'); expect(source).toContain('repairActionCount'); expect(source).toContain('ledgerSettlement,'); diff --git a/packages/pipeline-hosts/src/asset-pack-harness.ts b/packages/pipeline-hosts/src/asset-pack-harness.ts index c8a1a23d1..754856051 100644 --- a/packages/pipeline-hosts/src/asset-pack-harness.ts +++ b/packages/pipeline-hosts/src/asset-pack-harness.ts @@ -1571,16 +1571,18 @@ try { resolveReadingPipelineTelemetryProjection, summarizeReadingPipelineObservabilityCoverage, synthesizeReadNeedForPipelineInput, - }, - { enablePipelineStreaming, factoryPipelineExecution }, - { applyAssetPackSettlementUnlockToPreview, buildAssetPackSettlementUnlock }, - { reconcileLedgerDatabaseProjection }, - ] = 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'), - ]); + }, + { enablePipelineStreaming, factoryPipelineExecution }, + { applyAssetPackSettlementUnlockToPreview, buildAssetPackSettlementUnlock }, + { reconcileLedgerDatabaseProjection }, + { evaluateBtdOrganizationInterfaceAuthority }, + ] = 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'), + ]); readingPipelineObservabilityInventory = buildReadingPipelineObservabilityInventory(); resolveReadingPipelineTelemetryProjectionFn = resolveReadingPipelineTelemetryProjection; summarizeReadingPipelineObservabilityCoverageFn = summarizeReadingPipelineObservabilityCoverage; @@ -1827,14 +1829,38 @@ try { reason: settlementUnlock.reason, }); assertAssetPackDisclosureSourceSafe(assetPackDisclosureReview); + const organizationAuthority = [ + evaluateBtdOrganizationInterfaceAuthority({ + actorId: userId || readerWalletId, + organizationId: manifest.organizationId || manifest.organization?.id || 'staging-testnet-organization', + organizationRole: 'admin', + organizationPermissionGrants: ['asset_pack:deliver'], + interfaceSurface: 'terminal', + action: 'deliver_asset_pack', + walletId: readerWalletId, + targetAnchor: pullRequestUrl || null, + readAccessDecision: settlementUnlock.sourceAvailable + ? { + decision: 'licensed_read', + accessPolicyHash: ledgerSettlement.accessPolicyHash || sourceSafePreview?.accessPolicy?.accessPolicyHash || 'policy-pending', + reason: settlementUnlock.reason, + } + : null, + settlementState: settlementUnlock.sourceAvailable ? 'settled' : 'pending', + confirmed: ledgerSettlement.settlementAdmissible === true, + repairApprovalState: 'not_required', + }), + ]; execution.store('asset-pack/preview', 'sourceSafe', settledSourceSafePreview); execution.store('asset-pack/preview', 'disclosureReview', assetPackDisclosureReview); execution.store('asset-pack/settlement', 'unlock', settlementUnlock); execution.store('asset-pack/settlement', 'readLicenseId', settlementUnlock.readLicenseId); + execution.store('asset-pack/settlement', 'organizationAuthority', organizationAuthority); output = { ...(output || {}), sourceSafePreview: settledSourceSafePreview, assetPackDisclosureReview, + organizationAuthority, ledgerSettlement: { ...ledgerSettlement, protectedSourceUnlock: settlementUnlock, @@ -1855,6 +1881,8 @@ try { assetPackId: ledgerSettlement.assetPackId || null, reconciliationState: ledgerDatabaseReconciliation?.state || null, repairActionCount: ledgerDatabaseReconciliation?.repairActions?.length || 0, + organizationAuthorityDecision: organizationAuthority[0].decision, + organizationAuthorityRoot: organizationAuthority[0].proofRoots.authorityRoot, }); const readingPipelineObservabilityCoverage = summarizeReadingPipelineObservabilityCoverageFn ? summarizeReadingPipelineObservabilityCoverageFn(events) @@ -1880,6 +1908,7 @@ try { deliveryMechanism: output?.deliveryMechanism || null, shippables: output?.shippables || null, ledgerSettlement: output.ledgerSettlement, + organizationAuthority, ledgerDatabaseReconciliation, execution: summarizeExecution(execution), readingPipelineObservabilityInventory, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cf11af1d6..7c6460e0c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -76,10 +76,10 @@ importers: version: 29.5.14 jest: specifier: ^29.0.0 - version: 29.7.0(@types/node@25.6.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.8.3)) + version: 29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.8.3)) ts-jest: specifier: ^29.0.0 - version: 29.4.0(@babel/core@7.27.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@25.6.0)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@25.6.0)(typescript@5.8.3)))(typescript@5.8.3) + version: 29.4.0(@babel/core@7.27.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.41)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.41)(typescript@5.8.3)))(typescript@5.8.3) typescript: specifier: ^5.0.0 version: 5.8.3 @@ -286,6 +286,9 @@ importers: packages/chatgptapp: dependencies: + '@bitcode/btd': + specifier: workspace:* + version: link:../btd '@bitcode/digest': specifier: workspace:* version: link:../digest @@ -331,10 +334,13 @@ importers: version: 20.19.2 jest: specifier: ^29.7.0 - version: 29.7.0(@types/node@20.19.2)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.2)(typescript@6.0.3)) + version: 29.7.0(@types/node@20.19.2)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.2)(typescript@5.8.3)) ts-jest: specifier: ^29.1.1 - version: 29.4.0(@babel/core@7.27.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.7))(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.2)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.2)(typescript@6.0.3)))(typescript@6.0.3) + version: 29.4.0(@babel/core@7.27.7)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.7))(esbuild@0.25.5)(jest-util@29.7.0)(jest@29.7.0(@types/node@20.19.2)(babel-plugin-macros@3.1.0)(ts-node@10.9.2(@types/node@20.19.2)(typescript@5.8.3)))(typescript@5.8.3) + typescript: + specifier: ^5.8.3 + version: 5.8.3 packages/circleci: {} diff --git a/scripts/check-v29-gate7-organization-permission-authority.mjs b/scripts/check-v29-gate7-organization-permission-authority.mjs new file mode 100644 index 000000000..f2a604eea --- /dev/null +++ b/scripts/check-v29-gate7-organization-permission-authority.mjs @@ -0,0 +1,257 @@ +#!/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-v29-gate7-organization-permission-authority.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 7 organization permission and interface authority closure.', + ].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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 Gate 7 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-7-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 7 work must occur on version/v29 or v29/gate-7-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'scripts/check-v29-gate7-organization-permission-authority.mjs', + 'packages/btd/src/authority.ts', + 'packages/btd/src/index.ts', + 'packages/btd/__tests__/btd.test.ts', + 'packages/api/src/routes/btd-crypto.ts', + 'packages/api/src/routes/__tests__/btd-crypto.test.ts', + 'uapi/app/api/btd/organization-interface-authority/route.ts', + 'packages/executions-mcp/src/mcp-server/src/auth/middleware.ts', + 'packages/executions-mcp/src/mcp-server/src/types/index.ts', + 'packages/executions-mcp/src/mcp-server/src/__tests__/unit/auth.test.ts', + 'packages/chatgptapp/src/tools.ts', + 'packages/chatgptapp/src/__tests__/tools.test.ts', + 'packages/chatgptapp/package.json', + 'packages/pipeline-hosts/src/asset-pack-harness.ts', + 'packages/pipeline-hosts/src/__tests__/asset-pack-harness.test.ts', + 'uapi/app/terminal/terminal-organization-authority.ts', + 'uapi/app/terminal/TerminalTransactionOrganizationAuthorityCard.tsx', + 'uapi/app/terminal/terminal-transaction-detail-snapshot.ts', + 'uapi/app/terminal/terminal-transaction-read-model.ts', + 'uapi/app/terminal/terminal-transaction-query.ts', + 'uapi/app/terminal/README.md', + 'uapi/tests/terminalOrganizationAuthority.test.ts', + 'uapi/tests/terminalTransactionDetailCards.test.tsx', + 'uapi/tests/terminalTransactionDetailSnapshot.test.ts', + '.github/workflows/bitcode-gate-quality.yml', + 'package.json', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 7 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const btdAuthority = read(root, 'packages/btd/src/authority.ts'); + const btdIndex = read(root, 'packages/btd/src/index.ts'); + const btdTest = read(root, 'packages/btd/__tests__/btd.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/organization-interface-authority/route.ts'); + const mcpAuth = read(root, 'packages/executions-mcp/src/mcp-server/src/auth/middleware.ts'); + const mcpTypes = read(root, 'packages/executions-mcp/src/mcp-server/src/types/index.ts'); + const mcpTest = read(root, 'packages/executions-mcp/src/mcp-server/src/__tests__/unit/auth.test.ts'); + const chatgptTools = read(root, 'packages/chatgptapp/src/tools.ts'); + const chatgptTest = read(root, 'packages/chatgptapp/src/__tests__/tools.test.ts'); + const chatgptPackage = read(root, 'packages/chatgptapp/package.json'); + 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-organization-authority.ts'); + const terminalCard = read(root, 'uapi/app/terminal/TerminalTransactionOrganizationAuthorityCard.tsx'); + 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 terminalQuery = read(root, 'uapi/app/terminal/terminal-transaction-query.ts'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const terminalTest = read(root, 'uapi/tests/terminalOrganizationAuthority.test.ts'); + const terminalCardTest = read(root, 'uapi/tests/terminalTransactionDetailCards.test.tsx'); + const terminalSnapshotTest = read(root, 'uapi/tests/terminalTransactionDetailSnapshot.test.ts'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + assertCheck(failures, spec.includes('V29 organization interface authority canon'), 'V29 SPEC must define organization interface authority canon.'); + assertCheck(failures, delta.includes('Gate 7: Organization Permissions And Interface Authority') && delta.includes('organizationAuthority'), 'V29 DELTA must define Gate 7 closure acceptance.'); + assertCheck(failures, notes.includes('Gate 7 working notes'), 'V29 NOTES must carry Gate 7 working notes.'); + assertCheck(failures, parity.includes('## Gate 7 Parity'), 'V29 PARITY must include Gate 7 parity.'); + assertCheck(failures, parity.includes('Gate 7 completion condition'), 'V29 PARITY must include Gate 7 completion condition.'); + + for (const symbol of [ + 'BtdOrganizationInterfaceAuthorityDecision', + 'BtdOrganizationPermissionAction', + 'BtdOrganizationRegistryAuthoritySummary', + 'summarizeBtdOrganizationRegistryAuthority', + 'evaluateBtdOrganizationInterfaceAuthority', + 'sourceVisibilityWhenAllowed', + 'requiresRegistryReadAccess', + 'requiresSettledPayment', + 'requiresExplicitConfirmation', + 'terminal', + 'api', + 'mcp', + 'chatgpt_app', + 'deliver_asset_pack', + 'administer_organization', + 'authorityRoot', + ]) { + assertCheck(failures, btdAuthority.includes(symbol), `BTD authority primitive is missing ${symbol}.`); + } + + assertCheck( + failures, + btdIndex.includes("export * from './authority'") && + btdTest.includes('organization interface authority') && + btdTest.includes('activeReadLicenseCount') && + btdTest.includes('protected_source_allowed') && + btdTest.includes('settlement_required') && + btdTest.includes('interface_action_not_authorized'), + 'BTD package exports/tests must prove Gate 7 holdings, license usage, paid delivery, unpaid denial, and unsupported interface denial.', + ); + assertCheck( + failures, + apiRoute.includes('buildBtdOrganizationInterfaceAuthorityDecision') && + apiRoute.includes('/btd/organization-interface-authority') && + apiTest.includes('organization interface authority') && + apiTest.includes('registry_read_access_required') && + uapiRoute.includes('postBtdOrganizationInterfaceAuthority'), + 'API and UAPI routes/tests must expose JSON-safe organization authority decisions.', + ); + assertCheck( + failures, + mcpAuth.includes('requiredInterfaceAuthority') && + mcpAuth.includes('validateRequiredInterfaceAuthority') && + mcpAuth.includes('evaluateBtdOrganizationInterfaceAuthority') && + mcpTypes.includes('interfaceAuthority') && + mcpTest.includes('interface authority') && + mcpTest.includes('INSUFFICIENT_INTERFACE_AUTHORITY'), + 'MCP auth must support required interface authority and focused tests.', + ); + assertCheck( + failures, + chatgptPackage.includes('"@bitcode/btd"') && + chatgptTools.includes('CHATGPT_APP_ORGANIZATION_AUTHORITY_VALIDATOR') && + chatgptTools.includes('assertChatGptAppOrganizationAuthority') && + chatgptTools.includes('organizationAuthority') && + chatgptTest.includes('organizationAuthority') && + chatgptTest.includes('organization authority is unpaid'), + 'ChatGPT App write carriers/tests must require organization authority evidence.', + ); + assertCheck( + failures, + harness.includes('organizationAuthority') && + harness.includes('evaluateBtdOrganizationInterfaceAuthority') && + harness.includes("execution.store('asset-pack/settlement', 'organizationAuthority'") && + harness.includes('organizationAuthorityDecision') && + harnessTest.includes('organizationAuthority'), + 'Sandbox harness must persist and test organization authority evidence.', + ); + assertCheck( + failures, + terminalProjection.includes('buildTerminalOrganizationAuthorityProjection') && + terminalProjection.includes('authorityRoot') && + terminalCard.includes('Organization authority') && + terminalSnapshot.includes('organizationAuthority') && + terminalReadModel.includes("'authority'") && + terminalQuery.includes("'authority'") && + terminalTest.includes('authority proof roots') && + terminalCardTest.includes('Organization authority') && + terminalSnapshotTest.includes('organizationAuthority') && + terminalReadme.includes('Organization Authority section'), + 'Terminal projection/card/read-model/docs/tests must expose authority detail.', + ); + assertCheck( + failures, + packageJson.includes('"check:v29-gate7"') && + gateWorkflow.includes('check-v29-gate7-organization-permission-authority.mjs') && + gateWorkflow.includes('terminalOrganizationAuthority.test.ts') && + gateWorkflow.includes('packages/chatgptapp') && + gateWorkflow.includes('packages/executions-mcp/src/mcp-server'), + 'Package scripts and gate-quality workflow must invoke Gate 7 checker and focused tests.', + ); + + if (failures.length) { + process.stderr.write('V29 Gate 7 check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V29 Gate 7 organization permission and interface authority check passed.\n'); +} + +main(); diff --git a/uapi/app/api/btd/organization-interface-authority/route.ts b/uapi/app/api/btd/organization-interface-authority/route.ts new file mode 100644 index 000000000..78525eeb1 --- /dev/null +++ b/uapi/app/api/btd/organization-interface-authority/route.ts @@ -0,0 +1,3 @@ +import { postBtdOrganizationInterfaceAuthority } from '@bitcode/api'; + +export const POST = postBtdOrganizationInterfaceAuthority; diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 40961b96b..24ee6df08 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -141,6 +141,14 @@ database projection require approval, and settled transactions with missing pull-request delivery surface delivery recovery without exposing protected AssetPack source before payment. +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, +confirmation state, interface admission, blockers, and proof roots before raw +authority payload inspection. Terminal may show source-safe previews without a +paid unlock, but protected-source unlock and delivery remain blocked until the +same `organizationAuthority` evidence admits the action. + ## Related shared systems - [../../components/base/bitcode/execution/README.md](../../components/base/bitcode/execution/README.md) diff --git a/uapi/app/terminal/TerminalTransactionDetailActionBar.tsx b/uapi/app/terminal/TerminalTransactionDetailActionBar.tsx index 810380960..cba0f9d14 100644 --- a/uapi/app/terminal/TerminalTransactionDetailActionBar.tsx +++ b/uapi/app/terminal/TerminalTransactionDetailActionBar.tsx @@ -14,6 +14,7 @@ type DetailAction = { const DETAIL_ACTIONS: DetailAction[] = [ { id: 'shippables', label: 'Shippables' }, { id: 'transaction', label: 'Identity' }, + { id: 'authority', label: 'Authority' }, { id: 'closure', label: 'Closure' }, { id: 'proofs', label: 'Proofs' }, { id: 'history', label: 'History' }, diff --git a/uapi/app/terminal/TerminalTransactionDetailSurface.tsx b/uapi/app/terminal/TerminalTransactionDetailSurface.tsx index 0ba956195..607b631f8 100644 --- a/uapi/app/terminal/TerminalTransactionDetailSurface.tsx +++ b/uapi/app/terminal/TerminalTransactionDetailSurface.tsx @@ -22,6 +22,7 @@ import TerminalTransactionDetailHero from './TerminalTransactionDetailHero'; import TerminalTransactionHistoryCard from './TerminalTransactionHistoryCard'; import TerminalTransactionIdentityCard from './TerminalTransactionIdentityCard'; import TerminalTransactionJournalReconciliationCard from './TerminalTransactionJournalReconciliationCard'; +import TerminalTransactionOrganizationAuthorityCard from './TerminalTransactionOrganizationAuthorityCard'; import TerminalTransactionProofsCard from './TerminalTransactionProofsCard'; import TerminalTransactionWalletBtcCard from './TerminalTransactionWalletBtcCard'; import { @@ -31,6 +32,7 @@ import { } from './terminal-activity-history'; import { normalizeTerminalClosureState } from './terminal-closure-state'; import { buildTerminalJournalReconciliation } from './terminal-journal-reconciliation'; +import { buildTerminalOrganizationAuthorityProjection } from './terminal-organization-authority'; import { buildTerminalTransactionClosurePayload, buildTerminalTransactionClosureFollowThrough, @@ -101,6 +103,7 @@ export default function TerminalTransactionDetailSurface({ const showShippables = detailSection === 'shippables'; const showTransaction = detailSection === 'transaction'; const showWalletBtc = detailSection === 'wallet-btc'; + const showAuthority = detailSection === 'authority'; const showClosure = detailSection === 'closure'; const showProofs = detailSection === 'proofs'; const showHistory = detailSection === 'history'; @@ -196,6 +199,10 @@ export default function TerminalTransactionDetailSurface({ () => buildTerminalWalletBtcOperationProjection({ selectedRun, detail }), [detail, selectedRun], ); + const organizationAuthority = useMemo( + () => buildTerminalOrganizationAuthorityProjection(detail), + [detail], + ); const writtenAssets = detail?.writtenAssets || null; const deliveryMechanism = detail?.shippables || detail?.deliveryMechanism || null; const mergedAssetPackSurface = @@ -344,6 +351,12 @@ export default function TerminalTransactionDetailSurface({

) : null} + {showAuthority ? ( +
+ +
+ ) : null} + {showShippables && mergedAssetPackSurface ? (
+
+ + + {authority.blockers.length ? ( +
+

+ Authority blockers +

+
    + {authority.blockers.map((blocker) => ( +
  • {blocker}
  • + ))} +
+
+ ) : null} + +
+

+ Permission decisions +

+ +
+ +
+

+ Authority proof roots +

+ +
+
+ + ); +} diff --git a/uapi/app/terminal/terminal-organization-authority.ts b/uapi/app/terminal/terminal-organization-authority.ts new file mode 100644 index 000000000..82bce8a42 --- /dev/null +++ b/uapi/app/terminal/terminal-organization-authority.ts @@ -0,0 +1,138 @@ +import type { TerminalRunDetailSnapshot, TerminalJsonRecord } from './terminal-transaction-detail-snapshot'; + +export type TerminalOrganizationAuthorityDecision = { + id: string; + title: string; + summary: string; + supportingText?: string; +}; + +export type TerminalOrganizationAuthorityProjection = { + state: 'allowed' | 'denied' | 'not_projected'; + stateLabel: string; + summary: string; + metrics: Array<{ label: string; value: string }>; + decisions: TerminalOrganizationAuthorityDecision[]; + blockers: string[]; + proofRoots: TerminalOrganizationAuthorityDecision[]; + payload: unknown; +}; + +function isRecord(value: unknown): value is TerminalJsonRecord { + return typeof value === 'object' && value !== null; +} + +function stringValue(value: unknown, fallback = 'n/a') { + return typeof value === 'string' && value.trim() ? value.trim() : fallback; +} + +function arrayValue(value: unknown): unknown[] { + return Array.isArray(value) ? value : []; +} + +function nestedRecord(value: unknown, key: string): TerminalJsonRecord | null { + return isRecord(value) && isRecord(value[key]) ? value[key] as TerminalJsonRecord : null; +} + +function formatDecisionTitle(decision: TerminalJsonRecord) { + const action = stringValue(decision.action, 'unknown action').replaceAll('_', ' '); + const surface = stringValue(decision.interfaceSurface, 'interface'); + return `${surface} · ${action}`; +} + +function decisionSummary(decision: TerminalJsonRecord) { + const state = stringValue(decision.decision, 'not_projected'); + const reason = stringValue(decision.reason, 'authority evidence missing'); + const visibility = stringValue(decision.sourceVisibility, 'source_safe_preview'); + return `${state} · ${reason} · ${visibility}`; +} + +function readProofRoot(decision: TerminalJsonRecord, key: string) { + const proofRoots = nestedRecord(decision, 'proofRoots'); + return proofRoots ? stringValue(proofRoots[key], '') : ''; +} + +function buildProofRootItems(decisions: TerminalJsonRecord[]): TerminalOrganizationAuthorityDecision[] { + const roots = decisions.flatMap((decision) => { + const title = formatDecisionTitle(decision); + return [ + ['authorityRoot', readProofRoot(decision, 'authorityRoot')], + ['roleRoot', readProofRoot(decision, 'roleRoot')], + ['permissionRoot', readProofRoot(decision, 'permissionRoot')], + ['readAccessRoot', readProofRoot(decision, 'readAccessRoot')], + ['interfaceRoot', readProofRoot(decision, 'interfaceRoot')], + ].map(([kind, root]) => ({ + id: `${title}:${kind}:${root}`, + title: `${title} ${kind}`, + summary: root || 'n/a', + })); + }); + + return roots.filter((root) => root.summary !== 'n/a'); +} + +export function buildTerminalOrganizationAuthorityProjection( + detail: TerminalRunDetailSnapshot | null, +): TerminalOrganizationAuthorityProjection { + const authorityRecords = detail?.organizationAuthority ?? []; + + if (!authorityRecords.length) { + return { + state: 'not_projected', + stateLabel: 'Not projected', + summary: + 'Organization permission authority is not attached to this activity yet. Terminal keeps action controls source-safe until role, license, and interface evidence are projected.', + metrics: [ + { label: 'State', value: 'Not projected' }, + { label: 'Decisions', value: '0' }, + { label: 'Proof roots', value: '0' }, + ], + decisions: [], + blockers: ['No organization authority decision was readable from this activity payload.'], + proofRoots: [], + payload: { + organizationAuthority: null, + ledgerSettlement: detail?.ledgerSettlement ?? null, + }, + }; + } + + const denied = authorityRecords.filter((decision) => stringValue(decision.decision, '') === 'denied'); + const allowed = authorityRecords.filter((decision) => stringValue(decision.decision, '') === 'allowed'); + const proofRoots = buildProofRootItems(authorityRecords); + const blockers = denied.flatMap((decision) => { + const reasons = arrayValue(decision.reasons) + .map((reason) => stringValue(reason, '')) + .filter(Boolean); + return reasons.length ? reasons : [stringValue(decision.reason, 'authority denied')]; + }); + const state = denied.length ? 'denied' : allowed.length ? 'allowed' : 'not_projected'; + + return { + state, + stateLabel: state === 'allowed' ? 'Allowed' : state === 'denied' ? 'Denied' : 'Not projected', + summary: + state === 'allowed' + ? 'Registry-derived organization role, read-license, settlement, and interface authority admit the projected action.' + : 'One or more organization authority decisions block protected-source action until role, license, settlement, confirmation, or interface evidence is repaired.', + metrics: [ + { label: 'State', value: state === 'allowed' ? 'Allowed' : state === 'denied' ? 'Denied' : 'Not projected' }, + { label: 'Allowed', value: String(allowed.length) }, + { label: 'Denied', value: String(denied.length) }, + { label: 'Proof roots', value: String(proofRoots.length) }, + ], + decisions: authorityRecords.map((decision) => ({ + id: `${formatDecisionTitle(decision)}:${stringValue(decision.targetAnchor, 'target')}`, + title: formatDecisionTitle(decision), + summary: decisionSummary(decision), + supportingText: stringValue(decision.targetAnchor, ''), + })), + blockers, + proofRoots, + payload: { + organizationAuthority: authorityRecords, + ledgerSettlement: detail?.ledgerSettlement ?? null, + bitcodeActivityState: detail?.bitcodeActivityState ?? null, + }, + }; +} diff --git a/uapi/app/terminal/terminal-protocol-projection.ts b/uapi/app/terminal/terminal-protocol-projection.ts index 3f5f555fb..5811d93a4 100644 --- a/uapi/app/terminal/terminal-protocol-projection.ts +++ b/uapi/app/terminal/terminal-protocol-projection.ts @@ -198,6 +198,7 @@ export function buildProtocolProjectedRunDetail( closureState: null, ledgerSettlement: null, terminalJournal: null, + organizationAuthority: null, bitcodeActivityState: workbench || activeScenario || supplySelection || repository ? { diff --git a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts index 79dc7f4a1..f8ae77057 100644 --- a/uapi/app/terminal/terminal-transaction-detail-snapshot.ts +++ b/uapi/app/terminal/terminal-transaction-detail-snapshot.ts @@ -117,6 +117,7 @@ export interface TerminalRunDetailSnapshot { closureState: TerminalClosureState | null; ledgerSettlement: TerminalLedgerSettlementSnapshot | null; terminalJournal: TerminalJournalReadbackSnapshot | null; + organizationAuthority: TerminalJsonRecord[] | null; bitcodeActivityState: { depositWorkbench?: TerminalDepositReadWorkbench | null; fitWorkbench?: TerminalDepositReadWorkbench | null; @@ -437,6 +438,19 @@ function coerceTerminalJournalReadback(value: unknown): TerminalJournalReadbackS }; } +function coerceOrganizationAuthority(value: unknown): TerminalJsonRecord[] | null { + if (Array.isArray(value)) { + const records = coerceRecordArray(value); + return records.length ? records : null; + } + if (isRecord(value)) { + const decisions = coerceRecordArray(value.decisions); + if (decisions.length) return decisions; + return [value]; + } + return null; +} + function coerceCandidates(value: unknown): TerminalClosureCandidate[] | undefined { if (!Array.isArray(value)) return undefined; return value @@ -767,6 +781,7 @@ export function buildTerminalRunDetailFromSelectedRun( closureState: null, ledgerSettlement: null, terminalJournal: null, + organizationAuthority: null, bitcodeActivityState: null, historyItemCount: selectedRun.itemCount || 0, eventCount: 0, @@ -822,6 +837,13 @@ export function normalizeTerminalRunDetailPayload( coerceTerminalJournalReadback(run.terminal_journal) || coerceTerminalJournalReadback(isRecord(run.output) ? run.output.terminal_journal : null) || base.terminalJournal; + const organizationAuthority = + coerceOrganizationAuthority(run.organization_authority) || + coerceOrganizationAuthority(run.organizationAuthority) || + coerceOrganizationAuthority(isRecord(run.output) ? run.output.organizationAuthority : null) || + coerceOrganizationAuthority(assetPackCompletion?.organizationAuthority) || + coerceOrganizationAuthority(assetPackCompletion?.interfaceAuthority) || + base.organizationAuthority; const bitcodeActivityState = coerceBitcodeActivityState(assetPackCompletion?.bitcodeActivityState) || base.bitcodeActivityState; const runProcessingStats = coerceProcessingStats(run.processing_stats); @@ -861,6 +883,7 @@ export function normalizeTerminalRunDetailPayload( closureState, ledgerSettlement, terminalJournal, + organizationAuthority, bitcodeActivityState, historyItemCount: Array.isArray(run.items) ? run.items.length : base.historyItemCount, eventCount: Array.isArray((payload as TerminalRunHistoryPayload).events) diff --git a/uapi/app/terminal/terminal-transaction-query.ts b/uapi/app/terminal/terminal-transaction-query.ts index 401210b56..5f789c725 100644 --- a/uapi/app/terminal/terminal-transaction-query.ts +++ b/uapi/app/terminal/terminal-transaction-query.ts @@ -44,6 +44,7 @@ export type TerminalTransactionDetailSection = | 'shippables' | 'transaction' | 'wallet-btc' + | 'authority' | 'closure' | 'proofs' | 'history' @@ -54,6 +55,7 @@ const TRANSACTION_DETAIL_SECTION_VALUES: TerminalTransactionDetailSection[] = [ 'shippables', 'transaction', 'wallet-btc', + 'authority', 'closure', 'proofs', 'history', diff --git a/uapi/app/terminal/terminal-transaction-read-model.ts b/uapi/app/terminal/terminal-transaction-read-model.ts index 5f2da13f2..209bc00d9 100644 --- a/uapi/app/terminal/terminal-transaction-read-model.ts +++ b/uapi/app/terminal/terminal-transaction-read-model.ts @@ -17,6 +17,7 @@ export type TerminalTransactionFactFamily = | 'delivery' | 'identity' | 'wallet' + | 'authority' | 'settlement' | 'proof' | 'ledger' @@ -94,6 +95,13 @@ const SECTION_DEFINITIONS: Array<{ summary: 'Wallet signer session, BTC fee quote, PSBT handoff, broadcast, finality, and blocked readiness.', factFamily: 'wallet', }, + { + id: 'authority', + label: 'Authority', + targetId: 'terminalTransactionAuthority', + summary: 'Organization role, read-license, settlement, confirmation, and interface authority decisions.', + factFamily: 'authority', + }, { id: 'closure', label: 'Closure', @@ -241,6 +249,19 @@ function resolveSectionAvailability({ }; } + if (sectionId === 'authority') { + const decisionCount = detail?.organizationAuthority?.length || 0; + return { + availability: decisionCount > 0 ? 'available' : 'empty', + blocker: decisionCount > 0 + ? null + : 'No organization role, read-license, settlement, or interface authority projection is attached yet.', + metricCount: 4, + rowCount: decisionCount, + payloadAvailable: decisionCount > 0, + }; + } + if (sectionId === 'closure') { const hasClosure = Boolean(detail?.closureState) || diff --git a/uapi/jest.config.cjs b/uapi/jest.config.cjs index 0a3f4b1eb..8d2524531 100644 --- a/uapi/jest.config.cjs +++ b/uapi/jest.config.cjs @@ -142,6 +142,7 @@ module.exports = { '/tests/terminalPipelineHarnessClient.test.ts', '/tests/pipelineExecutionLogHeader.test.tsx', '/tests/terminalJournalReconciliation.test.ts', + '/tests/terminalOrganizationAuthority.test.ts', '/tests/terminalTransactionActivitySurface.test.tsx', '/tests/terminalTransactionDetail.test.ts', '/tests/terminalTransactionDetailCards.test.tsx', diff --git a/uapi/tests/terminalJournalReconciliation.test.ts b/uapi/tests/terminalJournalReconciliation.test.ts index 876c8f2c7..dc227ecdf 100644 --- a/uapi/tests/terminalJournalReconciliation.test.ts +++ b/uapi/tests/terminalJournalReconciliation.test.ts @@ -19,6 +19,7 @@ function detail(overrides: Partial): TerminalRunDetai closureState: null, ledgerSettlement: null, terminalJournal: null, + organizationAuthority: null, bitcodeActivityState: null, historyItemCount: 0, eventCount: 0, diff --git a/uapi/tests/terminalOrganizationAuthority.test.ts b/uapi/tests/terminalOrganizationAuthority.test.ts new file mode 100644 index 000000000..3e2bb59e1 --- /dev/null +++ b/uapi/tests/terminalOrganizationAuthority.test.ts @@ -0,0 +1,74 @@ +import { buildTerminalOrganizationAuthorityProjection } from '@/app/terminal/terminal-organization-authority'; +import type { TerminalRunDetailSnapshot } from '@/app/terminal/terminal-transaction-detail-snapshot'; + +function detailWithAuthority( + organizationAuthority: TerminalRunDetailSnapshot['organizationAuthority'], +): TerminalRunDetailSnapshot { + return { + summary: 'Authority test detail', + shippables: null, + assetPackSynthesisArtifacts: null, + writtenAssets: null, + deliveryMechanism: null, + repoSnapshot: null, + processingStats: { + time: null, + tokenTotal: null, + measuredBtd: null, + btcFeeUsdEquivalent: null, + averageLatencyMs: null, + }, + proofStatus: null, + closureFocus: null, + closureFollowThrough: null, + closureState: null, + ledgerSettlement: null, + terminalJournal: null, + organizationAuthority, + bitcodeActivityState: null, + historyItemCount: 0, + eventCount: 0, + }; +} + +describe('terminal organization authority projection', () => { + it('projects allowed decisions and authority proof roots', () => { + const projection = buildTerminalOrganizationAuthorityProjection( + detailWithAuthority([ + { + decision: 'allowed', + interfaceSurface: 'mcp', + action: 'deliver_asset_pack', + reason: 'role_authorized', + reasons: ['role_authorized', 'licensed_read_access_authorized'], + sourceVisibility: 'protected_source_allowed', + targetAnchor: 'github:engineeredsoftware/ENGI/pull/42', + proofRoots: { + authorityRoot: 'btd-proof-root:organization-interface-authority:abc123', + roleRoot: 'btd-proof-root:organization-role:def456', + permissionRoot: 'btd-proof-root:organization-permission:ghi789', + }, + }, + ]), + ); + + expect(projection.state).toBe('allowed'); + expect(projection.metrics).toEqual(expect.arrayContaining([{ label: 'Allowed', value: '1' }])); + expect(projection.decisions[0]).toMatchObject({ + title: 'mcp · deliver asset pack', + summary: 'allowed · role_authorized · protected_source_allowed', + }); + expect(projection.proofRoots.map((root) => root.summary)).toEqual( + expect.arrayContaining(['btd-proof-root:organization-interface-authority:abc123']), + ); + }); + + it('keeps missing authority visible as a not-projected blocker', () => { + const projection = buildTerminalOrganizationAuthorityProjection(detailWithAuthority(null)); + + expect(projection.state).toBe('not_projected'); + expect(projection.blockers).toEqual([ + 'No organization authority decision was readable from this activity payload.', + ]); + }); +}); diff --git a/uapi/tests/terminalTransactionActivitySurface.test.tsx b/uapi/tests/terminalTransactionActivitySurface.test.tsx index 49b315796..3c2f81975 100644 --- a/uapi/tests/terminalTransactionActivitySurface.test.tsx +++ b/uapi/tests/terminalTransactionActivitySurface.test.tsx @@ -45,6 +45,7 @@ const detail: TerminalRunDetailSnapshot = { closureState: null, ledgerSettlement: null, terminalJournal: null, + organizationAuthority: null, bitcodeActivityState: { repositoryAnchor: { provider: 'github', diff --git a/uapi/tests/terminalTransactionDetail.test.ts b/uapi/tests/terminalTransactionDetail.test.ts index 14547577f..194ff7d9b 100644 --- a/uapi/tests/terminalTransactionDetail.test.ts +++ b/uapi/tests/terminalTransactionDetail.test.ts @@ -84,6 +84,7 @@ const detail: TerminalRunDetailSnapshot = { }, ledgerSettlement: null, terminalJournal: null, + organizationAuthority: null, closureState: { canonLabel: 'persisted closure posture', verification: { diff --git a/uapi/tests/terminalTransactionDetailCards.test.tsx b/uapi/tests/terminalTransactionDetailCards.test.tsx index 2b949c0c0..a5a320822 100644 --- a/uapi/tests/terminalTransactionDetailCards.test.tsx +++ b/uapi/tests/terminalTransactionDetailCards.test.tsx @@ -5,6 +5,7 @@ import TerminalTransactionClosureCard from '@/app/terminal/TerminalTransactionCl import TerminalTransactionHistoryCard from '@/app/terminal/TerminalTransactionHistoryCard'; import TerminalTransactionIdentityCard from '@/app/terminal/TerminalTransactionIdentityCard'; import TerminalTransactionJournalReconciliationCard from '@/app/terminal/TerminalTransactionJournalReconciliationCard'; +import TerminalTransactionOrganizationAuthorityCard from '@/app/terminal/TerminalTransactionOrganizationAuthorityCard'; import TerminalTransactionProofsCard from '@/app/terminal/TerminalTransactionProofsCard'; describe('Terminal transaction detail cards', () => { @@ -162,6 +163,41 @@ describe('Terminal transaction detail cards', () => { }, }} /> + , ); @@ -174,6 +210,10 @@ describe('Terminal transaction detail cards', () => { expect(screen.getByText('Metaphysical canonical facts')).toBeTruthy(); expect(screen.getByText('Repair actions')).toBeTruthy(); expect(screen.getByText('Proof roots')).toBeTruthy(); + expect(screen.getByText('Organization authority')).toBeTruthy(); + expect(screen.getByText('Role, read-license, settlement, and interface permission')).toBeTruthy(); + expect(screen.getByText('Permission decisions')).toBeTruthy(); + expect(screen.getByText('Authority proof roots')).toBeTruthy(); expect(screen.getAllByText('Structured payload shape').length).toBeGreaterThanOrEqual(3); expect(screen.getAllByText('selection-materialization').length).toBeGreaterThan(0); expect(screen.getAllByText('run-001').length).toBeGreaterThan(0); diff --git a/uapi/tests/terminalTransactionDetailSnapshot.test.ts b/uapi/tests/terminalTransactionDetailSnapshot.test.ts index 78840c091..aec769cff 100644 --- a/uapi/tests/terminalTransactionDetailSnapshot.test.ts +++ b/uapi/tests/terminalTransactionDetailSnapshot.test.ts @@ -71,6 +71,7 @@ describe('terminal-transaction-detail-snapshot helpers', () => { closureState: null, ledgerSettlement: null, terminalJournal: null, + organizationAuthority: null, bitcodeActivityState: { repositoryAnchor: { provider: 'github', @@ -317,6 +318,21 @@ describe('terminal-transaction-detail-snapshot helpers', () => { }, journalEntryIds: ['journal-mint-run-1'], }, + organizationAuthority: [ + { + kind: 'btd_organization_interface_authority_decision', + decision: 'allowed', + interfaceSurface: 'terminal', + action: 'deliver_asset_pack', + reason: 'role_authorized', + sourceVisibility: 'protected_source_allowed', + targetAnchor: 'github:bitcode/bitcode/pull/2', + proofRoots: { + authorityRoot: 'btd-proof-root:organization-interface-authority:abc123', + roleRoot: 'btd-proof-root:organization-role:def456', + }, + }, + ], }, terminal_journal: { expectedJournalEntryIds: ['journal-mint-run-1'], @@ -462,6 +478,13 @@ describe('terminal-transaction-detail-snapshot helpers', () => { btcFeeTransactions: [{ receipt_id: 'btc-fee-run-1', finality_state: 'prepared' }], }, }); + expect(snapshot.organizationAuthority).toEqual([ + expect.objectContaining({ + action: 'deliver_asset_pack', + decision: 'allowed', + sourceVisibility: 'protected_source_allowed', + }), + ]); expect(snapshot.historyItemCount).toBe(2); expect(snapshot.eventCount).toBe(3); }); diff --git a/uapi/tests/terminalTransactionReadModel.test.ts b/uapi/tests/terminalTransactionReadModel.test.ts index 175b2012c..f33f58f64 100644 --- a/uapi/tests/terminalTransactionReadModel.test.ts +++ b/uapi/tests/terminalTransactionReadModel.test.ts @@ -162,6 +162,7 @@ describe('terminal transaction read model', () => { writtenAssets: null, closureFollowThrough: null, terminalJournal: null, + organizationAuthority: null, eventCount: 0, }, detailSection: 'console', diff --git a/uapi/tests/terminalWalletBtcOperation.test.ts b/uapi/tests/terminalWalletBtcOperation.test.ts index 8bc14a68d..fcb32d10f 100644 --- a/uapi/tests/terminalWalletBtcOperation.test.ts +++ b/uapi/tests/terminalWalletBtcOperation.test.ts @@ -71,6 +71,7 @@ function detailWithBtcFee(finalityState = 'confirmed'): TerminalRunDetailSnapsho readLicenseId: 'license-1', }, terminalJournal: null, + organizationAuthority: null, bitcodeActivityState: null, historyItemCount: 0, eventCount: 0, From f059a0d05bbc9ed1930329e5cdf35f18dcf67847 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 12:22:01 -0300 Subject: [PATCH 08/18] V29 Gate 8: Formalize protocol package boundary (#27) Move gate-critical canon helpers behind the @bitcode/protocol package index, retarget root canonical scripts away from direct protocol-demonstration source imports, and correct package-local repo-root defaults for spec and proof helpers. Document the Gate 8 package-native boundary in the V29 spec family and protocol README, add a fail-closed Gate 8 checker, expand protocol package tests, and wire CI to run protocol package checks plus the UAPI commercial boundary test. Validation: pnpm --filter @bitcode/protocol typecheck; pnpm --filter @bitcode/protocol test; pnpm run check:v29-gate8; node scripts/check-bitcode-spec-family.mjs --version V28 --mode promoted --current-target V28; node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28; node scripts/check-bitcode-canonical-inputs.mjs --current-target V28; node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29; node scripts/run-bitcode-spec-quality.mjs --mode basic; pnpm --dir uapi exec jest --runTestsByPath tests/protocolCommercialBoundary.test.ts --runInBand; git diff --check. --- .github/workflows/bitcode-gate-quality.yml | 4 + BITCODE_SPEC_V29.md | 21 ++ BITCODE_SPEC_V29_DELTA.md | 10 + BITCODE_SPEC_V29_NOTES.md | 21 ++ BITCODE_SPEC_V29_PARITY_MATRIX.md | 34 ++- package.json | 1 + packages/protocol/README.md | 30 ++- packages/protocol/src/canon-posture.js | 4 +- .../src/canonical/proven-generator.js | 2 +- .../protocol/src/canonical/v21-specifying.js | 2 +- .../src/canonical/v22-canon-posture.js | 2 +- .../canonical/v26-product-readiness-audit.js | 2 +- packages/protocol/src/index.d.ts | 21 ++ packages/protocol/src/index.js | 11 + .../test/protocol-package-boundary.test.js | 34 +++ scripts/check-bitcode-canon-posture-drift.mjs | 2 +- scripts/check-bitcode-canonical-inputs.mjs | 2 +- scripts/check-bitcode-pre-commit.mjs | 4 +- scripts/check-bitcode-spec-family.mjs | 2 +- ...te8-demonstration-origin-formalization.mjs | 243 ++++++++++++++++++ scripts/generate-bitcode-proven.mjs | 2 +- scripts/run-bitcode-spec-quality.mjs | 2 +- 22 files changed, 432 insertions(+), 24 deletions(-) create mode 100644 scripts/check-v29-gate8-demonstration-origin-formalization.mjs diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 3c87202f0..95f1019e9 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -69,6 +69,7 @@ jobs: node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs --skip-branch-check node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs --skip-branch-check node scripts/check-v29-gate7-organization-permission-authority.mjs --skip-branch-check + node scripts/check-v29-gate8-demonstration-origin-formalization.mjs --skip-branch-check - name: Validate source casing and imports run: | @@ -83,6 +84,7 @@ jobs: pnpm --dir packages/chatgptapp exec tsc --noEmit --pretty false pnpm --filter @bitcode/pipeline-asset-pack typecheck pnpm --filter @bitcode/pipeline-hosts typecheck + pnpm --filter @bitcode/protocol typecheck - name: Test gate packages run: | @@ -97,6 +99,7 @@ jobs: pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath src/__tests__/reading-pipeline-observability.test.ts src/__tests__/reading-pipeline-contract.test.ts --runInBand pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath src/__tests__/asset-pack-disclosure.test.ts src/__tests__/postprocess.test.ts src/__tests__/read-need.test.ts --runInBand pnpm --filter @bitcode/pipeline-hosts exec jest --config jest.config.cjs --passWithNoTests --forceExit + pnpm --filter @bitcode/protocol test - name: Test staged Reading route and Terminal harness contracts run: | @@ -110,6 +113,7 @@ jobs: 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/pipelineExecutionLogHeader.test.tsx \ diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index 26a5e7530..8103ff6ff 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -147,6 +147,27 @@ Layer boundaries: - 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. +## V29 demonstration-origin commercial formalization canon + +V29 Gate 8 makes demonstration-origin canonical helpers package-native commercial APIs. +The formal package boundary is `packages/protocol` exposed as `@bitcode/protocol`. +Commercial scripts, workflows, API surfaces, Terminal code, and package tests must import canonical posture, spec-family checks, canon-drift checks, canonical-input checks, and proof generation from `packages/protocol/src/index.js` or from the package export. +They must not import `protocol-demonstration/src/*` runtime modules. + +`protocol-demonstration/` remains valuable, but it is a standalone minimal witness, not a commercial runtime dependency. +It may be executed by its own test and proof workflows. +It may be cited as historical evidence by generated proof inventories. +It must not be the imported implementation source for gate checks, promotion scripts, commercial APIs, or Terminal runtime code. + +The commercial protocol package owns the active/draft posture while V29 is in flight: + +- `ACTIVE_CANON_VERSION = 'V28'`; +- `DRAFT_TARGET_VERSION = 'V29'`; +- spec-family, canonical-input, canon-posture-drift, and proven-generation helpers are exported through the package index; +- package tests and Gate 8 checks fail closed on direct demonstration-source imports. + +This formalization preserves the demonstration boundary while allowing V29 promotion and later gates to operate from package-owned commercial source. + ## V29 canonical domain model The V29 domain model extends V28 operationally: diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index a6549ad17..fe5199c21 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -169,6 +169,16 @@ Closure acceptance: Gate 8 owns cleanup of freshly ported demonstration-origin internals into package-native APIs, no demonstration runtime imports, durable package tests, and updated internal/public documentation. +Closure acceptance: + +- `@bitcode/protocol` exports active/draft canon posture, spec-family checks, canonical-input checks, canon-posture-drift checks, and canonical proven-generation helpers through the package index and type declarations. +- Root scripts for spec quality, spec-family validation, canonical-input validation, canon-posture drift, pre-commit posture, and proven generation import those helpers from the protocol package instead of `protocol-demonstration/src/*`. +- Commercial/runtime source scans fail closed on direct imports from standalone demonstration source. +- The protocol package records active V28 / draft V29 posture while V29 is being developed. +- Protocol package tests prove exported helpers, posture, provenance-helper availability, repository-revision deposit behavior, and direct demonstration-source import boundaries. +- Gate-quality CI runs the Gate 8 checker, protocol package typecheck/test, and the UAPI commercial protocol boundary test. +- V29 SPEC, DELTA, NOTES, PARITY, protocol package README, package scripts, and gate-quality workflow name the Gate 8 formalization boundary. + ### Gate 9: Terminal UX Quality And Browser Proof Gate 9 owns accessibility, responsive layout, copy/prose clarity, empty/loading/blocked/failed states, Playwright coverage, and visual/browser verification for the complete Terminal transaction cockpit. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 1356628cd..eb25f8062 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -188,6 +188,27 @@ Gate 7 completion condition: - Focused BTD, API, MCP, ChatGPT App, pipeline-hosts, and UAPI tests cover the authority primitive and interface surfaces. - Spec, delta, notes, parity, Terminal README, package scripts, and gate-quality workflow name the Gate 7 closure surface. +## Gate 8 working notes + +Gate 8 is a commercial-source boundary cleanup gate. +Earlier versions intentionally kept some proof and canon helpers close to the standalone demonstration so the minimal witness could remain easy to audit. +V29 keeps that witness, but the commercial repository now needs package-native imports for every helper used by scripts, workflows, Terminal, APIs, and promotion checks. + +Accepted Gate 8 posture: + +- `@bitcode/protocol` is the package boundary for canonical posture, spec-family, canonical-input, canon-posture-drift, and proven-generation helpers. +- `protocol-demonstration/` remains executable as a standalone minimal witness and may remain cited in proof inventories. +- Commercial/runtime code and root scripts must not import from `protocol-demonstration/src/*`. +- The protocol package posture must say active V28 and draft V29 until promotion. +- The protocol package tests own the durable import-boundary scan so future gates cannot silently regress into demonstration runtime imports. +- Gate-quality CI must run protocol package typecheck/test, the Gate 8 checker, and the UAPI commercial protocol boundary test. + +Gate 8 completion condition: + +- `pnpm run check:v29-gate8` passes. +- Protocol package tests pass. +- The spec family, package README, root scripts, and CI all name and enforce the package-native boundary. + ## Later-version boundaries - V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index ff8dcf814..768f58a64 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -55,7 +55,7 @@ No `_legacy/` source is active source truth. | AssetPack disclosure rights | Gate 5 | `asset-pack-disclosure.ts`, AssetPack postprocess, sandbox harness, BTD access tests, Terminal disclosure review UI, Gate 5 checker | drafted | Source-safe preview and paid unlock are proven without protected-source leakage. | | Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, sandbox harness settlement evidence, Terminal repair UI, Gate 6 checker | drafted | Ledger, database, and metaphysical state drift is classified, proof-rooted, repair-actioned, and visible. | | Organization permission authority | Gate 7 | `packages/btd/src/authority.ts`, BTD/API/MCP/ChatGPT App tests, sandbox harness authority evidence, Terminal Authority section, Gate 7 checker | drafted | Registry-derived roles, holdings, read-license authority, settlement, confirmation, and interface admission govern actions. | -| Commercial formalization | Gate 8 | packages/protocol, package tests, import scans, docs | pending | Demonstration-origin commercial internals are package-native and no runtime demo imports remain. | +| Commercial formalization | Gate 8 | `packages/protocol/src/index.js`, `packages/protocol/src/canon-posture.js`, root scripts, protocol package tests, import scans, docs, Gate 8 checker | drafted | Demonstration-origin commercial internals are package-native and no direct demonstration-source imports remain in commercial/runtime sources. | | Terminal UX quality | Gate 9 | Playwright/Jest/a11y/responsive/browser QA | pending | Complete transaction cockpit is usable by default and inspectable in detail. | | Promotion readiness | Gate 10 | promotion workflow, `.bitcode/v29-*`, `BITCODE_SPEC_V29_PROVEN.md` | pending | `version/v29` can promote to `main` only after all V29 checks pass. | @@ -72,7 +72,8 @@ No `_legacy/` source is active source truth. | Gate 4 Reading observability | `pnpm run check:v29-gate4` proves contract-aware Reading stream telemetry and Terminal rendering | drafted | | Gate 5 AssetPack disclosure | `pnpm run check:v29-gate5` proves source-safe disclosure review, leakage detection, Terminal preview rendering, and PR title enforcement | drafted | | Gate 7 organization authority | `pnpm run check:v29-gate7` proves shared org/interface authority across BTD, API, MCP, ChatGPT App, harness, and Terminal | drafted | -| Product implementation gates | Gates 8-9 close remaining Terminal transaction depth with tests and docs | pending | +| Gate 8 commercial formalization | `pnpm run check:v29-gate8` proves package-native protocol exports, V28/V29 posture, script import cleanup, docs, tests, and CI wiring | drafted | +| Product implementation gates | Gate 9 closes remaining Terminal transaction UX quality with browser proof | pending | | Promotion gate | Gate 10 closes generated proof and promotion automation | pending | ## Gate 1 Parity @@ -242,3 +243,32 @@ Gate 7 completion condition: - Gate-quality CI invokes the Gate 7 checker and focused tests. - Gate 7 does not add broad enterprise RBAC administration beyond Terminal transaction authority; later versions may deepen team policy authoring. - Gate 7 does not reveal protected source before settlement and does not add versioned API routes or source identifiers. + +## Gate 8 Parity + +Gate 8 closes the demonstration-origin commercial formalization slice by moving gate-critical helpers behind the protocol package boundary. + +Accepted surfaces: + +- `packages/protocol/src/index.js` exports canonical posture, spec-family validation, canonical-input validation, canon-posture-drift validation, generated artifact builders, and canonical proven-generation helpers. +- `packages/protocol/src/index.d.ts` declares the same package-native API surface for consumers that type-check against the protocol package. +- `packages/protocol/src/canon-posture.js` declares active V28 and draft V29 while V29 gates are in progress. +- Root scripts for spec-family checks, canonical-input checks, canon-posture drift, spec quality, pre-commit posture, and proven generation import through the protocol package source boundary. +- `packages/protocol/test/protocol-package-boundary.test.js` proves package exports, posture, provenance-helper availability, repository-revision deposit behavior, and direct demonstration-source import boundaries. +- `uapi/tests/protocolCommercialBoundary.test.ts` remains the commercial application boundary scan proving UAPI depends on `@bitcode/protocol` and not the standalone demonstration package. +- `.github/workflows/bitcode-gate-quality.yml` runs the Gate 8 checker, protocol package typecheck/test, and the commercial protocol boundary test. + +Accepted boundaries: + +- Gate 8 does not delete the standalone protocol demonstration. +- Gate 8 does not forbid generated proof inventories or historical documentation from citing `protocol-demonstration/` as evidence. +- Gate 8 forbids direct imports from standalone demonstration source in commercial/runtime source and root scripts. +- Gate 8 does not promote `BITCODE_SPEC.txt` to V29. +- Gate 8 does not add versioned API routes or source identifiers. + +Gate 8 completion condition: + +- `pnpm run check:v29-gate8` passes. +- Focused protocol package typecheck/test and the UAPI commercial protocol boundary test pass. +- V29 SPEC, DELTA, NOTES, PARITY, protocol package README, package scripts, and gate-quality workflow name the formalized package-native boundary. +- Root scripts use protocol package exports for canonical helpers and do not directly import `protocol-demonstration/src/*`. diff --git a/package.json b/package.json index 1b751773d..8828780e9 100644 --- a/package.json +++ b/package.json @@ -51,6 +51,7 @@ "check:v29-gate5": "node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs", "check:v29-gate6": "node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs", "check:v29-gate7": "node scripts/check-v29-gate7-organization-permission-authority.mjs", + "check:v29-gate8": "node scripts/check-v29-gate8-demonstration-origin-formalization.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 08c3e6f80..9c2b4f633 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -2,12 +2,24 @@ Formal Bitcode protocol package for commercial source. -V28 starts the separation between the deterministic `protocol-demonstration` -reference and commercial runtime imports. Commercial surfaces should import -protocol state, API context, and protocol primitives from this package rather -than importing the standalone demonstration package. - -Some implementation internals are still freshly ported from the demonstration -and intentionally retain source proximity for parity. V29 must continue -commercializing those internals into narrower packages and cleaner module -boundaries. +V29 Gate 8 makes 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, +and proven-generation helpers from `@bitcode/protocol` or +`packages/protocol/src/index.js`. + +They must not import `protocol-demonstration/src/*`. The demonstration remains +a standalone minimal witness and may still be executed or cited by proof +inventories, but it is not a commercial runtime implementation dependency. + +Current exported commercial helpers include: + +- active/draft canon posture (`V28` active, `V29` draft during V29 work); +- spec-family and canonical-input validation helpers; +- canon-posture drift reporting; +- canonical proven-generation helpers; +- the package app/server context used by commercial interfaces. + +The package boundary is enforced by `packages/protocol` tests, the UAPI +commercial protocol boundary test, and `check:v29-gate8`. diff --git a/packages/protocol/src/canon-posture.js b/packages/protocol/src/canon-posture.js index c485f9d51..aa5848621 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 = 'V27'; -export const DRAFT_TARGET_VERSION = 'V28'; +export const ACTIVE_CANON_VERSION = 'V28'; +export const DRAFT_TARGET_VERSION = 'V29'; export const CURRENT_CANON_OPERATOR_LABEL = `${ACTIVE_CANON_VERSION} active canon / ${DRAFT_TARGET_VERSION} system draft`; /** diff --git a/packages/protocol/src/canonical/proven-generator.js b/packages/protocol/src/canonical/proven-generator.js index 3a5075004..ddafabe1e 100644 --- a/packages/protocol/src/canonical/proven-generator.js +++ b/packages/protocol/src/canonical/proven-generator.js @@ -49,7 +49,7 @@ const COLLECTED_PROVEN_RUN_CACHE = new Map(); const BASE_PROVEN_DATA_CACHE = new Map(); const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const REPO_ROOT = path.resolve(__dirname, '../../..'); +const REPO_ROOT = path.resolve(__dirname, '../../../..'); /** * @param {string} version diff --git a/packages/protocol/src/canonical/v21-specifying.js b/packages/protocol/src/canonical/v21-specifying.js index 040d390ae..80878fbd3 100644 --- a/packages/protocol/src/canonical/v21-specifying.js +++ b/packages/protocol/src/canonical/v21-specifying.js @@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -export const DEFAULT_V21_SPECIFYING_REPO_ROOT = path.resolve(__dirname, '../../..'); +export const DEFAULT_V21_SPECIFYING_REPO_ROOT = path.resolve(__dirname, '../../../..'); export const COMMON_REQUIRED_SPEC_SECTIONS = [ 'Status', diff --git a/packages/protocol/src/canonical/v22-canon-posture.js b/packages/protocol/src/canonical/v22-canon-posture.js index dd5dba705..8e84bc36d 100644 --- a/packages/protocol/src/canonical/v22-canon-posture.js +++ b/packages/protocol/src/canonical/v22-canon-posture.js @@ -18,7 +18,7 @@ import { buildV21GeneratedArtifactContents } from './v21-specifying.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -export const DEFAULT_V22_CANON_POSTURE_REPO_ROOT = path.resolve(__dirname, '../../..'); +export const DEFAULT_V22_CANON_POSTURE_REPO_ROOT = path.resolve(__dirname, '../../../..'); export const V22_CANON_POSTURE_REPORT_ID = 'v22-canon-posture-drift-report'; export const V22_CANON_POSTURE_GENERATOR_ID = 'bitcode.v22-canon-posture.v1'; export const V23_CANON_POSTURE_REPORT_ID = 'v23-canon-posture-drift-report'; diff --git a/packages/protocol/src/canonical/v26-product-readiness-audit.js b/packages/protocol/src/canonical/v26-product-readiness-audit.js index f173005a2..edc828535 100644 --- a/packages/protocol/src/canonical/v26-product-readiness-audit.js +++ b/packages/protocol/src/canonical/v26-product-readiness-audit.js @@ -6,7 +6,7 @@ import { fileURLToPath } from 'node:url'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); -const DEFAULT_REPO_ROOT = path.resolve(__dirname, '../../..'); +const DEFAULT_REPO_ROOT = path.resolve(__dirname, '../../../..'); const PRODUCT_READINESS_AUDIT_ROWS = [ { diff --git a/packages/protocol/src/index.d.ts b/packages/protocol/src/index.d.ts index 7a78d4b0c..5dd56ee8c 100644 --- a/packages/protocol/src/index.d.ts +++ b/packages/protocol/src/index.d.ts @@ -31,3 +31,24 @@ export function startServer( export const ACTIVE_CANON_VERSION: string; export const DRAFT_TARGET_VERSION: string; + +export interface BitcodeProtocolReport { + passed: boolean; + [key: string]: unknown; +} + +export interface BitcodeProvenMarkdownPackage { + data: unknown; + markdown: string; + artifacts?: Record; + [key: string]: unknown; +} + +export const PROVEN_GENERATOR_ID: string; + +export function buildV21SpecFamilyReport(input?: Record): BitcodeProtocolReport; +export function buildV21CanonicalInputReport(input?: Record): BitcodeProtocolReport; +export function buildV21GeneratedArtifactContents(input?: Record): unknown; +export function buildCanonPostureDriftReport(input?: Record): BitcodeProtocolReport; +export function defaultProvenOutputPath(version: string): string; +export function generateCanonicalProvenMarkdown(input?: Record): BitcodeProvenMarkdownPackage; diff --git a/packages/protocol/src/index.js b/packages/protocol/src/index.js index 79f8ffbef..3ac95173f 100644 --- a/packages/protocol/src/index.js +++ b/packages/protocol/src/index.js @@ -6,3 +6,14 @@ export { DEFAULT_BITCODE_PUBLIC_DIR } from '../server.js'; export { ACTIVE_CANON_VERSION, DRAFT_TARGET_VERSION } from './canon-posture.js'; +export { + buildV21CanonicalInputReport, + buildV21GeneratedArtifactContents, + buildV21SpecFamilyReport +} from './canonical/v21-specifying.js'; +export { buildCanonPostureDriftReport } from './canonical/v22-canon-posture.js'; +export { + PROVEN_GENERATOR_ID, + defaultProvenOutputPath, + generateCanonicalProvenMarkdown +} from './canonical/proven-generator.js'; diff --git a/packages/protocol/test/protocol-package-boundary.test.js b/packages/protocol/test/protocol-package-boundary.test.js index c0084be39..97a602ee9 100644 --- a/packages/protocol/test/protocol-package-boundary.test.js +++ b/packages/protocol/test/protocol-package-boundary.test.js @@ -7,7 +7,9 @@ import test from 'node:test'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const packageRoot = path.resolve(__dirname, '..'); +const repoRoot = path.resolve(packageRoot, '..', '..'); const importBoundaryPattern = /(?:import\s+(?:[^'"]+\s+from\s+)?|import\s*\(|require\s*\()\s*['"][^'"]*(?:@bitcode\/protocol-demonstration|protocol-demonstration\/)/; +const demonstrationSourceImportPattern = /(?:import\s+(?:[^'"]+\s+from\s+)?|import\s*\(|require\s*\()\s*['"][^'"]*(?:@bitcode\/protocol-demonstration|protocol-demonstration\/src)/; function collectRuntimeFiles(root) { const files = []; @@ -41,6 +43,38 @@ test('@bitcode/protocol does not import the standalone protocol demonstration', assert.equal(typeof protocol.createAppContext, 'function'); }); +test('@bitcode/protocol commercial formalization exports package-native canon helpers', async () => { + const protocol = await import('../src/index.js'); + + assert.equal(protocol.ACTIVE_CANON_VERSION, 'V28'); + assert.equal(protocol.DRAFT_TARGET_VERSION, 'V29'); + assert.equal(typeof protocol.buildV21SpecFamilyReport, 'function'); + assert.equal(typeof protocol.buildV21CanonicalInputReport, 'function'); + assert.equal(typeof protocol.buildV21GeneratedArtifactContents, 'function'); + assert.equal(typeof protocol.buildCanonPostureDriftReport, 'function'); + assert.equal(typeof protocol.PROVEN_GENERATOR_ID, 'string'); + assert.equal(typeof protocol.defaultProvenOutputPath, 'function'); + assert.equal(typeof protocol.generateCanonicalProvenMarkdown, 'function'); + assert.equal(protocol.defaultProvenOutputPath('V28'), 'BITCODE_SPEC_V28_PROVEN.md'); + const specFamilyReport = protocol.buildV21SpecFamilyReport({ + version: 'V29', + mode: 'draft', + currentTarget: 'V28', + }); + const canonicalInputReport = protocol.buildV21CanonicalInputReport({ currentTarget: 'V28' }); + assert.equal(specFamilyReport.passed, true); + assert.equal(canonicalInputReport.passed, true); +}); + +test('commercial scripts do not directly import standalone demonstration source', () => { + const runtimeFiles = collectRuntimeFiles(path.join(repoRoot, 'scripts')); + const violations = runtimeFiles + .filter((filePath) => demonstrationSourceImportPattern.test(readFileSync(filePath, 'utf8'))) + .map((filePath) => path.relative(repoRoot, filePath)); + + assert.deepEqual(violations, []); +}); + test('@bitcode/protocol witness bundle does not overwrite commercial route titles when embedded', () => { const appBundle = readFileSync(path.join(packageRoot, 'public', 'app.js'), 'utf8'); diff --git a/scripts/check-bitcode-canon-posture-drift.mjs b/scripts/check-bitcode-canon-posture-drift.mjs index 9ef888ac7..f46074978 100644 --- a/scripts/check-bitcode-canon-posture-drift.mjs +++ b/scripts/check-bitcode-canon-posture-drift.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { buildCanonPostureDriftReport } from '../protocol-demonstration/src/canonical/v22-canon-posture.js'; +import { buildCanonPostureDriftReport } from '../packages/protocol/src/index.js'; function projectLabel(version) { const numeric = Number(String(version || '').replace(/^V/u, '')); diff --git a/scripts/check-bitcode-canonical-inputs.mjs b/scripts/check-bitcode-canonical-inputs.mjs index f3e143cf7..09ddaa70a 100644 --- a/scripts/check-bitcode-canonical-inputs.mjs +++ b/scripts/check-bitcode-canonical-inputs.mjs @@ -1,6 +1,6 @@ #!/usr/bin/env node -import { buildV21CanonicalInputReport } from '../protocol-demonstration/src/canonical/v21-specifying.js'; +import { buildV21CanonicalInputReport } from '../packages/protocol/src/index.js'; function projectLabel(version) { return 'Bitcode'; diff --git a/scripts/check-bitcode-pre-commit.mjs b/scripts/check-bitcode-pre-commit.mjs index 3bf0fe841..46c3c706a 100644 --- a/scripts/check-bitcode-pre-commit.mjs +++ b/scripts/check-bitcode-pre-commit.mjs @@ -4,7 +4,7 @@ import { execFileSync } from 'node:child_process'; import { readFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; -import { ACTIVE_CANON_VERSION } from '../protocol-demonstration/src/canon-posture.js'; +import { ACTIVE_CANON_VERSION } from '../packages/protocol/src/index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); @@ -14,7 +14,7 @@ const defaultQualityScript = path.join(defaultRepoRoot, 'scripts/run-bitcode-spe const SPEC_RELEVANT_PATHS = [ /^BITCODE_SPEC(?:IFYING)?(?:_.*)?\.md$/u, /^BITCODE_SPEC\.txt$/u, - /^packages\/protocol-demonstration\/src\/canonical\/v21-specifying\.js$/u, + /^packages\/protocol\/src\/canonical\/v21-specifying\.js$/u, /^package\.json$/u, /^scripts\/(?:check-bitcode-|check-v28-metadevelopment-readiness|check-v29-gate1-objectives-and-gating|prepare-bitcode-spec-family-promotion|prepare-bitcode-runtime-canon-promotion|promote-bitcode-canon|run-bitcode-spec-quality|setup-bitcode-git-hooks)/u, /^\.githooks\/(?:pre-commit|commit-msg)$/u, diff --git a/scripts/check-bitcode-spec-family.mjs b/scripts/check-bitcode-spec-family.mjs index 46c6eea5d..fe907913a 100644 --- a/scripts/check-bitcode-spec-family.mjs +++ b/scripts/check-bitcode-spec-family.mjs @@ -3,7 +3,7 @@ import { readFileSync } from 'node:fs'; import path from 'node:path'; -import { buildV21SpecFamilyReport } from '../protocol-demonstration/src/canonical/v21-specifying.js'; +import { buildV21SpecFamilyReport } from '../packages/protocol/src/index.js'; function projectLabel(version) { return 'Bitcode'; diff --git a/scripts/check-v29-gate8-demonstration-origin-formalization.mjs b/scripts/check-v29-gate8-demonstration-origin-formalization.mjs new file mode 100644 index 000000000..533362007 --- /dev/null +++ b/scripts/check-v29-gate8-demonstration-origin-formalization.mjs @@ -0,0 +1,243 @@ +#!/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, '..'); + +const sourceExtensions = new Set(['.cjs', '.js', '.jsx', '.mjs', '.ts', '.tsx']); +const skippedDirectories = new Set(['node_modules', 'coverage', 'dist', 'tmp', '.next', '.turbo']); +const directDemonstrationImportPattern = + /\b(?:import\s+(?:[^'"]+\s+from\s+)?|import\s*\(|require\s*\()\s*['"][^'"]*(?:@bitcode\/protocol-demonstration|protocol-demonstration\/src)/u; + +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-v29-gate8-demonstration-origin-formalization.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 8 demonstration-origin commercial formalization closure.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function collectSourceFiles(root) { + const files = []; + + if (!existsSync(root)) return files; + + for (const entry of readdirSync(root)) { + const absolutePath = path.join(root, entry); + const stat = statSync(absolutePath); + + if (stat.isDirectory()) { + if (skippedDirectories.has(entry)) continue; + files.push(...collectSourceFiles(absolutePath)); + continue; + } + + if (sourceExtensions.has(path.extname(entry))) files.push(absolutePath); + } + + return files; +} + +function findDirectDemonstrationRuntimeImports(root, relativeRoots) { + return relativeRoots.flatMap((relativeRoot) => + collectSourceFiles(path.join(root, relativeRoot)).flatMap((filePath) => { + const source = readFileSync(filePath, 'utf8'); + if (!directDemonstrationImportPattern.test(source)) return []; + return [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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 Gate 8 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-8-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 8 work must occur on version/v29 or v29/gate-8-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'scripts/check-v29-gate8-demonstration-origin-formalization.mjs', + 'packages/protocol/package.json', + 'packages/protocol/README.md', + 'packages/protocol/src/index.js', + 'packages/protocol/src/index.d.ts', + 'packages/protocol/src/canon-posture.js', + 'packages/protocol/src/canonical/v21-specifying.js', + 'packages/protocol/src/canonical/v22-canon-posture.js', + 'packages/protocol/src/canonical/proven-generator.js', + 'packages/protocol/test/protocol-package-boundary.test.js', + 'scripts/check-bitcode-canon-posture-drift.mjs', + 'scripts/check-bitcode-canonical-inputs.mjs', + 'scripts/check-bitcode-pre-commit.mjs', + 'scripts/check-bitcode-spec-family.mjs', + 'scripts/generate-bitcode-proven.mjs', + 'scripts/run-bitcode-spec-quality.mjs', + 'package.json', + '.github/workflows/bitcode-gate-quality.yml', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 8 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const protocolReadme = read(root, 'packages/protocol/README.md'); + const protocolIndex = read(root, 'packages/protocol/src/index.js'); + const protocolTypes = read(root, 'packages/protocol/src/index.d.ts'); + const protocolPosture = read(root, 'packages/protocol/src/canon-posture.js'); + const protocolTest = read(root, 'packages/protocol/test/protocol-package-boundary.test.js'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + assertCheck(failures, spec.includes('V29 demonstration-origin commercial formalization canon'), 'V29 SPEC must define demonstration-origin commercial formalization canon.'); + assertCheck(failures, delta.includes('Gate 8: Demonstration-Origin Commercial Formalization') && delta.includes('package-native APIs'), 'V29 DELTA must define Gate 8 closure acceptance.'); + assertCheck(failures, notes.includes('Gate 8 working notes'), 'V29 NOTES must carry Gate 8 working notes.'); + assertCheck(failures, parity.includes('## Gate 8 Parity'), 'V29 PARITY must include Gate 8 parity.'); + assertCheck(failures, parity.includes('Gate 8 completion condition'), 'V29 PARITY must include Gate 8 completion condition.'); + + assertCheck( + failures, + protocolPosture.includes("ACTIVE_CANON_VERSION = 'V28'") && + protocolPosture.includes("DRAFT_TARGET_VERSION = 'V29'") && + !protocolPosture.includes("ACTIVE_CANON_VERSION = 'V27'") && + !protocolPosture.includes("DRAFT_TARGET_VERSION = 'V28'"), + 'Protocol package canon posture must be active V28 / draft V29.', + ); + + for (const symbol of [ + 'ACTIVE_CANON_VERSION', + 'DRAFT_TARGET_VERSION', + 'buildV21CanonicalInputReport', + 'buildV21GeneratedArtifactContents', + 'buildV21SpecFamilyReport', + 'buildCanonPostureDriftReport', + 'PROVEN_GENERATOR_ID', + 'defaultProvenOutputPath', + 'generateCanonicalProvenMarkdown', + ]) { + assertCheck(failures, protocolIndex.includes(symbol), `Protocol package index must export ${symbol}.`); + assertCheck(failures, protocolTypes.includes(symbol), `Protocol package types must declare ${symbol}.`); + } + + const demonstrationImportViolations = findDirectDemonstrationRuntimeImports(root, [ + 'scripts', + 'packages', + 'uapi/app', + 'uapi/components', + 'uapi/config', + 'uapi/hooks', + 'uapi/lib', + 'uapi/networking', + 'uapi/types', + ]).filter((relativePath) => !relativePath.startsWith('protocol-demonstration/')); + assertCheck( + failures, + demonstrationImportViolations.length === 0, + `Commercial/runtime sources must not import standalone demonstration runtime code. Violations: ${demonstrationImportViolations.join(', ') || 'none'}.`, + ); + + assertCheck( + failures, + protocolTest.includes('commercial formalization exports') && + protocolTest.includes("ACTIVE_CANON_VERSION, 'V28'") && + protocolTest.includes("DRAFT_TARGET_VERSION, 'V29'") && + protocolTest.includes('buildV21SpecFamilyReport') && + protocolTest.includes('generateCanonicalProvenMarkdown') && + protocolTest.includes('directly import standalone demonstration source'), + 'Protocol package tests must cover Gate 8 exports, posture, provenance, and import boundaries.', + ); + assertCheck( + failures, + protocolReadme.includes('Gate 8') && + protocolReadme.includes('package-native') && + protocolReadme.includes('must not import') && + protocolReadme.includes('protocol-demonstration'), + 'Protocol package README must document Gate 8 package-native boundary.', + ); + assertCheck( + failures, + packageJson.includes('"check:v29-gate8"') && + gateWorkflow.includes('check-v29-gate8-demonstration-origin-formalization.mjs') && + gateWorkflow.includes('@bitcode/protocol typecheck') && + gateWorkflow.includes('@bitcode/protocol test') && + gateWorkflow.includes('protocolCommercialBoundary.test.ts'), + 'Package scripts and gate-quality workflow must invoke Gate 8 checker, protocol package checks, and commercial boundary test.', + ); + + if (failures.length) { + process.stderr.write('V29 Gate 8 check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V29 Gate 8 demonstration-origin commercial formalization check passed.\n'); +} + +main(); diff --git a/scripts/generate-bitcode-proven.mjs b/scripts/generate-bitcode-proven.mjs index 115dd469a..59862fddf 100644 --- a/scripts/generate-bitcode-proven.mjs +++ b/scripts/generate-bitcode-proven.mjs @@ -8,7 +8,7 @@ import { PROVEN_GENERATOR_ID, defaultProvenOutputPath, generateCanonicalProvenMarkdown -} from '../protocol-demonstration/src/canonical/proven-generator.js'; +} from '../packages/protocol/src/index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/scripts/run-bitcode-spec-quality.mjs b/scripts/run-bitcode-spec-quality.mjs index 2734fa0ea..681e4125d 100644 --- a/scripts/run-bitcode-spec-quality.mjs +++ b/scripts/run-bitcode-spec-quality.mjs @@ -5,7 +5,7 @@ import { existsSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; -import { ACTIVE_CANON_VERSION, DRAFT_TARGET_VERSION } from '../protocol-demonstration/src/canon-posture.js'; +import { ACTIVE_CANON_VERSION, DRAFT_TARGET_VERSION } from '../packages/protocol/src/index.js'; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); From 7a2c464c22ca908d8ffc4bbacfb0aadd773d6b74 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 13:17:22 -0300 Subject: [PATCH 09/18] V29 Gate 9: Terminal UX Quality And Browser Proof Closes Gate 9 by proving the Terminal cockpit UX with source-safe landmarks, state semantics, responsive Playwright coverage, and maintained gate-quality automation. --- .github/workflows/bitcode-gate-quality.yml | 8 + BITCODE_SPEC_V29.md | 23 ++ BITCODE_SPEC_V29_DELTA.md | 10 + BITCODE_SPEC_V29_NOTES.md | 29 ++ BITCODE_SPEC_V29_PARITY_MATRIX.md | 32 ++- package.json | 1 + ...ck-v29-gate9-terminal-ux-browser-proof.mjs | 250 ++++++++++++++++++ uapi/app/terminal/README.md | 17 ++ uapi/app/terminal/TerminalPageClient.tsx | 22 +- .../TerminalTransactionActivitySurface.tsx | 14 +- .../TerminalTransactionDetailActionBar.tsx | 18 +- .../TerminalTransactionDetailHero.tsx | 9 +- .../TerminalTransactionDetailSurface.tsx | 40 ++- .../terminal/TerminalTransactionWorkspace.tsx | 41 ++- .../app/terminal/terminal-ux-browser-proof.ts | 100 +++++++ .../BitcodeTransactionsDataTable.tsx | 20 +- .../execution/BitcodeTransactionsTable.tsx | 8 +- uapi/jest.config.cjs | 1 + uapi/package.json | 1 + uapi/playwright.config.ts | 3 +- .../e2e/commercial-mvp.terminal-ux.spec.ts | 104 ++++++++ uapi/tests/terminalUxBrowserProof.test.tsx | 234 ++++++++++++++++ 22 files changed, 951 insertions(+), 34 deletions(-) create mode 100644 scripts/check-v29-gate9-terminal-ux-browser-proof.mjs create mode 100644 uapi/app/terminal/terminal-ux-browser-proof.ts create mode 100644 uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts create mode 100644 uapi/tests/terminalUxBrowserProof.test.tsx diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index 95f1019e9..e38d64bb5 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -70,6 +70,7 @@ jobs: node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs --skip-branch-check node scripts/check-v29-gate7-organization-permission-authority.mjs --skip-branch-check node scripts/check-v29-gate8-demonstration-origin-formalization.mjs --skip-branch-check + node scripts/check-v29-gate9-terminal-ux-browser-proof.mjs --skip-branch-check - name: Validate source casing and imports run: | @@ -116,9 +117,16 @@ jobs: tests/protocolCommercialBoundary.test.ts \ tests/terminalTransactionDetailCards.test.tsx \ tests/terminalTransactionDetailSnapshot.test.ts \ + tests/terminalUxBrowserProof.test.tsx \ tests/pipelineExecutionLogHeader.test.tsx \ --runInBand + - name: Install Terminal browser proof browser + run: pnpm --dir uapi exec playwright install chromium --with-deps + + - name: Browser proof Terminal cockpit + run: pnpm --dir uapi run test:e2e:terminal-ux + - name: Test pipeline readback verifier run: pnpm test:qa:v28:pipeline-readback diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index 8103ff6ff..c78e27b66 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -223,6 +223,29 @@ The Terminal transaction read model must contain: 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. +## V29 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 V29 Terminal cockpit commercially operable enough that later local/staging promotion readiness can debug failures from the UI rather than from browser network logs alone. + ## V29 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_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index fe5199c21..de2d678e8 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -183,6 +183,16 @@ Closure acceptance: Gate 9 owns accessibility, responsive layout, copy/prose clarity, empty/loading/blocked/failed states, Playwright coverage, and visual/browser verification for the complete Terminal transaction cockpit. +Closure acceptance: + +- Terminal exposes one named cockpit `main` landmark, a keyboard-reachable skip link to the selected transaction workspace, named regions for the transaction workspace and selected activity detail, and accessible controls for route-owned detail sections. +- The default operator path remains low-detail: activity summary, selected result digest, section availability, blockers, and source-safe preview metadata are readable before raw payload expansion. +- Loading, empty, failed, blocked, and source-safe preview states are represented by typed UI states with `status` or `alert` semantics where appropriate, not only by browser-network inspection. +- The complete cockpit is responsive across phone, tablet, laptop, and widescreen viewports without document-level horizontal overflow; table overflow remains contained inside the table scroller. +- Browser proof is executable through a focused Playwright spec that opens Terminal in deterministic mock mode, verifies landmarks, skip navigation, blocked Console posture, source-safe detail, route-owned selection, and responsive readability. +- Focused Jest coverage proves the UI state contract and the exported browser-proof contract that CI and documentation name. +- `check:v29-gate9` fails closed unless V29 specification, Terminal README, Terminal UX contract, Jest tests, Playwright spec, package scripts, and gate-quality workflow all name the Gate 9 browser-proof surface. + ### Gate 10: Local And Staging Promotion Readiness Gate 10 owns non-mocked local validation, staging-testnet readback, generated proof artifacts, V29 promotion workflow support, promotion dry-run, and final version branch readiness. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index eb25f8062..2b355e509 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -76,6 +76,7 @@ For a simplified reading of V29: 9. **Gate 9: Terminal UX Quality And Browser Proof** - Close accessibility, responsive, copy, loading/empty/error/blocked states, browser checks, and Playwright coverage for the complete Terminal cockpit. + - Acceptance detail: the Terminal page exposes a named cockpit `main`, skip navigation into the selected transaction workspace, named workspace/detail regions, source-safe low-detail defaults, explicit state semantics, and deterministic Playwright coverage for landmarks, blocked Console posture, route-owned selection, and phone/tablet/laptop/widescreen readability. 10. **Gate 10: Local And Staging Promotion Readiness** - Run non-mocked local validation, staging-testnet readback, generated proof artifacts, promotion dry-run, and `version/v29` promotion readiness. @@ -209,6 +210,34 @@ Gate 8 completion condition: - Protocol package tests pass. - The spec family, package README, root scripts, and CI all name and enforce the package-native boundary. +## Gate 9 working notes + +Gate 9 closes the Terminal cockpit quality slice. +It treats UX quality as protocol evidence: operators must be able to read the transaction state, section availability, source-safe preview posture, blocked actions, and activity stream without relying on browser network logs. + +Accepted surfaces: + +- `uapi/app/terminal/terminal-ux-browser-proof.ts` records the browser-proof contract: required landmarks, state semantics, viewports, route checks, and evidence files. +- `TerminalPageClient.tsx` owns the named cockpit `main` landmark and skip link. +- `TerminalTransactionWorkspace.tsx` owns the named transaction workspace region, loading/empty/error semantics, and selected result status. +- `TerminalTransactionDetailSurface.tsx`, `TerminalTransactionDetailHero.tsx`, and `TerminalTransactionDetailActionBar.tsx` own the selected activity detail region, low-detail source-safe header, section controls, blocked Console posture, and action errors. +- `BitcodeTransactionsTable.tsx` and `BitcodeTransactionsDataTable.tsx` keep transaction table overflow contained while exposing loading, empty, error, and selectable-row states to tests and assistive technology. +- `uapi/tests/terminalUxBrowserProof.test.tsx` proves the typed state contract. +- `uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts` proves the cockpit in a real browser in deterministic mock mode. + +Gate 9 accepted boundaries: + +- Gate 9 does not redesign the five-step Reading product flow; it makes the current transaction cockpit accessible and provable. +- Gate 9 does not reveal protected AssetPack source before settlement. +- Gate 9 does not add versioned routes, gate-named runtime routes, or work-in-progress source identifiers. +- Gate 9 does not require live staging credentials; Gate 10 owns non-mocked local/staging promotion readiness. + +Gate 9 completion condition: + +- `pnpm run check:v29-gate9` passes. +- Focused UAPI Jest coverage and Terminal Playwright browser proof pass locally. +- Gate-quality CI invokes the Gate 9 checker, focused Jest test, and focused Playwright browser proof. + ## Later-version boundaries - V30 remains reserved for Protocol/BTD hardening that is not necessary to close Terminal transaction depth. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 768f58a64..f1a4b9c53 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -56,7 +56,7 @@ No `_legacy/` source is active source truth. | Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, sandbox harness settlement evidence, Terminal repair UI, Gate 6 checker | drafted | Ledger, database, and metaphysical state drift is classified, proof-rooted, repair-actioned, and visible. | | Organization permission authority | Gate 7 | `packages/btd/src/authority.ts`, BTD/API/MCP/ChatGPT App tests, sandbox harness authority evidence, Terminal Authority section, Gate 7 checker | drafted | Registry-derived roles, holdings, read-license authority, settlement, confirmation, and interface admission govern actions. | | Commercial formalization | Gate 8 | `packages/protocol/src/index.js`, `packages/protocol/src/canon-posture.js`, root scripts, protocol package tests, import scans, docs, Gate 8 checker | drafted | Demonstration-origin commercial internals are package-native and no direct demonstration-source imports remain in commercial/runtime sources. | -| Terminal UX quality | Gate 9 | Playwright/Jest/a11y/responsive/browser QA | pending | Complete transaction cockpit is usable by default and inspectable in detail. | +| Terminal UX quality | Gate 9 | Terminal UX contract, Playwright/Jest/a11y/responsive/browser QA | drafted | Complete transaction cockpit is usable by default and inspectable in detail. | | Promotion readiness | Gate 10 | promotion workflow, `.bitcode/v29-*`, `BITCODE_SPEC_V29_PROVEN.md` | pending | `version/v29` can promote to `main` only after all V29 checks pass. | ## V29 implementation checklist @@ -73,7 +73,7 @@ No `_legacy/` source is active source truth. | Gate 5 AssetPack disclosure | `pnpm run check:v29-gate5` proves source-safe disclosure review, leakage detection, Terminal preview rendering, and PR title enforcement | drafted | | Gate 7 organization authority | `pnpm run check:v29-gate7` proves shared org/interface authority across BTD, API, MCP, ChatGPT App, harness, and Terminal | drafted | | Gate 8 commercial formalization | `pnpm run check:v29-gate8` proves package-native protocol exports, V28/V29 posture, script import cleanup, docs, tests, and CI wiring | drafted | -| Product implementation gates | Gate 9 closes remaining Terminal transaction UX quality with browser proof | pending | +| Gate 9 Terminal UX browser proof | `pnpm run check:v29-gate9` proves named landmarks, explicit state semantics, responsive browser coverage, focused Jest coverage, and CI wiring | drafted | | Promotion gate | Gate 10 closes generated proof and promotion automation | pending | ## Gate 1 Parity @@ -272,3 +272,31 @@ Gate 8 completion condition: - Focused protocol package typecheck/test and the UAPI commercial protocol boundary test pass. - V29 SPEC, DELTA, NOTES, PARITY, protocol package README, package scripts, and gate-quality workflow name the formalized package-native boundary. - Root scripts use protocol package exports for canonical helpers and do not directly import `protocol-demonstration/src/*`. + +## Gate 9 Parity + +Gate 9 closes the Terminal UX quality and browser-proof slice by making the transaction cockpit readable, keyboard reachable, responsive, and test-proven. + +Accepted surfaces: + +- `uapi/app/terminal/terminal-ux-browser-proof.ts` exports the typed contract for Gate 9 landmarks, viewports, states, route checks, and evidence files. +- `TerminalPageClient.tsx` exposes a named `main` cockpit region and skip link to the selected transaction workspace. +- `TerminalTransactionWorkspace.tsx` exposes a named transaction workspace region, selected activity status, and explicit loading, empty, and error states. +- `TerminalTransactionDetailSurface.tsx`, `TerminalTransactionDetailHero.tsx`, and `TerminalTransactionDetailActionBar.tsx` expose a named selected activity detail region, source-safe low-detail detail hero, route-owned section controls, blocked Console posture, and action error alerts. +- `BitcodeTransactionsTable.tsx` and `BitcodeTransactionsDataTable.tsx` expose table state semantics while containing table overflow inside the table scroller. +- `uapi/tests/terminalUxBrowserProof.test.tsx` proves the contract and UI state semantics. +- `uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts` proves the cockpit through a real browser in deterministic mock mode. +- `.github/workflows/bitcode-gate-quality.yml` runs the Gate 9 checker, focused Jest test, Playwright browser install, and focused Terminal browser proof. + +Accepted boundaries: + +- Gate 9 does not redesign Reading into a different flow. +- Gate 9 does not reveal protected AssetPack source before settlement. +- Gate 9 does not add versioned API routes or gate/work-in-progress runtime identifiers. +- Gate 9 does not perform non-mocked staging promotion readiness; Gate 10 owns that slice. + +Gate 9 completion condition: + +- `pnpm run check:v29-gate9` passes. +- Focused UAPI Jest coverage and Playwright Terminal browser proof pass. +- V29 SPEC, DELTA, NOTES, PARITY, Terminal README, package scripts, and gate-quality workflow name the browser-proof contract. diff --git a/package.json b/package.json index 8828780e9..3e734144b 100644 --- a/package.json +++ b/package.json @@ -52,6 +52,7 @@ "check:v29-gate6": "node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs", "check:v29-gate7": "node scripts/check-v29-gate7-organization-permission-authority.mjs", "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: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/scripts/check-v29-gate9-terminal-ux-browser-proof.mjs b/scripts/check-v29-gate9-terminal-ux-browser-proof.mjs new file mode 100644 index 000000000..205947d83 --- /dev/null +++ b/scripts/check-v29-gate9-terminal-ux-browser-proof.mjs @@ -0,0 +1,250 @@ +#!/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-v29-gate9-terminal-ux-browser-proof.mjs [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 9 Terminal UX quality and browser-proof closure.', + ].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 === 'V28', + `BITCODE_SPEC.txt must remain V28 during V29 Gate 9 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-9-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 9 work must occur on version/v29 or v29/gate-9-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'scripts/check-v29-gate9-terminal-ux-browser-proof.mjs', + 'uapi/app/terminal/terminal-ux-browser-proof.ts', + 'uapi/app/terminal/TerminalPageClient.tsx', + 'uapi/app/terminal/TerminalTransactionWorkspace.tsx', + 'uapi/app/terminal/TerminalTransactionDetailSurface.tsx', + 'uapi/app/terminal/TerminalTransactionDetailHero.tsx', + 'uapi/app/terminal/TerminalTransactionDetailActionBar.tsx', + 'uapi/app/terminal/TerminalTransactionActivitySurface.tsx', + 'uapi/components/base/bitcode/execution/BitcodeTransactionsTable.tsx', + 'uapi/components/base/bitcode/execution/BitcodeTransactionsDataTable.tsx', + 'uapi/tests/terminalUxBrowserProof.test.tsx', + 'uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts', + 'uapi/playwright.config.ts', + 'uapi/app/terminal/README.md', + 'uapi/package.json', + 'uapi/jest.config.cjs', + '.github/workflows/bitcode-gate-quality.yml', + 'package.json', + ]; + + for (const relativePath of requiredFiles) { + assertCheck(failures, fileExists(root, relativePath), `Missing Gate 9 file: ${relativePath}`); + } + + const spec = read(root, 'BITCODE_SPEC_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const contract = read(root, 'uapi/app/terminal/terminal-ux-browser-proof.ts'); + const pageClient = read(root, 'uapi/app/terminal/TerminalPageClient.tsx'); + const workspace = read(root, 'uapi/app/terminal/TerminalTransactionWorkspace.tsx'); + const detailSurface = read(root, 'uapi/app/terminal/TerminalTransactionDetailSurface.tsx'); + const detailHero = read(root, 'uapi/app/terminal/TerminalTransactionDetailHero.tsx'); + const actionBar = read(root, 'uapi/app/terminal/TerminalTransactionDetailActionBar.tsx'); + const activitySurface = read(root, 'uapi/app/terminal/TerminalTransactionActivitySurface.tsx'); + const table = read(root, 'uapi/components/base/bitcode/execution/BitcodeTransactionsTable.tsx'); + const dataTable = read(root, 'uapi/components/base/bitcode/execution/BitcodeTransactionsDataTable.tsx'); + const jestTest = read(root, 'uapi/tests/terminalUxBrowserProof.test.tsx'); + const e2eTest = read(root, 'uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts'); + const playwrightConfig = read(root, 'uapi/playwright.config.ts'); + const terminalReadme = read(root, 'uapi/app/terminal/README.md'); + const uapiPackage = read(root, 'uapi/package.json'); + const jestConfig = read(root, 'uapi/jest.config.cjs'); + const packageJson = read(root, 'package.json'); + const gateWorkflow = read(root, '.github/workflows/bitcode-gate-quality.yml'); + + assertCheck(failures, spec.includes('V29 Terminal UX quality and browser-proof canon'), 'V29 SPEC must define the Terminal UX browser-proof canon.'); + assertCheck(failures, delta.includes('Gate 9: Terminal UX Quality And Browser Proof') && delta.includes('focused Playwright spec'), 'V29 DELTA must define Gate 9 closure acceptance.'); + assertCheck(failures, notes.includes('Gate 9 working notes') && notes.includes('terminal-ux-browser-proof.ts'), 'V29 NOTES must carry Gate 9 working notes.'); + assertCheck(failures, parity.includes('## Gate 9 Parity') && parity.includes('Gate 9 completion condition'), 'V29 PARITY must include Gate 9 parity and completion condition.'); + assertCheck(failures, terminalReadme.includes('V29 Terminal UX browser proof checkpoint') && terminalReadme.includes('terminal-ux-browser-proof.ts'), 'Terminal README must document the Gate 9 browser-proof checkpoint.'); + + for (const token of [ + 'TERMINAL_UX_BROWSER_PROOF_CONTRACT', + 'TERMINAL_UX_BROWSER_PROOF_LANDMARKS', + 'TERMINAL_UX_BROWSER_PROOF_VIEWPORTS', + 'TERMINAL_UX_BROWSER_PROOF_STATES', + 'TERMINAL_UX_BROWSER_PROOF_ROUTE_CHECKS', + 'terminalMain', + 'terminalTransactionWorkspace', + 'terminalSelectedActivityDetail', + 'phone', + 'tablet', + 'laptop', + 'widescreen', + ]) { + assertCheck(failures, contract.includes(token), `Terminal UX browser-proof contract is missing ${token}.`); + } + + assertCheck( + failures, + pageClient.includes('id="terminalMain"') && + pageClient.includes('data-testid="terminal-cockpit-root"') && + pageClient.includes('Skip to selected Terminal activity') && + pageClient.includes('aria-labelledby="terminalPageTitle"'), + 'Terminal page must expose named main landmark and skip link.', + ); + assertCheck( + failures, + workspace.includes('data-testid="terminal-transaction-workspace"') && + workspace.includes('aria-labelledby="terminalTransactionWorkspaceTitle"') && + workspace.includes('terminal-workspace-loading-state') && + workspace.includes('terminal-workspace-empty-state') && + workspace.includes('terminal-workspace-error-state') && + workspace.includes('role="alert"') && + workspace.includes('role="status"'), + 'Terminal workspace must expose named region and loading/empty/error semantics.', + ); + assertCheck( + failures, + detailSurface.includes('data-testid="terminal-selected-activity-detail"') && + detailSurface.includes('terminalTransactionDetailTitle') && + detailSurface.includes('terminal-detail-loading-state') && + detailSurface.includes('terminal-detail-empty-state') && + detailSurface.includes('terminal-detail-action-error') && + detailHero.includes('data-testid="terminal-selected-activity-hero"') && + detailHero.includes('titleId') && + actionBar.includes('data-testid="terminal-detail-section-controls"') && + actionBar.includes('aria-pressed') && + actionBar.includes('Selected activity detail sections') && + activitySurface.includes('terminal-activity-stream-surface'), + 'Selected activity detail surfaces must expose source-safe hero, detail controls, blocked/error states, and activity stream proof hooks.', + ); + assertCheck( + failures, + table.includes('data-testid="bitcode-transactions-table-shell"') && + dataTable.includes('data-testid="bitcode-transactions-loading-state"') && + dataTable.includes('data-testid="bitcode-transactions-empty-state"') && + dataTable.includes('data-testid="bitcode-transactions-error-state"') && + dataTable.includes('aria-label="Recent Bitcode transactions"') && + dataTable.includes('overflow-x-auto'), + 'Transaction table must expose state semantics and contained overflow.', + ); + assertCheck( + failures, + jestTest.includes('TERMINAL_UX_BROWSER_PROOF_CONTRACT') && + jestTest.includes('terminal-workspace-loading-state') && + jestTest.includes('bitcode-transactions-loading-state') && + jestTest.includes('Selected activity detail sections') && + jestConfig.includes('terminalUxBrowserProof.test.tsx'), + 'Focused Jest coverage must prove the Gate 9 contract and UI state semantics.', + ); + assertCheck( + failures, + e2eTest.includes('Terminal UX browser proof') && + e2eTest.includes('terminal-cockpit-root') && + e2eTest.includes('Skip to selected Terminal activity') && + e2eTest.includes('terminal-selected-activity-hero') && + e2eTest.includes('documentOverflow') && + e2eTest.includes('phone') && + e2eTest.includes('widescreen'), + 'Focused Playwright coverage must prove landmarks, skip navigation, blocked detail posture, and responsive readability.', + ); + assertCheck( + failures, + playwrightConfig.includes('PLAYWRIGHT_READY_URL') && + playwrightConfig.includes('/terminal') && + playwrightConfig.includes('url: appReadyUrl'), + 'Playwright web server readiness must wait on the Terminal route, not only an open port.', + ); + assertCheck( + failures, + packageJson.includes('"check:v29-gate9"') && + uapiPackage.includes('"test:e2e:terminal-ux"') && + uapiPackage.includes('NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321') && + uapiPackage.includes('NEXT_PUBLIC_SUPABASE_ANON_KEY=mock-anon-key') && + uapiPackage.includes('NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=mock-publishable-key') && + gateWorkflow.includes('check-v29-gate9-terminal-ux-browser-proof.mjs') && + gateWorkflow.includes('terminalUxBrowserProof.test.tsx') && + gateWorkflow.includes('test:e2e:terminal-ux') && + gateWorkflow.includes('playwright install chromium --with-deps'), + 'Package scripts and gate-quality workflow must invoke self-contained Gate 9 checker, focused Jest, and Terminal browser proof.', + ); + + if (failures.length) { + process.stderr.write('V29 Gate 9 check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write('V29 Gate 9 Terminal UX quality and browser proof check passed.\n'); +} + +main(); diff --git a/uapi/app/terminal/README.md b/uapi/app/terminal/README.md index 24ee6df08..59fe795af 100644 --- a/uapi/app/terminal/README.md +++ b/uapi/app/terminal/README.md @@ -149,6 +149,23 @@ authority payload inspection. Terminal may show source-safe previews without a paid unlock, but protected-source unlock and delivery remain blocked until the same `organizationAuthority` evidence admits the action. +## V29 Terminal UX browser proof checkpoint + +The Terminal cockpit is now browser-proofed as a transaction operation surface, +not only a collection of panels. The route must expose a named `main` landmark, +a keyboard-reachable skip link into `#terminalTransactionWorkspace`, named +workspace/detail regions, explicit loading/empty/error/blocked state semantics, +and contained table overflow for phone through widescreen viewports. + +The browser-proof contract lives in `terminal-ux-browser-proof.ts`. It names the +required landmarks, state semantics, viewport set, route checks, and evidence +files used by Gate 9. The focused Jest test proves the contract and UI state +semantics; the focused Playwright spec proves the cockpit through a real browser +in deterministic mock mode. Playwright readiness waits on the Terminal route +itself through `PLAYWRIGHT_READY_URL` so an open dev-server port is not mistaken +for a rendered cockpit. Gate 9 does not reveal protected AssetPack source, does +not redesign Reading, and does not add versioned routes. + ## Related shared systems - [../../components/base/bitcode/execution/README.md](../../components/base/bitcode/execution/README.md) diff --git a/uapi/app/terminal/TerminalPageClient.tsx b/uapi/app/terminal/TerminalPageClient.tsx index 15d522c02..5e7a974aa 100644 --- a/uapi/app/terminal/TerminalPageClient.tsx +++ b/uapi/app/terminal/TerminalPageClient.tsx @@ -472,12 +472,26 @@ export default function TerminalPageClient() { ) : null}
-
-
+ + Skip to selected Terminal activity + +
+

Bitcode Terminal

-

+

Deposit, Read, and read recent Bitcode activity

@@ -655,7 +669,7 @@ export default function TerminalPageClient() {

-
+
{FEATURE_FLAGS.TERMINAL_DEBUG_WIDGET ? ( +
No activity stream is available for this selected Bitcode activity yet.
); } return ( -
+

Bitcode activity

-

Execution activity and work updates

+

Execution activity and work updates

Read the selected Bitcode activity's execution stream, state, and iteration updates directly from the Bitcode Terminal. Current convergence keeps execution primitives explicit here while the broader Bitcode activity family also admits diff --git a/uapi/app/terminal/TerminalTransactionDetailActionBar.tsx b/uapi/app/terminal/TerminalTransactionDetailActionBar.tsx index cba0f9d14..945de6a6f 100644 --- a/uapi/app/terminal/TerminalTransactionDetailActionBar.tsx +++ b/uapi/app/terminal/TerminalTransactionDetailActionBar.tsx @@ -1,5 +1,7 @@ 'use client'; +import React from 'react'; + import { DisabledTooltipWrapper } from '@/components/base/bitcode/overlays/disabled-tooltip-wrapper'; import type { TerminalTransactionDetailSection } from './terminal-transaction-query'; @@ -86,13 +88,17 @@ export default function TerminalTransactionDetailActionBar({ ); return ( -

+

{isExchangeSurface ? 'Exchange detail interaction' : 'Activity interaction'}

-

+

{isExchangeSurface ? 'Route-owned Exchange detail focus' : 'Route-owned result focus and closure actions'}

@@ -118,13 +124,19 @@ export default function TerminalTransactionDetailActionBar({ ) : null}

-
+
{visibleActions.map((action) => { const sectionButton = (
) : null} -
+
); } diff --git a/uapi/app/terminal/TerminalTransactionWorkspace.tsx b/uapi/app/terminal/TerminalTransactionWorkspace.tsx index da6f4dccc..6605c9463 100644 --- a/uapi/app/terminal/TerminalTransactionWorkspace.tsx +++ b/uapi/app/terminal/TerminalTransactionWorkspace.tsx @@ -1,5 +1,6 @@ 'use client'; +import React from 'react'; import { useEffect, useMemo, useState } from 'react'; import { @@ -371,16 +372,19 @@ export default function TerminalTransactionWorkspace({ return (

{surfaceKicker}

-

+

{surfaceTitle}

-

+

{surfaceSummary}

@@ -400,19 +404,46 @@ export default function TerminalTransactionWorkspace({
) : null}
+

+ {isLoadingRuns + ? loadingLabel + : runsError + ? `Terminal activity failed: ${runsError}` + : selectedRun + ? `Selected activity ${selectedRun.id} is active in ${getTransactionDataModeLabel(transactionDataMode)}.` + : 'No Terminal activity is selected.'} +

{isLoadingRuns ? ( -
+
{loadingLabel}
) : runsError ? ( -
+
{runsError}
) : !selectedRun ? ( -
+
{TERMINAL_SURFACE_COPY.detail.emptySelection}
) : ( diff --git a/uapi/app/terminal/terminal-ux-browser-proof.ts b/uapi/app/terminal/terminal-ux-browser-proof.ts new file mode 100644 index 000000000..c3065de2f --- /dev/null +++ b/uapi/app/terminal/terminal-ux-browser-proof.ts @@ -0,0 +1,100 @@ +export const TERMINAL_UX_BROWSER_PROOF_LANDMARKS = [ + { + id: 'terminalMain', + label: 'Terminal cockpit main landmark', + selector: '#terminalMain', + semantic: 'main', + }, + { + id: 'terminalTransactionWorkspace', + label: 'Selected transaction workspace region', + selector: '#terminalTransactionWorkspace', + semantic: 'region', + }, + { + id: 'terminalSelectedActivityDetail', + label: 'Selected activity detail region', + selector: '[data-testid="terminal-selected-activity-detail"]', + semantic: 'region', + }, +] as const; + +export const TERMINAL_UX_BROWSER_PROOF_VIEWPORTS = [ + { id: 'phone', width: 390, height: 844 }, + { id: 'tablet', width: 768, height: 1024 }, + { id: 'laptop', width: 1280, height: 900 }, + { id: 'widescreen', width: 1440, height: 900 }, +] as const; + +export const TERMINAL_UX_BROWSER_PROOF_STATES = [ + { + id: 'loading', + testId: 'terminal-workspace-loading-state', + semantic: 'status', + }, + { + id: 'empty', + testId: 'terminal-workspace-empty-state', + semantic: 'status', + }, + { + id: 'failed', + testId: 'terminal-workspace-error-state', + semantic: 'alert', + }, + { + id: 'blocked', + testId: 'terminal-detail-section-controls', + semantic: 'disabled-action', + }, + { + id: 'source-safe-preview', + testId: 'terminal-selected-activity-hero', + semantic: 'source-safe-low-detail', + }, +] as const; + +export const TERMINAL_UX_BROWSER_PROOF_ROUTE_CHECKS = [ + { + id: 'default-terminal', + path: '/terminal', + expectation: 'named cockpit, selected transaction workspace, selected result digest', + }, + { + id: 'activity-detail', + path: '/terminal?transactionId=mock-run-branch-remediation&transactionDetail=activity', + expectation: 'source-safe selected detail and execution stream', + }, + { + id: 'blocked-console', + path: '/terminal?transactionId=mock-run-branch-remediation&transactionDetail=console', + expectation: 'Console detail stays blocked in mock review posture', + }, +] as const; + +export const TERMINAL_UX_BROWSER_PROOF_EVIDENCE_FILES = [ + 'uapi/tests/terminalUxBrowserProof.test.tsx', + 'uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts', + 'scripts/check-v29-gate9-terminal-ux-browser-proof.mjs', + '.github/workflows/bitcode-gate-quality.yml', +] as const; + +export const TERMINAL_UX_BROWSER_PROOF_CONTRACT = { + gate: 'V29 Gate 9: Terminal UX Quality And Browser Proof', + landmarks: TERMINAL_UX_BROWSER_PROOF_LANDMARKS, + viewports: TERMINAL_UX_BROWSER_PROOF_VIEWPORTS, + states: TERMINAL_UX_BROWSER_PROOF_STATES, + routeChecks: TERMINAL_UX_BROWSER_PROOF_ROUTE_CHECKS, + evidenceFiles: TERMINAL_UX_BROWSER_PROOF_EVIDENCE_FILES, +} as const; + +export function summarizeTerminalUxBrowserProofContract() { + return { + gate: TERMINAL_UX_BROWSER_PROOF_CONTRACT.gate, + landmarkCount: TERMINAL_UX_BROWSER_PROOF_LANDMARKS.length, + viewportCount: TERMINAL_UX_BROWSER_PROOF_VIEWPORTS.length, + stateCount: TERMINAL_UX_BROWSER_PROOF_STATES.length, + routeCheckCount: TERMINAL_UX_BROWSER_PROOF_ROUTE_CHECKS.length, + evidenceFileCount: TERMINAL_UX_BROWSER_PROOF_EVIDENCE_FILES.length, + }; +} diff --git a/uapi/components/base/bitcode/execution/BitcodeTransactionsDataTable.tsx b/uapi/components/base/bitcode/execution/BitcodeTransactionsDataTable.tsx index 9bd8dfcdc..93bef27bf 100644 --- a/uapi/components/base/bitcode/execution/BitcodeTransactionsDataTable.tsx +++ b/uapi/components/base/bitcode/execution/BitcodeTransactionsDataTable.tsx @@ -47,16 +47,26 @@ export default function BitcodeTransactionsDataTable({ error, }: BitcodeTransactionsDataTableProps) { return ( -
+
{isLoading ? ( -
Loading Bitcode transactions…
+
+ Loading Bitcode transactions… +
) : error ? ( -
{error}
+
{error}
) : records.length === 0 ? ( -
No Bitcode transactions match the current filters.
+
No Bitcode transactions match the current filters.
) : (
- +
diff --git a/uapi/components/base/bitcode/execution/BitcodeTransactionsTable.tsx b/uapi/components/base/bitcode/execution/BitcodeTransactionsTable.tsx index 5b97dbead..d6fb3525f 100644 --- a/uapi/components/base/bitcode/execution/BitcodeTransactionsTable.tsx +++ b/uapi/components/base/bitcode/execution/BitcodeTransactionsTable.tsx @@ -66,11 +66,15 @@ export default function BitcodeTransactionsTable({ : 'Terminal uses this shared activity table as a focused result surface for recent Deposit, Read, proof, and closure work. Select a row to read its AssetPack evidence, proof posture, history, and execution updates.'; return ( -
+

{tableKicker}

-

{tableTitle}

+

{tableTitle}

{tableSummary}

diff --git a/uapi/jest.config.cjs b/uapi/jest.config.cjs index 8d2524531..e1a7f09f9 100644 --- a/uapi/jest.config.cjs +++ b/uapi/jest.config.cjs @@ -149,6 +149,7 @@ module.exports = { '/tests/terminalTransactionDetailSnapshot.test.ts', '/tests/terminalTransactionQuery.test.ts', '/tests/terminalTransactionReadModel.test.ts', + '/tests/terminalUxBrowserProof.test.tsx', '/tests/terminalWalletBtcOperation.test.ts', '/tests/terminalCoreNativeSections.test.tsx', '/tests/terminalDepositComposer.test.ts', diff --git a/uapi/package.json b/uapi/package.json index d7d47e002..429e837b6 100644 --- a/uapi/package.json +++ b/uapi/package.json @@ -23,6 +23,7 @@ "test:e2e:api": "playwright test tests/e2e/api.e2e.test.ts", "test:e2e:ui": "playwright test", "test:e2e:commercial-mvp": "START_STORYBOOK=false NEXT_PUBLIC_MASTER_MOCK_MODE=true NEXT_PUBLIC_ENABLE_MOCKS=true NEXT_PUBLIC_MOCK_USER_AUXILLARIES=true NEXT_PUBLIC_MOCK_USER_AUXILLARIES_SCENARIO=demo NEXT_PUBLIC_MOCK_SCENARIO=demo NEXT_PUBLIC_MOCK_GITHUB_ACCOUNTS=true NEXT_PUBLIC_MOCK_GITHUB_REPOS=true NEXT_PUBLIC_MOCK_GITHUB_BRANCHES=true NEXT_PUBLIC_MOCK_GITHUB_COMMITS=true NEXT_PUBLIC_MOCK_CHAT_STREAM=true NEXT_PUBLIC_MOCK_CHAT_SCENARIO=demo playwright test tests/e2e/commercial-mvp*.spec.ts --project=laptop --workers=1", + "test:e2e:terminal-ux": "START_STORYBOOK=false NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321 NEXT_PUBLIC_SUPABASE_ANON_KEY=mock-anon-key NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY=mock-publishable-key NEXT_PUBLIC_MASTER_MOCK_MODE=true NEXT_PUBLIC_ENABLE_MOCKS=true NEXT_PUBLIC_MOCK_USER_AUXILLARIES=true NEXT_PUBLIC_MOCK_USER_AUXILLARIES_SCENARIO=demo NEXT_PUBLIC_MOCK_SCENARIO=demo NEXT_PUBLIC_MOCK_GITHUB_ACCOUNTS=true NEXT_PUBLIC_MOCK_GITHUB_REPOS=true NEXT_PUBLIC_MOCK_GITHUB_BRANCHES=true NEXT_PUBLIC_MOCK_GITHUB_COMMITS=true NEXT_PUBLIC_MOCK_CHAT_STREAM=true NEXT_PUBLIC_MOCK_CHAT_SCENARIO=demo playwright test tests/e2e/commercial-mvp.terminal-ux.spec.ts --project=laptop --workers=1", "test:e2e:visual": "playwright test tests/e2e/**/*.visual.spec.ts", "test:e2e:onboarding": "START_STORYBOOK=false USE_API_MOCK=true playwright test tests/e2e/onboarding.visual.spec.ts tests/e2e/account.onboarding.visual.spec.ts --timeout=120000", "test:e2e:onboarding-first-step": "START_STORYBOOK=false USE_API_MOCK=true playwright test tests/e2e/onboarding-first-step.spec.ts --timeout=120000", diff --git a/uapi/playwright.config.ts b/uapi/playwright.config.ts index 57fbb7233..df07a998f 100644 --- a/uapi/playwright.config.ts +++ b/uapi/playwright.config.ts @@ -6,6 +6,7 @@ import { defineConfig, devices } from '@playwright/test'; // it here would accidentally launch / hit the admin interface instead of // the main product and make the tests fail with `ERR_CONNECTION_REFUSED`. const devPort = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000; +const appReadyUrl = process.env.PLAYWRIGHT_READY_URL || `http://127.0.0.1:${devPort}/terminal`; // Port for Storybook server during Playwright tests; override via STORYBOOK_PORT env var or default to 6006 const storybookPort = process.env.STORYBOOK_PORT ? parseInt(process.env.STORYBOOK_PORT, 10) : 6006; @@ -24,7 +25,7 @@ export default defineConfig({ // triggers unrelated prebuilds and local-service startup before the // product route under test can even load. command: `pnpm dev:remote -- -p ${devPort}`, - port: devPort, + url: appReadyUrl, reuseExistingServer: true, }, // Optionally start Storybook for component visual tests diff --git a/uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts b/uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts new file mode 100644 index 000000000..838441935 --- /dev/null +++ b/uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts @@ -0,0 +1,104 @@ +import { expect, test } from '@playwright/test'; + +import { + expectNoFrameworkOverlay, + expectReadableViewport, + installCommercialBrowserErrorTrap, + installCommercialMvpApiMocks, + openCommercialRoute, +} from './commercial-mvp.helpers'; + +const TERMINAL_BROWSER_PROOF_VIEWPORTS = [ + { id: 'phone', width: 390, height: 844 }, + { id: 'tablet', width: 768, height: 1024 }, + { id: 'laptop', width: 1280, height: 900 }, + { id: 'widescreen', width: 1440, height: 900 }, +] as const; + +test.describe('commercial MVP Terminal UX browser proof', () => { + test.setTimeout(120_000); + + test.beforeEach(async ({ page }) => { + await installCommercialMvpApiMocks(page); + }); + + test('Terminal cockpit exposes landmarks, skip navigation, and selected activity detail', async ({ + page, + }, testInfo) => { + const trap = installCommercialBrowserErrorTrap(page, testInfo); + + await page.goto('/terminal'); + await expect(page.getByTestId('terminal-cockpit-root')).toBeVisible({ timeout: 90_000 }); + await expect(page.getByText(/The Bitcode Terminal is where operators prepare Deposit and Read work/i).first()).toBeVisible(); + await expectNoFrameworkOverlay(page); + await expectReadableViewport(page); + + await expect(page.getByRole('main', { name: /Deposit, Read, and read recent Bitcode activity/i })).toBeVisible(); + await expect(page.getByTestId('terminal-cockpit-root')).toBeVisible(); + await expect(page.getByRole('region', { name: /Recent Terminal activity and selected result/i })).toBeVisible(); + await expect(page.getByTestId('terminal-selected-activity-detail')).toBeVisible(); + await expect(page.getByRole('group', { name: /Selected activity detail sections/i })).toBeVisible(); + + const skipLink = page.getByRole('link', { name: /Skip to selected Terminal activity/i }); + await skipLink.evaluate((element) => (element as HTMLElement).focus()); + await expect(skipLink).toBeFocused(); + await page.keyboard.press('Enter'); + await expect(page.locator('#terminalTransactionWorkspace')).toBeInViewport(); + + await page.goto('/terminal?transactionId=mock-run-branch-remediation&transactionDetail=activity'); + await expect(page.getByTestId('terminal-activity-stream-surface')).toBeVisible({ timeout: 20_000 }); + + await trap.assertClean(); + }); + + test('Terminal blocked detail posture is readable without raw network inspection', async ({ + page, + }, testInfo) => { + const trap = installCommercialBrowserErrorTrap(page, testInfo); + + await openCommercialRoute( + page, + '/terminal?transactionId=mock-run-branch-remediation&transactionDetail=console', + /Prepared the active branch artifact pack/i, + ); + + await expect(page.getByTestId('terminal-selected-activity-hero')).toContainText(/Console \/ blocked/i); + await expect(page.getByRole('button', { name: /^Console$/ })).toBeDisabled(); + await expect(page.getByText(/Console detail is available only for live execution-history rows/i)).toBeVisible(); + + await trap.assertClean(); + }); + + test('Terminal cockpit remains readable from phone through widescreen without document overflow', async ({ + page, + }, testInfo) => { + const trap = installCommercialBrowserErrorTrap(page, testInfo); + + for (const viewport of TERMINAL_BROWSER_PROOF_VIEWPORTS) { + await page.setViewportSize({ width: viewport.width, height: viewport.height }); + await openCommercialRoute( + page, + '/terminal', + /The Bitcode Terminal is where operators prepare Deposit and Read work/i, + ); + await expect(page.getByTestId('terminal-cockpit-root')).toBeVisible(); + await expect(page.locator('#terminalTransactionWorkspace')).toBeVisible(); + + const metrics = await page.evaluate(() => { + const workspace = document.querySelector('#terminalTransactionWorkspace'); + const workspaceRect = workspace?.getBoundingClientRect(); + return { + documentOverflow: document.documentElement.scrollWidth - document.documentElement.clientWidth, + workspaceWidth: Math.round(workspaceRect?.width || 0), + viewportWidth: window.innerWidth, + }; + }); + + expect(metrics.workspaceWidth).toBeGreaterThan(0); + expect(metrics.workspaceWidth).toBeLessThanOrEqual(metrics.viewportWidth); + expect(metrics.documentOverflow, `${viewport.id} document overflow`).toBeLessThanOrEqual(48); + } + + await trap.assertClean(); + }); +}); diff --git a/uapi/tests/terminalUxBrowserProof.test.tsx b/uapi/tests/terminalUxBrowserProof.test.tsx new file mode 100644 index 000000000..c9ded7c3d --- /dev/null +++ b/uapi/tests/terminalUxBrowserProof.test.tsx @@ -0,0 +1,234 @@ +import React from 'react'; +import { fireEvent, render, screen, within } from '@testing-library/react'; + +jest.mock('@/app/terminal/TerminalTransactionDetailSurface', () => ({ + __esModule: true, + default: () => null, +})); + +import TerminalTransactionDetailActionBar from '@/app/terminal/TerminalTransactionDetailActionBar'; +import TerminalTransactionWorkspace from '@/app/terminal/TerminalTransactionWorkspace'; +import { + summarizeTerminalUxBrowserProofContract, + TERMINAL_UX_BROWSER_PROOF_CONTRACT, +} from '@/app/terminal/terminal-ux-browser-proof'; +import { buildTerminalTransactionFilters } from '@/app/terminal/terminal-transactions'; +import BitcodeTransactionsDataTable from '@/components/base/bitcode/execution/BitcodeTransactionsDataTable'; +import { DEFAULT_TRANSACTION_PAGINATION } from '@/components/base/bitcode/execution/bitcode-transaction-types'; +import type { TransactionRecord } from '@/components/base/bitcode/execution/bitcode-transaction-types'; + +const noop = jest.fn(); + +function renderWorkspaceState({ + isLoadingRuns = false, + runsError = null, +}: { + isLoadingRuns?: boolean; + runsError?: string | null; +}) { + return render( + , + ); +} + +const transactionRecord: TransactionRecord = { + id: 'tx-browser-proof-1', + summary: 'Browser proof transaction row.', + type: 'agentic-execution:read-measurement', + typeLabel: 'Read measurement execution', + status: 'completed', + participant: 'engineeredsoftware', + repository: 'engineeredsoftware/ENGI', + branch: 'main', + proofStatus: 'proof witness ready', + closureFocus: 'source-safe preview', + createdAt: '2026-05-21T12:00:00.000Z', + tokenTotal: 1200, + isOwnTransaction: true, + transactionLens: 'read', +}; + +describe('Terminal UX browser proof contract', () => { + it('exports the Gate 9 landmarks, states, viewports, routes, and evidence files', () => { + expect(TERMINAL_UX_BROWSER_PROOF_CONTRACT.gate).toBe( + 'V29 Gate 9: Terminal UX Quality And Browser Proof', + ); + expect(summarizeTerminalUxBrowserProofContract()).toEqual({ + gate: 'V29 Gate 9: Terminal UX Quality And Browser Proof', + landmarkCount: 3, + viewportCount: 4, + stateCount: 5, + routeCheckCount: 3, + evidenceFileCount: 4, + }); + expect(TERMINAL_UX_BROWSER_PROOF_CONTRACT.landmarks.map((landmark) => landmark.id)).toEqual( + expect.arrayContaining([ + 'terminalMain', + 'terminalTransactionWorkspace', + 'terminalSelectedActivityDetail', + ]), + ); + expect(TERMINAL_UX_BROWSER_PROOF_CONTRACT.states.map((state) => state.id)).toEqual( + expect.arrayContaining(['loading', 'empty', 'failed', 'blocked', 'source-safe-preview']), + ); + expect(TERMINAL_UX_BROWSER_PROOF_CONTRACT.viewports.map((viewport) => viewport.id)).toEqual([ + 'phone', + 'tablet', + 'laptop', + 'widescreen', + ]); + expect(TERMINAL_UX_BROWSER_PROOF_CONTRACT.evidenceFiles).toContain( + 'uapi/tests/e2e/commercial-mvp.terminal-ux.spec.ts', + ); + }); + + it('renders Terminal workspace loading, failed, and empty states with explicit semantics', () => { + const { rerender } = renderWorkspaceState({ isLoadingRuns: true }); + const loadingState = screen.getByTestId('terminal-workspace-loading-state'); + expect(loadingState.getAttribute('role')).toBe('status'); + expect(loadingState.textContent).toContain('Loading Bitcode Terminal'); + + rerender( + , + ); + const errorState = screen.getByTestId('terminal-workspace-error-state'); + expect(errorState.getAttribute('role')).toBe('alert'); + expect(errorState.textContent).toContain('Pipeline history read failed.'); + + rerender( + , + ); + const emptyState = screen.getByTestId('terminal-workspace-empty-state'); + expect(emptyState.getAttribute('role')).toBe('status'); + expect(emptyState.textContent).toContain('Select recent Terminal activity'); + }); + + it('keeps transaction-table state semantics and selectable row access stable', () => { + const onSelectTransaction = jest.fn(); + const { rerender } = render( + , + ); + + expect(screen.getByTestId('bitcode-transactions-loading-state').getAttribute('role')).toBe('status'); + + rerender( + , + ); + expect(screen.getByTestId('bitcode-transactions-error-state').getAttribute('role')).toBe('alert'); + + rerender( + , + ); + expect(screen.getByTestId('bitcode-transactions-empty-state').getAttribute('role')).toBe('status'); + + rerender( + , + ); + expect(screen.getByRole('table', { name: /Recent Bitcode transactions/i })).toBeTruthy(); + fireEvent.click(screen.getByRole('button', { name: /tx-browser-proof-1/i })); + expect(onSelectTransaction).toHaveBeenCalledWith('tx-browser-proof-1'); + }); + + it('marks selected detail sections as route-owned controls with blocked actions disabled', () => { + const onChangeSection = jest.fn(); + render( + , + ); + + const controlGroup = screen.getByRole('group', { name: /Selected activity detail sections/i }); + const activityButton = within(controlGroup).getByRole('button', { name: 'Execution stream' }); + const consoleButton = within(controlGroup).getByRole('button', { name: 'Console' }) as HTMLButtonElement; + + expect(activityButton.getAttribute('aria-pressed')).toBe('true'); + expect(consoleButton.disabled).toBe(true); + fireEvent.click(activityButton); + expect(onChangeSection).toHaveBeenCalledWith('activity'); + }); +}); From 415146f10896901b2497f7440439295bc298f0c0 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 13:51:34 -0300 Subject: [PATCH 10/18] V29 Gate 10: Local And Staging Promotion Readiness Closes Gate 10 by adding local/staging promotion-readiness specification, QA ledger, V29 promotion workflow automation, V29 promotion command planning, and runtime posture promotion coverage. --- .github/workflows/bitcode-canon-quality.yml | 29 ++- .github/workflows/bitcode-gate-quality.yml | 39 +-- .github/workflows/v29-canon-promotion.yml | 145 +++++++++++ BITCODE_SPEC_V29.md | 35 +++ BITCODE_SPEC_V29_DELTA.md | 27 +++ BITCODE_SPEC_V29_NOTES.md | 36 +++ BITCODE_SPEC_V29_PARITY_MATRIX.md | 54 ++++- BITCODE_V29_QA.md | 62 +++++ README.md | 3 + package.json | 1 + packages/protocol/README.md | 5 + packages/protocol/data/state.json | 20 +- .../test/v22-canon-drift.test.js | 89 +++++++ ...te10-local-staging-promotion-readiness.mjs | 225 ++++++++++++++++++ ...repare-bitcode-runtime-canon-promotion.mjs | 105 +++++++- .../prepare-bitcode-spec-family-promotion.mjs | 34 ++- scripts/promote-bitcode-canon.mjs | 120 +++++++++- 17 files changed, 977 insertions(+), 52 deletions(-) create mode 100644 .github/workflows/v29-canon-promotion.yml create mode 100644 BITCODE_V29_QA.md create mode 100644 scripts/check-v29-gate10-local-staging-promotion-readiness.mjs diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index f8e889e6c..f7fa14f5b 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -20,12 +20,22 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Validate active canon and V29 draft posture + - name: Validate active canon and V29 posture run: | - node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 - node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29 - node scripts/check-bitcode-spec-family.mjs --version V28 --mode promoted --current-target V28 - node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 + POINTER="$(cat BITCODE_SPEC.txt)" + if [ "$POINTER" = "V28" ]; then + node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29 + node scripts/check-bitcode-spec-family.mjs --version V28 --mode promoted --current-target V28 + node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 + elif [ "$POINTER" = "V29" ]; then + 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 + else + echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 + exit 1 + fi bitcode-demonstration-mvp: name: Bitcode Demonstration MVP @@ -54,11 +64,16 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Run V29 strict draft conformance for spec-title changes + - name: Run V29 strict conformance for spec-title changes run: | case "$SPEC_TITLE" in spec:\ V29*|spec:\ v29*) - node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 + POINTER="$(cat BITCODE_SPEC.txt)" + if [ "$POINTER" = "V29" ]; then + node scripts/check-bitcode-spec-family.mjs --version V29 --mode promoted --current-target V29 + else + node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 + fi ;; *) echo "Skipping strict spec-title conformance; title is not a V29 spec change." diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index e38d64bb5..c01f8f057 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -57,20 +57,31 @@ jobs: - name: Validate draft canon posture run: | - test "$(cat BITCODE_SPEC.txt)" = "V28" - node scripts/check-bitcode-spec-family.mjs --version V28 --mode promoted --current-target V28 - node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 - node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29 - node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 - node scripts/check-v29-gate1-objectives-and-gating.mjs --skip-branch-check - node scripts/check-v29-gate2-terminal-transaction-read-models.mjs --skip-branch-check - node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs --skip-branch-check - node scripts/check-v29-gate4-reading-pipeline-observability.mjs --skip-branch-check - node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs --skip-branch-check - node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs --skip-branch-check - node scripts/check-v29-gate7-organization-permission-authority.mjs --skip-branch-check - node scripts/check-v29-gate8-demonstration-origin-formalization.mjs --skip-branch-check - node scripts/check-v29-gate9-terminal-ux-browser-proof.mjs --skip-branch-check + POINTER="$(cat BITCODE_SPEC.txt)" + if [ "$POINTER" = "V28" ]; then + node scripts/check-bitcode-spec-family.mjs --version V28 --mode promoted --current-target V28 + node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29 + node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 + node scripts/check-v29-gate1-objectives-and-gating.mjs --skip-branch-check + node scripts/check-v29-gate2-terminal-transaction-read-models.mjs --skip-branch-check + node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs --skip-branch-check + node scripts/check-v29-gate4-reading-pipeline-observability.mjs --skip-branch-check + node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs --skip-branch-check + node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs --skip-branch-check + node scripts/check-v29-gate7-organization-permission-authority.mjs --skip-branch-check + node scripts/check-v29-gate8-demonstration-origin-formalization.mjs --skip-branch-check + node scripts/check-v29-gate9-terminal-ux-browser-proof.mjs --skip-branch-check + 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-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 + else + echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 + exit 1 + fi - name: Validate source casing and imports run: | diff --git a/.github/workflows/v29-canon-promotion.yml b/.github/workflows/v29-canon-promotion.yml new file mode 100644 index 000000000..165b1e07e --- /dev/null +++ b/.github/workflows/v29-canon-promotion.yml @@ -0,0 +1,145 @@ +name: V29 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-v29: + name: V29 Promotion Validation + if: >- + ${{ + github.event_name == 'workflow_dispatch' || + ( + github.event.pull_request.base.ref == 'main' && + github.event.pull_request.head.ref == 'version/v29' && + 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 V29 promotion readiness + run: | + POINTER="$(cat BITCODE_SPEC.txt)" + if [ "$POINTER" = "V28" ]; then + node scripts/check-bitcode-spec-family.mjs --version V29 --mode draft --current-target V28 + node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V28 --draft-target V29 + node scripts/check-bitcode-canonical-inputs.mjs --current-target V28 + node scripts/check-v29-gate1-objectives-and-gating.mjs --skip-branch-check + node scripts/check-v29-gate2-terminal-transaction-read-models.mjs --skip-branch-check + node scripts/check-v29-gate3-wallet-signer-btc-operations.mjs --skip-branch-check + node scripts/check-v29-gate4-reading-pipeline-observability.mjs --skip-branch-check + node scripts/check-v29-gate5-assetpack-disclosure-rights.mjs --skip-branch-check + node scripts/check-v29-gate6-settlement-reconciliation-repair.mjs --skip-branch-check + node scripts/check-v29-gate7-organization-permission-authority.mjs --skip-branch-check + node scripts/check-v29-gate8-demonstration-origin-formalization.mjs --skip-branch-check + node scripts/check-v29-gate9-terminal-ux-browser-proof.mjs --skip-branch-check + node scripts/check-v29-gate10-local-staging-promotion-readiness.mjs --promotion-mode --skip-branch-check + node scripts/promote-bitcode-canon.mjs --version V29 --commit HEAD --dry-run + elif [ "$POINTER" = "V29" ]; then + node scripts/check-bitcode-spec-family.mjs --version V29 --mode promoted --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 + 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/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 V29 canon files + if: >- + ${{ + github.event_name == 'pull_request' && + github.event.pull_request.head.ref == 'version/v29' + }} + env: + HEAD_BRANCH: ${{ github.event.pull_request.head.ref }} + run: | + if [ "$(cat BITCODE_SPEC.txt)" = "V29" ]; then + echo "BITCODE_SPEC.txt already points to V29." + exit 0 + fi + PROOF_SOURCE_COMMIT="$(git rev-parse HEAD)" + npm run promote:canon -- --version V29 --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_V29.md \ + BITCODE_SPEC_V29_DELTA.md \ + BITCODE_SPEC_V29_NOTES.md \ + BITCODE_SPEC_V29_PARITY_MATRIX.md \ + BITCODE_SPEC_V29_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 V29" + git push origin "HEAD:$HEAD_BRANCH" diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index c78e27b66..bffee134f 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -246,6 +246,41 @@ 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 V29 Terminal cockpit commercially operable enough that later local/staging promotion readiness can debug failures from the UI rather than from browser network logs alone. +## V29 local and staging promotion readiness canon + +V29 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 V29 gate scripts are invoked by gate-quality CI while `BITCODE_SPEC.txt` + remains `V28`; +- gate-quality and canon-quality workflows also accept the promoted state after + the V29 promotion workflow commits `BITCODE_SPEC.txt -> V29`; +- the canonical promotion command supports `--version V29`, validates the V29 + draft family, runs local proof suites, prepares V29 hand-authored status + truth, prepares runtime canon posture for V29 active / V30 draft, generates + `BITCODE_SPEC_V29_PROVEN.md`, writes `.bitcode/v29-*` proof artifacts, and + then validates the promoted V29 family; +- the version-promotion workflow runs only for a `version/v29` 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 V28 active / V29 draft during Gate 10 work and be rewritten +to V29 active / V30 draft by promotion automation. + +Gate 10 does not itself promote `BITCODE_SPEC.txt`. +It closes when `version/v29` can be pull-requested to `main` and the V29 +promotion workflow has enough scripted proof to produce the standalone +canonical promotion commit. + ## V29 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_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index de2d678e8..a99891edd 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -196,3 +196,30 @@ Closure acceptance: ### Gate 10: Local And Staging Promotion Readiness Gate 10 owns non-mocked local validation, staging-testnet readback, generated proof artifacts, V29 promotion workflow support, promotion dry-run, and final version branch readiness. + +Closure acceptance: + +- `check:v29-gate10` validates the V29 promotion-readiness surface from a clean + Gate 10 branch and can run in `--promotion-mode` after `BITCODE_SPEC.txt` + advances to `V29`. +- Gate-quality CI invokes all V29 gate scripts while V29 is still a draft and + switches to promoted V29 validation after the promotion workflow writes the + canonical pointer commit. +- Canon-quality CI validates either V28 active / V29 draft posture or V29 active + / V30 draft posture so the version branch remains green before and after + promotion automation commits generated canon. +- `promote:canon -- --version V29 --commit --dry-run` renders a V29 + command plan naming all local proof suites, staging-testnet readback + verifier, Terminal browser proof, generated `.bitcode/v29-*` reports, + `BITCODE_SPEC_V29_PROVEN.md`, and promoted-family checks. +- `.github/workflows/v29-canon-promotion.yml` runs only for `version/v29` + pull requests into `main`, validates the source branch, runs promotion-grade + proof, and commits the generated V29 promotion artifacts back to `version/v29`. +- `prepare-bitcode-spec-family-promotion.mjs` rewrites V29 hand-authored status + truth for promoted mode. +- `prepare-bitcode-runtime-canon-promotion.mjs` rewrites both standalone + demonstration posture and commercial `packages/protocol` posture for V29 + active / V30 draft. +- `BITCODE_V29_QA.md`, README, V29 SPEC, DELTA, NOTES, PARITY, package scripts, + and workflows describe local/staging readiness without committing secrets or + staging credentials. diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 2b355e509..bca0c1e75 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -81,6 +81,42 @@ For a simplified reading of V29: 10. **Gate 10: Local And Staging Promotion Readiness** - Run non-mocked local validation, staging-testnet readback, generated proof artifacts, promotion dry-run, and `version/v29` promotion readiness. +## Gate 10 working notes + +Gate 10 is the final V29 gate before the version branch can be requested into +`main`. +It is not a product redesign gate. +It proves that every preceding Terminal-depth gate is promotable and that the +automation can safely advance canon. + +Accepted Gate 10 posture: + +- V29 remains draft while Gate 10 is implemented; `BITCODE_SPEC.txt` stays + `V28` until the V29 promotion workflow creates the canonical promotion commit. +- Gate-quality CI runs the Gate 10 checker and remains greenable before and + after promotion by branching on the active pointer. +- Canon-quality CI similarly accepts V28/V29 draft posture before promotion and + V29/V30 promoted posture after promotion. +- `promote-bitcode-canon.mjs` supports V29 and names every required local proof + suite, the staging-testnet readback verifier, Terminal browser proof, runtime + posture preparation, generated proof creation, and promoted-family validation. +- `.github/workflows/v29-canon-promotion.yml` owns the `version/v29` to `main` + promotion proof and generated-artifact commit. +- `packages/protocol/src/canon-posture.js`, `packages/protocol/data/state.json`, + and the standalone demonstration posture are kept aligned so local/staging + readback does not present stale active/draft truth. +- The V29 QA ledger records staging-testnet readback expectations and required + local proof commands without writing environment values into tracked files. + +Gate 10 completion condition: + +- `pnpm run check:v29-gate10` passes. +- `npm run promote:canon -- --version V29 --commit HEAD --dry-run` prints a V29 + promotion plan. +- The focused local suites named by the gate checker pass or are intentionally + delegated to the promotion workflow with documented rationale. +- The gate branch is committed, pushed, and pull-requested into `version/v29`. + ## Gate 1 closure notes Gate 1 is complete only when the V29 family exists, validates, and is wired to CI. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index f1a4b9c53..be96479b7 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -57,7 +57,7 @@ No `_legacy/` source is active source truth. | Organization permission authority | Gate 7 | `packages/btd/src/authority.ts`, BTD/API/MCP/ChatGPT App tests, sandbox harness authority evidence, Terminal Authority section, Gate 7 checker | drafted | Registry-derived roles, holdings, read-license authority, settlement, confirmation, and interface admission govern actions. | | Commercial formalization | Gate 8 | `packages/protocol/src/index.js`, `packages/protocol/src/canon-posture.js`, root scripts, protocol package tests, import scans, docs, Gate 8 checker | drafted | Demonstration-origin commercial internals are package-native and no direct demonstration-source imports remain in commercial/runtime sources. | | Terminal UX quality | Gate 9 | Terminal UX contract, Playwright/Jest/a11y/responsive/browser QA | drafted | Complete transaction cockpit is usable by default and inspectable in detail. | -| Promotion readiness | Gate 10 | promotion workflow, `.bitcode/v29-*`, `BITCODE_SPEC_V29_PROVEN.md` | pending | `version/v29` can promote to `main` only after all V29 checks pass. | +| Promotion readiness | Gate 10 | promotion workflow, promotion command plan, V29 QA ledger, runtime posture preparation, `.bitcode/v29-*`, `BITCODE_SPEC_V29_PROVEN.md` | drafted | `version/v29` can promote to `main` only after all V29 checks pass and promotion automation can commit generated canon. | ## V29 implementation checklist @@ -74,7 +74,7 @@ No `_legacy/` source is active source truth. | Gate 7 organization authority | `pnpm run check:v29-gate7` proves shared org/interface authority across BTD, API, MCP, ChatGPT App, harness, and Terminal | drafted | | Gate 8 commercial formalization | `pnpm run check:v29-gate8` proves package-native protocol exports, V28/V29 posture, script import cleanup, docs, tests, and CI wiring | drafted | | Gate 9 Terminal UX browser proof | `pnpm run check:v29-gate9` proves named landmarks, explicit state semantics, responsive browser coverage, focused Jest coverage, and CI wiring | drafted | -| Promotion gate | Gate 10 closes generated proof and promotion automation | pending | +| Gate 10 promotion readiness | `pnpm run check:v29-gate10` proves local/staging readiness, V29 promotion workflow support, runtime posture preparation, promotion dry-run, and generated-canon automation | drafted | ## Gate 1 Parity @@ -300,3 +300,53 @@ Gate 9 completion condition: - `pnpm run check:v29-gate9` passes. - Focused UAPI Jest coverage and Playwright Terminal browser proof pass. - V29 SPEC, DELTA, NOTES, PARITY, Terminal README, package scripts, and gate-quality workflow name the browser-proof contract. + +## Gate 10 Parity + +Gate 10 closes the local/staging and promotion-readiness slice by proving that +the version branch can become canon through automation rather than operator +memory. + +Accepted surfaces: + +- `scripts/check-v29-gate10-local-staging-promotion-readiness.mjs` validates + the Gate 10 specification, QA ledger, scripts, workflow wiring, runtime + posture, and promotion-mode behavior. +- `.github/workflows/bitcode-gate-quality.yml` runs all V29 gate checks in + draft posture and switches to promoted V29 checks after the promotion commit. +- `.github/workflows/bitcode-canon-quality.yml` accepts both V28 active / V29 + draft and V29 active / V30 draft states. +- `.github/workflows/v29-canon-promotion.yml` is the version promotion workflow + for `version/v29` pull requests into `main`; it validates, promotes, + generates `BITCODE_SPEC_V29_PROVEN.md`, writes `.bitcode/v29-*`, and commits + the pointer update back to the version branch. +- `scripts/promote-bitcode-canon.mjs` supports `--version V29`, includes every + V29 gate check, local proof suites, staging-testnet readback verifier, + Terminal browser proof, runtime/spec preparation, generated proof creation, + and promoted-family validation. +- `scripts/prepare-bitcode-spec-family-promotion.mjs` rewrites V29 + hand-authored status truth for promoted mode. +- `scripts/prepare-bitcode-runtime-canon-promotion.mjs` rewrites standalone + demonstration posture and commercial `packages/protocol` posture/data for V29 + active / V30 draft. +- `BITCODE_V29_QA.md` names the local and staging-testnet evidence packet + without storing environment secrets. + +Accepted boundaries: + +- Gate 10 does not merge `version/v29` to `main`; it prepares the version branch + for that pull request. +- Gate 10 does not commit `BITCODE_SPEC_V29_PROVEN.md`; the promotion workflow + owns generated canon. +- Gate 10 does not require value-bearing mainnet behavior. +- Gate 10 does not add versioned runtime routes or source identifiers. + +Gate 10 completion condition: + +- `pnpm run check:v29-gate10` passes. +- `npm run promote:canon -- --version V29 --commit HEAD --dry-run` produces a + V29 command plan. +- Gate-quality CI invokes the Gate 10 checker. +- V29 SPEC, DELTA, NOTES, PARITY, QA ledger, README, package scripts, promotion + scripts, runtime posture preparation, and workflows name the promotion + readiness boundary. diff --git a/BITCODE_V29_QA.md b/BITCODE_V29_QA.md new file mode 100644 index 000000000..e09f69aaf --- /dev/null +++ b/BITCODE_V29_QA.md @@ -0,0 +1,62 @@ +# Bitcode V29 QA Ledger + +## Purpose + +This ledger records V29 Terminal-depth and promotion-readiness QA. +It is source-safe: environment values, tokens, database passwords, OIDC tokens, +OpenAI keys, Supabase service roles, and wallet material stay in untracked +environment files or external systems. + +## Gate 10 Local And Staging Promotion Readiness QA + +Gate 10 closes when `version/v29` is ready to be pull-requested into `main` and +promotion automation can advance canon without hand edits. + +Required local proof: + +- `pnpm run check:v29-gate10` +- `npm run promote:canon -- --version V29 --commit HEAD --dry-run` +- `pnpm run check:v29-gate9` +- `pnpm --dir uapi run test:e2e:terminal-ux` +- `pnpm test:qa:v28:pipeline-readback` +- `npm --prefix protocol-demonstration test` +- `npm --prefix protocol-demonstration run test:v28-mvp-qa` + +Required staging-testnet readback: + +- staging Supabase project id remains `tkpyosihuouusyaxtbau`; +- staging Data API base remains `https://tkpyosihuouusyaxtbau.supabase.co/rest/v1/`; +- staging validation must use untracked environment files or deployment + environment variables; +- readback evidence must classify Terminal transaction rows, execution rows, + pipeline telemetry rows, ledger/journal rows, settlement/reconciliation rows, + AssetPack preview/unlock rows, and delivery/PR rows as present, absent, or + explicitly blocked. + +Promotion workflow evidence: + +- `.github/workflows/v29-canon-promotion.yml` runs only for `version/v29` pull + requests into `main`; +- the workflow validates V29 while `BITCODE_SPEC.txt` is `V28`; +- the workflow commits `BITCODE_SPEC.txt -> V29`, `BITCODE_SPEC_V29_PROVEN.md`, + `.bitcode/v29-*`, runtime canon posture, and package posture/data updates; +- after the workflow commit, canon-quality and gate-quality checks validate V29 + promoted posture rather than stale V28/V29 draft posture. + +Manual QA packet for staging-testnet promotion review: + +1. Terminal URL and selected transaction route state. +2. Browser screenshot of the Terminal cockpit default view. +3. Browser screenshot of selected transaction detail with expanded telemetry. +4. Pipeline readback summary for ReadNeedComprehensionSynthesis and + ReadFitsFindingSynthesis rows. +5. Ledger/database reconciliation summary. +6. AssetPack disclosure summary proving protected source remained hidden before + settlement. +7. Delivery or blocked-delivery summary. +8. Redacted server logs and browser console output. + +Gate 10 does not require committing live staging output. +It requires that the local and workflow proof surface is precise enough for +staging evidence to be attached to the promotion pull request without code +changes or secret leakage. diff --git a/README.md b/README.md index 79d8ad57a..51346f18b 100644 --- a/README.md +++ b/README.md @@ -66,6 +66,9 @@ 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). 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 diff --git a/package.json b/package.json index 3e734144b..55a10fdca 100644 --- a/package.json +++ b/package.json @@ -53,6 +53,7 @@ "check:v29-gate7": "node scripts/check-v29-gate7-organization-permission-authority.mjs", "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: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 9c2b4f633..c7864a6f8 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -21,5 +21,10 @@ Current exported commercial helpers include: - canonical proven-generation helpers; - the package app/server context used by commercial interfaces. +V29 Gate 10 treats this package as promotion-critical runtime posture. +`packages/protocol/src/canon-posture.js` and `packages/protocol/data/state.json` +must remain aligned to `V28` active, `V29` draft during gate work, then be +rewritten by promotion automation to `V29` active, `V30` draft. + The package boundary is enforced by `packages/protocol` tests, the UAPI commercial protocol boundary test, and `check:v29-gate8`. diff --git a/packages/protocol/data/state.json b/packages/protocol/data/state.json index 88ef93709..1b9686562 100644 --- a/packages/protocol/data/state.json +++ b/packages/protocol/data/state.json @@ -1,17 +1,17 @@ { "version": 3, - "specVersion": "Bitcode Spec V27 active canon / V28 system draft", + "specVersion": "Bitcode Spec V28 active canon / V29 system draft", "canonPosture": { - "activeCanonVersion": "V27", - "draftTargetVersion": "V28", - "operatorLabel": "V27 active canon / V28 system draft", - "specVersionLabel": "Bitcode Spec V27 active canon / V28 system draft", + "activeCanonVersion": "V28", + "draftTargetVersion": "V29", + "operatorLabel": "V28 active canon / V29 system draft", + "specVersionLabel": "Bitcode Spec V28 active canon / V29 system draft", "documentTitle": "Bitcode Demonstration", - "policyRef": "policy://bitcode/spec-v27-active-v28-system-draft/current", - "activeProvenAppendixPath": "BITCODE_SPEC_V27_PROVEN.md", - "draftSpecPath": "BITCODE_SPEC_V28.md", - "draftDeltaPath": "BITCODE_SPEC_V28_DELTA.md", - "draftParityPath": "BITCODE_SPEC_V28_PARITY_MATRIX.md", + "policyRef": "policy://bitcode/spec-v28-active-v29-system-draft/current", + "activeProvenAppendixPath": "BITCODE_SPEC_V28_PROVEN.md", + "draftSpecPath": "BITCODE_SPEC_V29.md", + "draftDeltaPath": "BITCODE_SPEC_V29_DELTA.md", + "draftParityPath": "BITCODE_SPEC_V29_PARITY_MATRIX.md", "inheritedCanonSurfaceLabel": "V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27", "heroEyebrow": "Bitcode transactions and activity", "heroLede": "Set the active scenario, select supply, and follow the flow from deposit through settlement.", diff --git a/protocol-demonstration/test/v22-canon-drift.test.js b/protocol-demonstration/test/v22-canon-drift.test.js index 2b436b00c..01756570c 100644 --- a/protocol-demonstration/test/v22-canon-drift.test.js +++ b/protocol-demonstration/test/v22-canon-drift.test.js @@ -371,6 +371,95 @@ test('V25 runtime promotion preparation rewrites canon posture source and README assert.match(rewrittenReadme, /V26 is the next draft target after this promotion\./); }); +test('runtime promotion preparation rewrites optional protocol package posture carriers', async () => { + const fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bitcode-package-runtime-promotion-')); + await fs.mkdir(path.join(fixtureRoot, 'protocol-demonstration', 'src'), { recursive: true }); + await fs.mkdir(path.join(fixtureRoot, 'packages', 'protocol', 'src'), { recursive: true }); + await fs.mkdir(path.join(fixtureRoot, 'packages', 'protocol', 'data'), { recursive: true }); + + const canonPostureSource = [ + "// @ts-check", + "export const ACTIVE_CANON_VERSION = 'V28';", + "export const DRAFT_TARGET_VERSION = 'V29';", + 'export function buildCanonPosture() {', + " return { inheritedCanonSurfaceLabel: 'V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27' };", + '}' + ].join('\n'); + const demonstrationReadme = [ + '# Bitcode Protocol Demonstration - V28 canonical deterministic local prototype', + '', + 'This demo is governed by the active V28 canonical spec.', + '', + '- `BITCODE_SPEC.txt -> V28`', + '- current generated appendix: `BITCODE_SPEC_V28_PROVEN.md`', + '', + 'Active canon remains `V28`.', + 'V29 is the next draft target after this promotion.' + ].join('\n'); + const packageReadme = [ + '# Bitcode Protocol Package', + '', + 'It carries active/draft canon posture (`V28` active, `V29` draft during V29 work);', + 'must remain aligned to `V28` active, `V29` draft during gate work, then be', + 'rewritten by promotion automation to `V29` active, `V30` draft.' + ].join('\n'); + const packageState = JSON.stringify( + { + specVersion: 'Bitcode Spec V28 active canon / V29 system draft', + canonPosture: { + activeCanonVersion: 'V28', + draftTargetVersion: 'V29', + operatorLabel: 'V28 active canon / V29 system draft', + specVersionLabel: 'Bitcode Spec V28 active canon / V29 system draft', + policyRef: 'policy://bitcode/spec-v28-active-v29-system-draft/current', + activeProvenAppendixPath: 'BITCODE_SPEC_V28_PROVEN.md', + draftSpecPath: 'BITCODE_SPEC_V29.md', + draftDeltaPath: 'BITCODE_SPEC_V29_DELTA.md', + draftParityPath: 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + inheritedCanonSurfaceLabel: 'V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27' + } + }, + null, + 2 + ); + + await Promise.all([ + fs.writeFile(path.join(fixtureRoot, 'protocol-demonstration', 'src', 'canon-posture.js'), canonPostureSource, 'utf8'), + fs.writeFile(path.join(fixtureRoot, 'protocol-demonstration', 'README.md'), demonstrationReadme, 'utf8'), + fs.writeFile(path.join(fixtureRoot, 'packages', 'protocol', 'src', 'canon-posture.js'), canonPostureSource, 'utf8'), + fs.writeFile(path.join(fixtureRoot, 'packages', 'protocol', 'README.md'), packageReadme, 'utf8'), + fs.writeFile(path.join(fixtureRoot, 'packages', 'protocol', 'data', 'state.json'), packageState, 'utf8') + ]); + + execFileSync(process.execPath, [ + prepareRuntimeScriptPath, + '--version', + 'V29', + '--next-draft', + 'V30', + '--repo-root', + fixtureRoot + ], { + cwd: fixtureRoot, + encoding: 'utf8' + }); + + const rewrittenPackagePosture = await fs.readFile(path.join(fixtureRoot, 'packages', 'protocol', 'src', 'canon-posture.js'), 'utf8'); + const rewrittenPackageReadme = await fs.readFile(path.join(fixtureRoot, 'packages', 'protocol', 'README.md'), 'utf8'); + const rewrittenPackageState = await fs.readFile(path.join(fixtureRoot, 'packages', 'protocol', 'data', 'state.json'), 'utf8'); + + assert.match(rewrittenPackagePosture, /ACTIVE_CANON_VERSION = 'V29'/); + assert.match(rewrittenPackagePosture, /DRAFT_TARGET_VERSION = 'V30'/); + assert.match(rewrittenPackagePosture, /inheritedCanonSurfaceLabel: 'V16\/V17\/V18\/V19\/V20\/V21\/V22\/V23\/V24\/V25\/V26\/V27\/V28'/); + assert.match(rewrittenPackageReadme, /`V29` active, `V30` draft after V29 promotion/); + assert.match(rewrittenPackageReadme, /must remain aligned to `V29` active, `V30` draft after promotion\./); + assert.match(rewrittenPackageState, /"activeCanonVersion": "V29"/); + assert.match(rewrittenPackageState, /"draftTargetVersion": "V30"/); + assert.match(rewrittenPackageState, /"activeProvenAppendixPath": "BITCODE_SPEC_V29_PROVEN.md"/); + assert.match(rewrittenPackageState, /"draftSpecPath": "BITCODE_SPEC_V30.md"/); + assert.match(rewrittenPackageState, /"inheritedCanonSurfaceLabel": "V16\/V17\/V18\/V19\/V20\/V21\/V22\/V23\/V24\/V25\/V26\/V27\/V28"/); +}); + test('V25 promotion dry-run includes drift detection and runtime posture preparation', () => { const output = execFileSync(process.execPath, [ promoteScriptPath, diff --git a/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs b/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs new file mode 100644 index 000000000..53e846a68 --- /dev/null +++ b/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs @@ -0,0 +1,225 @@ +#!/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-v29-gate10-local-staging-promotion-readiness.mjs [--promotion-mode] [--skip-branch-check] [--repo-root ]', + '', + 'Checks V29 Gate 10 local/staging validation and canonical promotion 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, + args.promotionMode ? ['V28', 'V29'].includes(pointer) : pointer === 'V28', + args.promotionMode + ? `BITCODE_SPEC.txt must be V28 before V29 promotion or V29 after promotion. Observed ${pointer || 'empty'}.` + : `BITCODE_SPEC.txt must remain V28 during V29 Gate 10 work. Observed ${pointer || 'empty'}.`, + ); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v29' || /^v29\/gate-10-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V29 Gate 10 work must occur on version/v29 or v29/gate-10-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + const requiredFiles = [ + 'BITCODE_SPEC_V29.md', + 'BITCODE_SPEC_V29_DELTA.md', + 'BITCODE_SPEC_V29_NOTES.md', + 'BITCODE_SPEC_V29_PARITY_MATRIX.md', + 'BITCODE_V29_QA.md', + 'scripts/check-v29-gate10-local-staging-promotion-readiness.mjs', + 'scripts/promote-bitcode-canon.mjs', + 'scripts/prepare-bitcode-spec-family-promotion.mjs', + 'scripts/prepare-bitcode-runtime-canon-promotion.mjs', + '.github/workflows/bitcode-gate-quality.yml', + '.github/workflows/bitcode-canon-quality.yml', + '.github/workflows/v29-canon-promotion.yml', + 'packages/protocol/src/canon-posture.js', + 'packages/protocol/data/state.json', + 'packages/protocol/README.md', + '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_V29.md'); + const delta = read(root, 'BITCODE_SPEC_V29_DELTA.md'); + const notes = read(root, 'BITCODE_SPEC_V29_NOTES.md'); + const parity = read(root, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'); + const qa = read(root, 'BITCODE_V29_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/v29-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 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('V29 local and staging promotion readiness canon'), 'V29 SPEC must define local/staging promotion readiness canon.'); + assertCheck(failures, delta.includes('Gate 10: Local And Staging Promotion Readiness') && delta.includes('Closure acceptance'), 'V29 DELTA must define Gate 10 closure acceptance.'); + assertCheck(failures, notes.includes('Gate 10 working notes') && notes.includes('staging-testnet readback'), 'V29 NOTES must carry Gate 10 working notes.'); + assertCheck(failures, parity.includes('## Gate 10 Parity') && parity.includes('Gate 10 completion condition'), 'V29 PARITY must include Gate 10 parity and completion condition.'); + assertCheck(failures, qa.includes('Bitcode V29 QA Ledger') && qa.includes('Gate 10 Local And Staging Promotion Readiness QA'), 'V29 QA ledger must record Gate 10 local/staging promotion readiness.'); + + assertCheck( + failures, + packageJson.includes('"check:v29-gate10"') && gateWorkflow.includes('check-v29-gate10-local-staging-promotion-readiness.mjs'), + 'package.json and gate-quality workflow must run the Gate 10 checker.', + ); + assertCheck( + failures, + gateWorkflow.includes('if [ "$POINTER" = "V28" ]') && + gateWorkflow.includes('elif [ "$POINTER" = "V29" ]') && + gateWorkflow.includes('--version V29 --mode promoted') && + gateWorkflow.includes('check-v29-gate10-local-staging-promotion-readiness.mjs --promotion-mode --skip-branch-check'), + 'Gate-quality workflow must tolerate both V28-draft and V29-promoted branch states.', + ); + assertCheck( + failures, + canonWorkflow.includes('if [ "$POINTER" = "V28" ]') && + canonWorkflow.includes('elif [ "$POINTER" = "V29" ]') && + canonWorkflow.includes('--active-canon V29 --draft-target V30'), + 'Canon-quality workflow must validate both V28/V29 draft posture and V29/V30 promoted posture.', + ); + assertCheck( + failures, + promotionWorkflow.includes('head.ref == \'version/v29\'') && + promotionWorkflow.includes('npm run promote:canon -- --version V29') && + promotionWorkflow.includes('BITCODE_SPEC_V29_PROVEN.md') && + promotionWorkflow.includes('packages/protocol/src/canon-posture.js') && + promotionWorkflow.includes('packages/protocol/data/state.json') && + promotionWorkflow.includes('packages/protocol/README.md') && + promotionWorkflow.includes('Promote V29 canon files'), + 'V29 promotion workflow must validate version/v29 and commit V29 promotion artifacts.', + ); + + assertCheck( + failures, + promoteScript.includes("const v29DraftSpecCheckCommand") && + promoteScript.includes("const v29Gate10Command") && + promoteScript.includes("if (version === 'V29')") && + promoteScript.includes("buildDerivedV29CommitMessageBody") && + promoteScript.includes("'V29'") && + promoteScript.includes("scripts/check-v29-gate10-local-staging-promotion-readiness.mjs"), + 'Canonical promotion script must support V29 command planning and commit body generation.', + ); + assertCheck( + failures, + prepareSpecScript.includes("if (version === 'V29')") && + prepareSpecScript.includes('V29 canonical system specification for Terminal transaction depth') && + prepareSpecScript.includes('BITCODE_SPEC_V29_PROVEN.md'), + 'Spec-family promotion preparation must rewrite V29 hand-authored status truth.', + ); + assertCheck( + failures, + prepareRuntimeScript.includes("'packages', 'protocol', 'src', 'canon-posture.js'") && + prepareRuntimeScript.includes("'packages', 'protocol', 'data', 'state.json'") && + prepareRuntimeScript.includes("'packages', 'protocol', 'README.md'") && + prepareRuntimeScript.includes('rewriteRuntimeDataState'), + 'Runtime promotion preparation must update commercial package posture, package data, and package README.', + ); + + assertCheck( + failures, + packageCanonPosture.includes("ACTIVE_CANON_VERSION = 'V28'") && + packageCanonPosture.includes("DRAFT_TARGET_VERSION = 'V29'") && + packageState.includes('"activeCanonVersion": "V28"') && + packageState.includes('"draftTargetVersion": "V29"') && + packageState.includes('"activeProvenAppendixPath": "BITCODE_SPEC_V28_PROVEN.md"') && + packageState.includes('"draftSpecPath": "BITCODE_SPEC_V29.md"'), + 'Protocol package posture and seed state must be aligned to V28 active / V29 draft before promotion.', + ); + assertCheck( + failures, + protocolReadme.includes('V28` active, `V29` draft') && protocolReadme.includes('Gate 10'), + 'Protocol package README must name the draft posture and Gate 10 promotion boundary.', + ); + assertCheck( + failures, + rootReadme.includes('check:v29-gate10') && rootReadme.includes('v29-canon-promotion.yml'), + 'README must document the Gate 10 command and V29 promotion workflow.', + ); + + if (failures.length) { + process.stderr.write('V29 Gate 10 local/staging promotion readiness check failed:\n'); + for (const failure of failures) process.stderr.write(`- ${failure}\n`); + process.exit(1); + } + + process.stdout.write( + `V29 Gate 10 local/staging 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 50215c96b..63f7fb573 100644 --- a/scripts/prepare-bitcode-runtime-canon-promotion.mjs +++ b/scripts/prepare-bitcode-runtime-canon-promotion.mjs @@ -28,7 +28,7 @@ function parseArgs(argv) { function printHelp() { process.stdout.write( [ - 'Usage: node scripts/prepare-bitcode-runtime-canon-promotion.mjs --version V26 [--next-draft V27] [--repo-root ]', + 'Usage: node scripts/prepare-bitcode-runtime-canon-promotion.mjs --version V29 [--next-draft V30] [--repo-root ]', '', 'Rewrites the preserved protocol/runtime canon-posture surfaces for canonical promotion.' ].join('\n') @@ -58,6 +58,16 @@ function promotedProvenPath(version) { : `_legacy/ENGI_SPEC_${version}_PROVEN.md`; } +/** + * @param {string} version + * @returns {string} + */ +function inheritedCanonSurfaceLabelFor(version) { + const numeric = Number(String(version || '').replace(/^V/u, '')); + if (!Number.isInteger(numeric) || numeric <= 16) return ''; + return Array.from({ length: numeric - 16 }, (_, index) => `V${index + 16}`).join('/'); +} + /** * @param {string} content * @param {string} version @@ -66,7 +76,11 @@ function promotedProvenPath(version) { function rewriteCanonPostureSource(content, version, nextDraft) { return content .replace(/export const ACTIVE_CANON_VERSION = 'V\d+';/, `export const ACTIVE_CANON_VERSION = '${version}';`) - .replace(/export const DRAFT_TARGET_VERSION = 'V\d+';/, `export const DRAFT_TARGET_VERSION = '${nextDraft}';`); + .replace(/export const DRAFT_TARGET_VERSION = 'V\d+';/, `export const DRAFT_TARGET_VERSION = '${nextDraft}';`) + .replace( + /inheritedCanonSurfaceLabel: 'V\d+(?:\/V\d+)*'/, + `inheritedCanonSurfaceLabel: '${inheritedCanonSurfaceLabelFor(version)}'` + ); } /** @@ -111,6 +125,57 @@ function rewriteReadme(content, version, nextDraft) { return rewritten; } +/** + * @param {string} content + * @param {string} version + * @param {string} nextDraft + */ +function rewritePackageReadme(content, version, nextDraft) { + return content.replace( + /active\/draft canon posture \(`V\d+` active, `V\d+` draft(?: during V\d+ work| after V\d+ promotion)?\);/m, + `active/draft canon posture (\`${version}\` active, \`${nextDraft}\` draft after ${version} promotion);` + ).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.` + ); +} + +/** + * @param {string} content + * @param {string} version + * @param {string} nextDraft + */ +function rewriteRuntimeDataState(content, version, nextDraft) { + const activeSpec = `${projectLabel(version)} Spec ${version} active canon / ${nextDraft} system draft`; + return content + .replace(/"specVersion": "Bitcode Spec V\d+ active canon \/ V\d+ system draft"/, `"specVersion": "${activeSpec}"`) + .replace(/"activeCanonVersion": "V\d+"/, `"activeCanonVersion": "${version}"`) + .replace(/"draftTargetVersion": "V\d+"/, `"draftTargetVersion": "${nextDraft}"`) + .replace(/"operatorLabel": "V\d+ active canon \/ V\d+ system draft"/, `"operatorLabel": "${version} active canon / ${nextDraft} system draft"`) + .replace(/"specVersionLabel": "Bitcode Spec V\d+ active canon \/ V\d+ system draft"/, `"specVersionLabel": "${activeSpec}"`) + .replace(/"policyRef": "policy:\/\/bitcode\/spec-v\d+-active-v\d+-system-draft\/current"/, `"policyRef": "policy://bitcode/spec-${version.toLowerCase()}-active-${nextDraft.toLowerCase()}-system-draft/current"`) + .replace(/"activeProvenAppendixPath": "BITCODE_SPEC_V\d+_PROVEN\.md"/, `"activeProvenAppendixPath": "${promotedProvenPath(version)}"`) + .replace(/"draftSpecPath": "BITCODE_SPEC_V\d+\.md"/, `"draftSpecPath": "BITCODE_SPEC_${nextDraft}.md"`) + .replace(/"draftDeltaPath": "BITCODE_SPEC_V\d+_DELTA\.md"/, `"draftDeltaPath": "BITCODE_SPEC_${nextDraft}_DELTA.md"`) + .replace(/"draftParityPath": "BITCODE_SPEC_V\d+_PARITY_MATRIX\.md"/, `"draftParityPath": "BITCODE_SPEC_${nextDraft}_PARITY_MATRIX.md"`) + .replace(/"inheritedCanonSurfaceLabel": "V\d+(?:\/V\d+)*"/, `"inheritedCanonSurfaceLabel": "${inheritedCanonSurfaceLabelFor(version)}"`); +} + +/** + * @param {string} filePath + * @returns {Promise} + */ +async function readOptionalFile(filePath) { + try { + return await fs.readFile(filePath, 'utf8'); + } catch (error) { + if (error && typeof error === 'object' && 'code' in error && error.code === 'ENOENT') { + return null; + } + throw error; + } +} + async function main() { const args = parseArgs(process.argv.slice(2)); if (args.help) { @@ -126,19 +191,37 @@ async function main() { const nextDraft = args.nextDraft || deriveNextDraft(version); const resolvedRepoRoot = path.resolve(args.repoRoot || repoRoot); - const canonPosturePath = path.join(resolvedRepoRoot, 'protocol-demonstration', 'src', 'canon-posture.js'); - const readmePath = path.join(resolvedRepoRoot, 'protocol-demonstration', 'README.md'); + const demonstrationCanonPosturePath = path.join(resolvedRepoRoot, 'protocol-demonstration', 'src', 'canon-posture.js'); + const demonstrationReadmePath = path.join(resolvedRepoRoot, 'protocol-demonstration', 'README.md'); + const packageCanonPosturePath = path.join(resolvedRepoRoot, 'packages', 'protocol', 'src', 'canon-posture.js'); + const packageReadmePath = path.join(resolvedRepoRoot, 'packages', 'protocol', 'README.md'); + const packageDataStatePath = path.join(resolvedRepoRoot, 'packages', 'protocol', 'data', 'state.json'); - const [canonPostureContent, readmeContent] = await Promise.all([ - fs.readFile(canonPosturePath, 'utf8'), - fs.readFile(readmePath, 'utf8') + const [demonstrationCanonPostureContent, demonstrationReadmeContent] = await Promise.all([ + fs.readFile(demonstrationCanonPosturePath, 'utf8'), + fs.readFile(demonstrationReadmePath, 'utf8') ]); - - await Promise.all([ - fs.writeFile(canonPosturePath, rewriteCanonPostureSource(canonPostureContent, version, nextDraft), 'utf8'), - fs.writeFile(readmePath, rewriteReadme(readmeContent, version, nextDraft), 'utf8') + const [packageCanonPostureContent, packageReadmeContent, packageDataStateContent] = await Promise.all([ + readOptionalFile(packageCanonPosturePath), + readOptionalFile(packageReadmePath), + readOptionalFile(packageDataStatePath) ]); + const writes = [ + fs.writeFile(demonstrationCanonPosturePath, rewriteCanonPostureSource(demonstrationCanonPostureContent, version, nextDraft), 'utf8'), + fs.writeFile(demonstrationReadmePath, rewriteReadme(demonstrationReadmeContent, version, nextDraft), 'utf8') + ]; + if (packageCanonPostureContent !== null) { + writes.push(fs.writeFile(packageCanonPosturePath, rewriteCanonPostureSource(packageCanonPostureContent, version, nextDraft), 'utf8')); + } + if (packageReadmeContent !== null) { + writes.push(fs.writeFile(packageReadmePath, rewritePackageReadme(packageReadmeContent, version, nextDraft), 'utf8')); + } + if (packageDataStateContent !== null) { + writes.push(fs.writeFile(packageDataStatePath, rewriteRuntimeDataState(packageDataStateContent, version, nextDraft), 'utf8')); + } + await Promise.all(writes); + process.stdout.write( `Prepared runtime canon posture for ${version} active canon and ${nextDraft} draft target\n` ); diff --git a/scripts/prepare-bitcode-spec-family-promotion.mjs b/scripts/prepare-bitcode-spec-family-promotion.mjs index d22b2d43a..1699a7537 100644 --- a/scripts/prepare-bitcode-spec-family-promotion.mjs +++ b/scripts/prepare-bitcode-spec-family-promotion.mjs @@ -28,10 +28,10 @@ function parseArgs(argv) { function printHelp() { process.stdout.write( [ - 'Usage: node scripts/prepare-bitcode-spec-family-promotion.mjs --version V28 --commit [--repo-root ]', + '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, and V28.' + 'Currently implemented for V21, V22, V23, V24, V25, V28, and V29.' ].join('\n') ); } @@ -132,8 +132,36 @@ function rewritePromotionStatus(version, commit, content, kind) { }); } + if (version === 'V29') { + const sharedInventory = 'active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion'; + const scopeByKind = { + spec: 'V29 canonical system specification for Terminal transaction depth, operator recovery, wallet/BTC settlement operation, AssetPack disclosure and rights review, ledger/database reconciliation, organization permission decisions, and promotion-ready workflow proof over V28', + delta: 'V29 canonical delta for Terminal transaction depth, operator recovery, wallet/BTC settlement operation, AssetPack disclosure and rights review, ledger/database reconciliation, organization permission decisions, and promotion-ready workflow proof over V28', + notes: 'V29 canonical notes for Terminal transaction depth, local/staging readiness, and promotion automation over V28', + parity: 'V29 canonical parity ledger for Terminal transaction depth, local/staging readiness, and promotion automation over V28' + }; + const stateByKind = { + spec: 'canonical promotion complete; V29 is the active Terminal transaction-depth canon and the V29 hand-authored plus generated canon are aligned', + delta: 'canonical promotion complete; this delta records the promoted V28-to-V29 Terminal transaction-depth and promotion-readiness closure set', + notes: 'canonical promotion complete; V29 notes record the accepted Terminal-depth, local/staging, and promotion-readiness evidence', + parity: 'canonical promotion complete; V29 parity truth, product-gate audit, generated proof, and promotion automation are aligned' + }; + return rewriteStatusValues(content, { + Scope: scopeByKind[kind], + ...(kind !== 'delta' + ? { 'Last fully realized canonical target preserved in source': '`V29`' } + : {}), + 'Current canonical/latest target': '`V29`', + 'Canonical proof-source commit': `\`${commit}\``, + 'Generated structured artifact inventory': sharedInventory, + 'Source parity state': + 'V29 source-side Terminal transaction, wallet/BTC, Reading observability, AssetPack disclosure, settlement repair, organization authority, UX proof, workflow, and promotion surfaces are canonicalized in the promoted V29 file family', + 'V29 state': stateByKind[kind] + }); + } + 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, and V28. Received ${version}.`); + throw new Error(`Promotion hand-authored family rewriting is currently implemented for V21, V22, V23, V24, V25, V28, and V29. 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 424832e6d..05613d043 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.', + ' --version Canonical version to promote. Accepted targets: V19, V20, V21, V22, V23, V24, V25, V28, V29.', ' --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.', @@ -323,6 +323,24 @@ function buildCommandPlan(version, commit) { const v28PromotedCanonicalInputCheckCommand = ['node', ['scripts/check-bitcode-canonical-inputs.mjs', '--current-target', 'V28']]; const v28PromotedSpecCheckCommand = ['node', ['scripts/check-bitcode-spec-family.mjs', '--version', 'V28', '--mode', 'promoted']]; const v28PromotedCanonPostureDriftCommand = ['node', ['scripts/check-bitcode-canon-posture-drift.mjs', '--active-canon', 'V28', '--draft-target', 'V29']]; + const v29DraftSpecCheckCommand = ['node', ['scripts/check-bitcode-spec-family.mjs', '--version', 'V29', '--mode', 'draft', '--current-target', 'V28']]; + const v29CanonicalInputCheckCommand = ['node', ['scripts/check-bitcode-canonical-inputs.mjs', '--current-target', 'V28']]; + const v29DraftCanonPostureDriftCommand = ['node', ['scripts/check-bitcode-canon-posture-drift.mjs', '--active-canon', 'V28', '--draft-target', 'V29']]; + const v29Gate1Command = ['node', ['scripts/check-v29-gate1-objectives-and-gating.mjs', '--skip-branch-check']]; + const v29Gate2Command = ['node', ['scripts/check-v29-gate2-terminal-transaction-read-models.mjs', '--skip-branch-check']]; + const v29Gate3Command = ['node', ['scripts/check-v29-gate3-wallet-signer-btc-operations.mjs', '--skip-branch-check']]; + const v29Gate4Command = ['node', ['scripts/check-v29-gate4-reading-pipeline-observability.mjs', '--skip-branch-check']]; + const v29Gate5Command = ['node', ['scripts/check-v29-gate5-assetpack-disclosure-rights.mjs', '--skip-branch-check']]; + const v29Gate6Command = ['node', ['scripts/check-v29-gate6-settlement-reconciliation-repair.mjs', '--skip-branch-check']]; + const v29Gate7Command = ['node', ['scripts/check-v29-gate7-organization-permission-authority.mjs', '--skip-branch-check']]; + const v29Gate8Command = ['node', ['scripts/check-v29-gate8-demonstration-origin-formalization.mjs', '--skip-branch-check']]; + const v29Gate9Command = ['node', ['scripts/check-v29-gate9-terminal-ux-browser-proof.mjs', '--skip-branch-check']]; + const v29Gate10Command = ['node', ['scripts/check-v29-gate10-local-staging-promotion-readiness.mjs', '--promotion-mode', '--skip-branch-check']]; + const v29PreparePromotionSpecFamilyCommand = ['node', ['scripts/prepare-bitcode-spec-family-promotion.mjs', '--version', 'V29', '--commit', commit]]; + const v29PrepareRuntimePromotionCommand = ['node', ['scripts/prepare-bitcode-runtime-canon-promotion.mjs', '--version', 'V29', '--next-draft', 'V30']]; + 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 inheritedProofCommands = [ ['npm', ['--prefix', 'protocol-demonstration', 'run', 'typecheck']], ['npm', ['--prefix', 'protocol-demonstration', 'run', 'test:unit']], @@ -482,7 +500,46 @@ function buildCommandPlan(version, commit) { ['git', ['diff', '--check']] ]; } - throw new Error(`Unsupported promotion target ${version}. Expected V19, V20, V21, V22, V23, V24, V25, or V28.`); + if (version === 'V29') { + return [ + v29DraftSpecCheckCommand, + v29CanonicalInputCheckCommand, + v29DraftCanonPostureDriftCommand, + v29Gate1Command, + v29Gate2Command, + v29Gate3Command, + v29Gate4Command, + v29Gate5Command, + v29Gate6Command, + v29Gate7Command, + v29Gate8Command, + v29Gate9Command, + v29Gate10Command, + ['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/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']], + v29PreparePromotionSpecFamilyCommand, + v29PrepareRuntimePromotionCommand, + ['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']], + v29PromotedCanonicalInputCheckCommand, + v29PromotedSpecCheckCommand, + v29PromotedCanonPostureDriftCommand, + ['git', ['diff', '--check']] + ]; + } + throw new Error(`Unsupported promotion target ${version}. Expected V19, V20, V21, V22, V23, V24, V25, V28, or V29.`); } /** @@ -821,6 +878,56 @@ async function buildDerivedV28CommitMessageBody(commit) { ].join('\n'); } +/** + * @param {string} commit + * @returns {Promise} + */ +async function buildDerivedV29CommitMessageBody(commit) { + const { spec, delta, parity } = await readSpecFamily('V29'); + const scope = extractStatusValue(spec, 'Scope') || 'V29 canonical system specification for Terminal transaction depth'; + const focus = deriveScopeFocus(scope); + const decisionSection = extractSection(delta, 'Accepted V29 decisions'); + const acceptedDecisions = extractOrderedItems(decisionSection).map(stripMarkdown); + const parityRows = [ + ...parseMarkdownTable(extractSection(parity, 'V29 implementation matrix')), + ...parseMarkdownTable(extractSection(parity, 'V29 implementation checklist')) + ]; + + /** @type {string[]} */ + const bullets = []; + for (const decision of acceptedDecisions.slice(0, 4)) { + bullets.push(trimTrailingPeriod(decision)); + } + + const prioritizedAreas = [ + 'Terminal transaction read models', + 'Wallet signer/BTC operations', + 'Reading pipeline observability', + 'AssetPack disclosure rights', + 'Settlement reconciliation repair', + 'Organization permission authority', + 'Commercial formalization', + 'Terminal UX quality', + 'Promotion readiness' + ]; + for (const area of prioritizedAreas) { + const row = findParityRow(parityRows, area); + if (!row) continue; + const closureSignal = trimTrailingPeriod(stripMarkdown(row['Closure requirement'] || row['Required V29 result'] || row['Source evidence'] || '')); + if (!closureSignal) continue; + bullets.push(`${stripMarkdown(area)}: ${closureSignal}`); + } + + return [ + `Promotes V29 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 @@ -878,7 +985,10 @@ async function buildCommitMessageBody(version, commit) { if (version === 'V28') { return buildDerivedV28CommitMessageBody(commit); } - throw new Error(`Unsupported promotion target ${version}. Expected V19, V20, V21, V22, V23, V24, V25, or V28.`); + if (version === 'V29') { + return buildDerivedV29CommitMessageBody(commit); + } + throw new Error(`Unsupported promotion target ${version}. Expected V19, V20, V21, V22, V23, V24, V25, V28, or V29.`); } async function main() { @@ -889,8 +999,8 @@ async function main() { } const version = args.version || ''; - if (!['V19', 'V20', 'V21', 'V22', 'V23', 'V24', 'V25', 'V28'].includes(version)) { - throw new Error(`Canonical promotion accepts --version V19, V20, V21, V22, V23, V24, V25, or V28. Received ${version || 'none'}.`); + 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'}.`); } const commit = args.commit || ''; if (!commit) { From c02638a13a464b1a15430cf9072fd13a4391435d Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 14:33:57 -0300 Subject: [PATCH 11/18] V29 Gate 10: Close promoted parity preparation (#31) Teach the V29 promotion preparer to rewrite promoted implementation matrix and checklist judgments before promoted-mode spec-family validation. Tighten the Gate 10 checker, document the promoted parity requirement, and add demonstration coverage for status plus parity mutation. --- BITCODE_SPEC_V29_DELTA.md | 3 +- BITCODE_SPEC_V29_PARITY_MATRIX.md | 3 +- .../test/v22-canon-drift.test.js | 74 +++++++++++++++++++ ...te10-local-staging-promotion-readiness.mjs | 7 +- .../prepare-bitcode-spec-family-promotion.mjs | 51 ++++++++++++- 5 files changed, 133 insertions(+), 5 deletions(-) diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index a99891edd..9cb37919f 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -216,7 +216,8 @@ Closure acceptance: pull requests into `main`, validates the source branch, runs promotion-grade proof, and commits the generated V29 promotion artifacts back to `version/v29`. - `prepare-bitcode-spec-family-promotion.mjs` rewrites V29 hand-authored status - truth for promoted mode. + truth and the promoted V29 implementation matrix/checklist judgments for + promoted mode. - `prepare-bitcode-runtime-canon-promotion.mjs` rewrites both standalone demonstration posture and commercial `packages/protocol` posture for V29 active / V30 draft. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index be96479b7..1775d7d60 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -325,7 +325,8 @@ Accepted surfaces: Terminal browser proof, runtime/spec preparation, generated proof creation, and promoted-family validation. - `scripts/prepare-bitcode-spec-family-promotion.mjs` rewrites V29 - hand-authored status truth for promoted mode. + hand-authored status truth and the promoted V29 implementation + matrix/checklist judgments for promoted mode. - `scripts/prepare-bitcode-runtime-canon-promotion.mjs` rewrites standalone demonstration posture and commercial `packages/protocol` posture/data for V29 active / V30 draft. diff --git a/protocol-demonstration/test/v22-canon-drift.test.js b/protocol-demonstration/test/v22-canon-drift.test.js index 01756570c..6a85b1ede 100644 --- a/protocol-demonstration/test/v22-canon-drift.test.js +++ b/protocol-demonstration/test/v22-canon-drift.test.js @@ -460,6 +460,80 @@ test('runtime promotion preparation rewrites optional protocol package posture c assert.match(rewrittenPackageState, /"inheritedCanonSurfaceLabel": "V16\/V17\/V18\/V19\/V20\/V21\/V22\/V23\/V24\/V25\/V26\/V27\/V28"/); }); +test('V29 spec-family promotion preparation rewrites status truth and promoted parity judgments', async () => { + const fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), 'bitcode-spec-family-v29-')); + const status = [ + '## Status', + '', + '- Current canonical/latest target: `V28`', + '- Source parity state: draft', + '- V29 state: draft implementation underway' + ].join('\n'); + const parity = [ + '# Bitcode Spec V29 Parity Matrix', + '', + status, + '', + '## V29 implementation matrix', + '', + '| Area | Gate | Source evidence | Judgment | Closure requirement |', + '| --- | --- | --- | --- | --- |', + '| Promotion readiness | Gate 10 | promotion workflow | drafted | Generated canon can be committed. |', + '', + '## V29 implementation checklist', + '', + '| Area | Required V29 result | Judgment |', + '| --- | --- | --- |', + '| Gate 10 promotion readiness | promotion dry-run and generated-canon automation | drafted |', + '', + '## Other table', + '', + '| Area | Judgment |', + '| --- | --- |', + '| Draft-only audit | drafted |' + ].join('\n'); + /** @type {Array<[string, string]>} */ + const files = [ + ['BITCODE_SPEC_V29.md', `# Bitcode Spec V29\n\n${status}\n\n## Body\nx\n`], + ['BITCODE_SPEC_V29_DELTA.md', `# Bitcode Spec V29 Delta\n\n${status}\n\n## Body\nx\n`], + ['BITCODE_SPEC_V29_NOTES.md', `# Bitcode Spec V29 Notes\n\n${status}\n\n## Body\nx\n`], + ['BITCODE_SPEC_V29_PARITY_MATRIX.md', parity] + ]; + await Promise.all(files.map(([relativePath, content]) => fs.writeFile(path.join(fixtureRoot, relativePath), content, 'utf8'))); + + const output = execFileSync(process.execPath, [ + prepareSpecFamilyScriptPath, + '--version', + 'V29', + '--commit', + 'deadbeef', + '--repo-root', + fixtureRoot + ], { + cwd: fixtureRoot, + encoding: 'utf8' + }); + + assert.match(output, /Prepared V29 hand-authored spec family for promotion with proof-source commit deadbeef/); + + for (const relativePath of files.map(([relativePath]) => relativePath)) { + const rewritten = await fs.readFile(path.join(fixtureRoot, relativePath), 'utf8'); + assert.match(rewritten, /Current canonical\/latest target: `V29`/); + assert.match(rewritten, /Canonical proof-source commit: `deadbeef`/); + const versionStateLine = rewritten.match(/^- V29 state: (.+)$/m); + const stateValue = versionStateLine?.[1]; + if (typeof stateValue !== 'string') { + throw new Error(`Missing V29 state line in ${relativePath}`); + } + assert.doesNotMatch(stateValue, /draft|pending|in progress/i); + } + + const rewrittenParity = await fs.readFile(path.join(fixtureRoot, 'BITCODE_SPEC_V29_PARITY_MATRIX.md'), 'utf8'); + assert.match(rewrittenParity, /\| Promotion readiness \| Gate 10 \| promotion workflow \| closed \|/); + assert.match(rewrittenParity, /\| Gate 10 promotion readiness \| promotion dry-run and generated-canon automation \| closed \|/); + assert.match(rewrittenParity, /\| Draft-only audit \| drafted \|/); +}); + test('V25 promotion dry-run includes drift detection and runtime posture preparation', () => { const output = execFileSync(process.execPath, [ promoteScriptPath, diff --git a/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs b/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs index 53e846a68..41c30a89d 100644 --- a/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs +++ b/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs @@ -178,8 +178,11 @@ function main() { failures, prepareSpecScript.includes("if (version === 'V29')") && prepareSpecScript.includes('V29 canonical system specification for Terminal transaction depth') && - prepareSpecScript.includes('BITCODE_SPEC_V29_PROVEN.md'), - 'Spec-family promotion preparation must rewrite V29 hand-authored status truth.', + prepareSpecScript.includes('BITCODE_SPEC_V29_PROVEN.md') && + prepareSpecScript.includes('rewritePromotedParityJudgments') && + prepareSpecScript.includes('implementation matrix') && + prepareSpecScript.includes('implementation checklist'), + 'Spec-family promotion preparation must rewrite V29 hand-authored status truth and promoted parity judgments.', ); assertCheck( failures, diff --git a/scripts/prepare-bitcode-spec-family-promotion.mjs b/scripts/prepare-bitcode-spec-family-promotion.mjs index 1699a7537..634ccbb3e 100644 --- a/scripts/prepare-bitcode-spec-family-promotion.mjs +++ b/scripts/prepare-bitcode-spec-family-promotion.mjs @@ -97,6 +97,54 @@ function rewriteStatusValues(content, values) { return `${content.slice(0, section.start)}${section.prefix}${body}${content.slice(section.end)}`; } +/** + * @param {string} content + * @param {string} heading + * @returns {string} + */ +function rewritePromotedParityTableJudgments(content, heading) { + const headingPattern = new RegExp(`^## ${heading.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\s*$`, 'm'); + const headingMatch = content.match(headingPattern); + if (!headingMatch || typeof headingMatch.index !== 'number') return content; + + const sectionStart = headingMatch.index; + const nextHeadingMatch = content.slice(sectionStart + headingMatch[0].length).match(/^##\s/m); + const sectionEnd = nextHeadingMatch + ? sectionStart + headingMatch[0].length + nextHeadingMatch.index + : content.length; + const section = content.slice(sectionStart, sectionEnd); + const lines = section.split('\n'); + const headerIndex = lines.findIndex((line) => line.trim().startsWith('|')); + if (headerIndex < 0) return content; + + const headers = lines[headerIndex].split('|').slice(1, -1).map((cell) => cell.trim()); + const judgmentIndex = headers.findIndex((header) => header === 'Judgment'); + if (judgmentIndex < 0) return content; + + const rewrittenLines = lines.map((line, index) => { + if (index <= headerIndex + 1 || !line.trim().startsWith('|')) return line; + const cells = line.split('|'); + const cellIndex = judgmentIndex + 1; + if (!cells[cellIndex] || cells[cellIndex].trim() !== 'drafted') return line; + cells[cellIndex] = ' closed '; + return cells.join('|'); + }); + + return `${content.slice(0, sectionStart)}${rewrittenLines.join('\n')}${content.slice(sectionEnd)}`; +} + +/** + * @param {string} content + * @param {string} version + * @returns {string} + */ +function rewritePromotedParityJudgments(content, version) { + return [ + `${version} implementation matrix`, + `${version} implementation checklist` + ].reduce((rewritten, heading) => rewritePromotedParityTableJudgments(rewritten, heading), content); +} + /** * @param {string} version * @param {string} commit @@ -146,7 +194,7 @@ function rewritePromotionStatus(version, commit, content, kind) { notes: 'canonical promotion complete; V29 notes record the accepted Terminal-depth, local/staging, and promotion-readiness evidence', parity: 'canonical promotion complete; V29 parity truth, product-gate audit, generated proof, and promotion automation are aligned' }; - return rewriteStatusValues(content, { + const rewritten = rewriteStatusValues(content, { Scope: scopeByKind[kind], ...(kind !== 'delta' ? { 'Last fully realized canonical target preserved in source': '`V29`' } @@ -158,6 +206,7 @@ function rewritePromotionStatus(version, commit, content, kind) { 'V29 source-side Terminal transaction, wallet/BTC, Reading observability, AssetPack disclosure, settlement repair, organization authority, UX proof, workflow, and promotion surfaces are canonicalized in the promoted V29 file family', 'V29 state': stateByKind[kind] }); + return kind === 'parity' ? rewritePromotedParityJudgments(rewritten, version) : rewritten; } if (!['V21', 'V22', 'V23', 'V24', 'V25'].includes(version)) { From c245da17bf329d0af509a2141ce737f3e3320725 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 May 2026 17:55:05 +0000 Subject: [PATCH 12/18] Promote Bitcode canon to V29 --- BITCODE_SPEC.txt | 2 +- BITCODE_SPEC_V29.md | 10 +- BITCODE_SPEC_V29_DELTA.md | 11 +- BITCODE_SPEC_V29_NOTES.md | 12 +- BITCODE_SPEC_V29_PARITY_MATRIX.md | 58 +- BITCODE_SPEC_V29_PROVEN.md | 2389 +++++++++++++++++++ packages/protocol/README.md | 5 +- packages/protocol/data/state.json | 22 +- packages/protocol/src/canon-posture.js | 6 +- protocol-demonstration/README.md | 6 +- protocol-demonstration/src/canon-posture.js | 6 +- 11 files changed, 2461 insertions(+), 66 deletions(-) create mode 100644 BITCODE_SPEC_V29_PROVEN.md diff --git a/BITCODE_SPEC.txt b/BITCODE_SPEC.txt index 337be8993..b3ce294a8 100644 --- a/BITCODE_SPEC.txt +++ b/BITCODE_SPEC.txt @@ -1 +1 @@ -V28 +V29 diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index bffee134f..c096e0dca 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -3,12 +3,13 @@ ## Status - Version: `V29` -- V29 state: draft target opened; V29 owns deeper Terminal transaction operation after V28 promotion and must not alter the active V28 canon pointer until promotion -- Current canonical/latest target: `V28` +- V29 state: canonical promotion complete; V29 is the active Terminal transaction-depth canon and the V29 hand-authored plus generated canon are aligned +- Current canonical/latest target: `V29` +- Canonical proof-source commit: `c02638a13a464b1a15430cf9072fd13a4391435d` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` -- Generated structured artifact inventory: draft `.bitcode/v29-spec-family-report.json`, draft `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality evidence, and no `BITCODE_SPEC_V29_PROVEN.md` until promotion -- Source parity state: V29 Gate 1 opens the draft specification and quality gates; product-source parity begins from V28 Terminal, Reading, AssetPack, settlement, ledger, and workflow implementation truth +- Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion +- Source parity state: V29 source-side Terminal transaction, wallet/BTC, Reading observability, AssetPack disclosure, settlement repair, organization authority, UX proof, workflow, and promotion surfaces are canonicalized in the promoted V29 file family - State: draft target opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V28` - Draft target source: `protocol-demonstration/src/canon-posture.js` declares `DRAFT_TARGET_VERSION = 'V29'` @@ -19,6 +20,7 @@ - Parity companion: `BITCODE_SPEC_V29_PARITY_MATRIX.md` - Generated proof appendix: none until V29 promotion - Scope: V29 canonical system specification for Terminal transaction depth, operator recovery, wallet/BTC settlement operation, AssetPack disclosure and rights review, ledger/database reconciliation, organization permission decisions, and promotion-ready workflow proof over V28 +- Last fully realized canonical target preserved in source: `V29` V29 begins from promoted V28. V28 made Depositing, Read Request, Read-Need Comprehension, Finding Fits, AssetPack synthesis, source-safe preview, settlement posture, delivery, and promotion governance coherent enough for canon. diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index 9cb37919f..dbb50ab22 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -3,15 +3,16 @@ ## Status - Version: `V29` -- V29 state: draft target opened; this delta records V29's planned Terminal-depth changes over promoted V28 -- Current canonical/latest target: `V28` +- V29 state: canonical promotion complete; this delta records the promoted V28-to-V29 Terminal transaction-depth and promotion-readiness closure set +- Current canonical/latest target: `V29` +- Canonical proof-source commit: `c02638a13a464b1a15430cf9072fd13a4391435d` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` -- Generated structured artifact inventory: draft `.bitcode/v29-spec-family-report.json`, draft `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, and no `BITCODE_SPEC_V29_PROVEN.md` until promotion -- Source parity state: V29 delta truth is opened in documentation and gate-quality scripts; product implementation begins only through V29 gate branches +- Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion +- Source parity state: V29 source-side Terminal transaction, wallet/BTC, Reading observability, AssetPack disclosure, settlement repair, organization authority, UX proof, workflow, and promotion surfaces are canonicalized in the promoted V29 file family - State: draft target delta opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V28` -- Scope: V29 delta for deeper Terminal transaction operation after V28 commercial Reading, AssetPack, settlement, delivery, and promotion closure +- Scope: V29 canonical delta for Terminal transaction depth, operator recovery, wallet/BTC settlement operation, AssetPack disclosure and rights review, ledger/database reconciliation, organization permission decisions, and promotion-ready workflow proof over V28 - Spec companion: `BITCODE_SPEC_V29.md` - Notes companion: `BITCODE_SPEC_V29_NOTES.md` - Parity companion: `BITCODE_SPEC_V29_PARITY_MATRIX.md` diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index bca0c1e75..1389c23c1 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -3,13 +3,15 @@ ## Status - Version: `V29` -- V29 state: draft target opened; V29 notes now track active V28 canon and V29 Terminal-depth gate planning -- Current canonical/latest target: `V28` +- V29 state: canonical promotion complete; V29 notes record the accepted Terminal-depth, local/staging, and promotion-readiness evidence +- Current canonical/latest target: `V29` +- Canonical proof-source commit: `c02638a13a464b1a15430cf9072fd13a4391435d` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` -- Generated structured artifact inventory: draft `.bitcode/v29-spec-family-report.json`, draft `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, and no `BITCODE_SPEC_V29_PROVEN.md` until promotion -- Source parity state: notes opened from V28 handoff; source implementation begins gate-by-gate after Gate 1 -- Scope: V29 notes for deeper Terminal workflow, transaction operation, evidence readability, wallet/BTC operation, settlement repair, organization permission, and promotion-readiness work. +- Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion +- Source parity state: V29 source-side Terminal transaction, wallet/BTC, Reading observability, AssetPack disclosure, settlement repair, organization authority, UX proof, workflow, and promotion surfaces are canonicalized in the promoted V29 file family +- Scope: V29 canonical notes for Terminal transaction depth, local/staging readiness, and promotion automation over V28 +- Last fully realized canonical target preserved in source: `V29` ## Notes companion rule diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 1775d7d60..8000e08cb 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -3,19 +3,21 @@ ## Status - Version: `V29` -- V29 state: draft target opened; parity now tracks V29 gates over active V28 canon -- Current canonical/latest target: `V28` +- V29 state: canonical promotion complete; V29 parity truth, product-gate audit, generated proof, and promotion automation are aligned +- Current canonical/latest target: `V29` +- Canonical proof-source commit: `c02638a13a464b1a15430cf9072fd13a4391435d` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` -- Generated structured artifact inventory: draft `.bitcode/v29-spec-family-report.json`, draft `.bitcode/v29-canonical-input-report.json`, future `.bitcode/v29-canon-posture-drift-report.json`, and no `BITCODE_SPEC_V29_PROVEN.md` until promotion -- Source parity state: Gate 1 parity is documentation/workflow/checker closure; product-source rows start as pending V29 gate work +- Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion +- Source parity state: V29 source-side Terminal transaction, wallet/BTC, Reading observability, AssetPack disclosure, settlement repair, organization authority, UX proof, workflow, and promotion surfaces are canonicalized in the promoted V29 file family - State: draft target parity matrix opened - Active canonical pointer during draft opening: `BITCODE_SPEC.txt` -> `V28` -- Scope: V29 parity ledger for Terminal transaction depth, wallet/BTC operations, Reading pipeline observability, AssetPack disclosure, settlement repair, organization permissions, UX quality, and promotion readiness +- Scope: V29 canonical parity ledger for Terminal transaction depth, local/staging readiness, and promotion automation over V28 - Spec companion: `BITCODE_SPEC_V29.md` - Notes companion: `BITCODE_SPEC_V29_NOTES.md` - Delta companion: `BITCODE_SPEC_V29_DELTA.md` - Generated proof appendix: none until V29 promotion +- Last fully realized canonical target preserved in source: `V29` ## Purpose @@ -47,34 +49,34 @@ No `_legacy/` source is active source truth. | Area | Gate | Source evidence | Judgment | Closure requirement | | --- | --- | --- | --- | --- | -| Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V29.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v29/gate-1-objectives-and-gating` | drafted | V29 family validates in draft mode over active V28 and `check:v29-gate1` passes. | -| Workflow retargeting | Gate 1 | `.github/workflows/bitcode-gate-quality.yml`, `.github/workflows/bitcode-canon-quality.yml` | drafted | CI checks V28 active / V29 draft posture instead of stale V27/V28 posture. | -| Terminal transaction read models | Gate 2 | `uapi/app/terminal/terminal-transaction-read-model.ts`, `uapi/app/terminal/terminal-transaction-query.ts`, `TerminalTransactionWorkspace.tsx`, `TerminalTransactionDetailSurface.tsx`, UAPI tests, Gate 2 checker | drafted | Terminal transaction state is URL-addressable, recoverable, typed, low-detail by default, and expandable without raw JSON as the ordinary operator contract. | -| Wallet signer/BTC operations | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, BTC fee route, Terminal Wallet/BTC detail section, BTD and UAPI tests, Gate 3 checker | drafted | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | -| Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack/src/reading-pipeline-observability.ts`, `packages/pipeline-hosts/src/asset-pack-harness.ts`, Terminal stream components, Gate 4 checker | drafted | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt/raw-output/parsed-output telemetry is contract-projected, complete, and readable. | -| AssetPack disclosure rights | Gate 5 | `asset-pack-disclosure.ts`, AssetPack postprocess, sandbox harness, BTD access tests, Terminal disclosure review UI, Gate 5 checker | drafted | Source-safe preview and paid unlock are proven without protected-source leakage. | -| Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, sandbox harness settlement evidence, Terminal repair UI, Gate 6 checker | drafted | Ledger, database, and metaphysical state drift is classified, proof-rooted, repair-actioned, and visible. | -| Organization permission authority | Gate 7 | `packages/btd/src/authority.ts`, BTD/API/MCP/ChatGPT App tests, sandbox harness authority evidence, Terminal Authority section, Gate 7 checker | drafted | Registry-derived roles, holdings, read-license authority, settlement, confirmation, and interface admission govern actions. | -| Commercial formalization | Gate 8 | `packages/protocol/src/index.js`, `packages/protocol/src/canon-posture.js`, root scripts, protocol package tests, import scans, docs, Gate 8 checker | drafted | Demonstration-origin commercial internals are package-native and no direct demonstration-source imports remain in commercial/runtime sources. | -| Terminal UX quality | Gate 9 | Terminal UX contract, Playwright/Jest/a11y/responsive/browser QA | drafted | Complete transaction cockpit is usable by default and inspectable in detail. | -| Promotion readiness | Gate 10 | promotion workflow, promotion command plan, V29 QA ledger, runtime posture preparation, `.bitcode/v29-*`, `BITCODE_SPEC_V29_PROVEN.md` | drafted | `version/v29` can promote to `main` only after all V29 checks pass and promotion automation can commit generated canon. | +| Draft family and branch posture | Gate 1 | `BITCODE_SPEC_V29.md`, DELTA, NOTES, PARITY, `BITCODE_SPEC.txt`, branch `v29/gate-1-objectives-and-gating` | closed | V29 family validates in draft mode over active V28 and `check:v29-gate1` passes. | +| Workflow retargeting | Gate 1 | `.github/workflows/bitcode-gate-quality.yml`, `.github/workflows/bitcode-canon-quality.yml` | closed | CI checks V28 active / V29 draft posture instead of stale V27/V28 posture. | +| Terminal transaction read models | Gate 2 | `uapi/app/terminal/terminal-transaction-read-model.ts`, `uapi/app/terminal/terminal-transaction-query.ts`, `TerminalTransactionWorkspace.tsx`, `TerminalTransactionDetailSurface.tsx`, UAPI tests, Gate 2 checker | closed | Terminal transaction state is URL-addressable, recoverable, typed, low-detail by default, and expandable without raw JSON as the ordinary operator contract. | +| Wallet signer/BTC operations | Gate 3 | `packages/btd/src/btc-fee-operation.ts`, BTC fee route, Terminal Wallet/BTC detail section, BTD and UAPI tests, Gate 3 checker | closed | Signer session, PSBT, broadcast/finality/reorg/replacement/failure states are ordinary Terminal states. | +| Reading pipeline observability | Gate 4 | `packages/pipelines/asset-pack/src/reading-pipeline-observability.ts`, `packages/pipeline-hosts/src/asset-pack-harness.ts`, Terminal stream components, Gate 4 checker | closed | Pipeline/phase/PTRR/ThricifiedGeneration/tool/prompt/raw-output/parsed-output telemetry is contract-projected, complete, and readable. | +| AssetPack disclosure rights | Gate 5 | `asset-pack-disclosure.ts`, AssetPack postprocess, sandbox harness, BTD access tests, Terminal disclosure review UI, Gate 5 checker | closed | Source-safe preview and paid unlock are proven without protected-source leakage. | +| Settlement reconciliation repair | Gate 6 | BTD journal/reconciliation, Supabase readback, sandbox harness settlement evidence, Terminal repair UI, Gate 6 checker | closed | Ledger, database, and metaphysical state drift is classified, proof-rooted, repair-actioned, and visible. | +| Organization permission authority | Gate 7 | `packages/btd/src/authority.ts`, BTD/API/MCP/ChatGPT App tests, sandbox harness authority evidence, Terminal Authority section, Gate 7 checker | closed | Registry-derived roles, holdings, read-license authority, settlement, confirmation, and interface admission govern actions. | +| Commercial formalization | Gate 8 | `packages/protocol/src/index.js`, `packages/protocol/src/canon-posture.js`, root scripts, protocol package tests, import scans, docs, Gate 8 checker | closed | Demonstration-origin commercial internals are package-native and no direct demonstration-source imports remain in commercial/runtime sources. | +| Terminal UX quality | Gate 9 | Terminal UX contract, Playwright/Jest/a11y/responsive/browser QA | closed | Complete transaction cockpit is usable by default and inspectable in detail. | +| Promotion readiness | Gate 10 | promotion workflow, promotion command plan, V29 QA ledger, runtime posture preparation, `.bitcode/v29-*`, `BITCODE_SPEC_V29_PROVEN.md` | closed | `version/v29` can promote to `main` only after all V29 checks pass and promotion automation can commit generated canon. | ## V29 implementation checklist | Area | Required V29 result | Judgment | | --- | --- | --- | -| Active canon pointer | `BITCODE_SPEC.txt` remains `V28` during V29 gate work | drafted | -| Gate branch pattern | V29 work happens on `version/v29` or `v29/gate-N-*` branches | drafted | -| Spec-family shape | V29 SPEC, DELTA, NOTES, and PARITY satisfy the full spec-family checker | drafted | -| Gate 1 script | `pnpm run check:v29-gate1` fails closed on stale posture or missing gates | drafted | -| Gate 2 read model | `pnpm run check:v29-gate2` proves typed route-owned Terminal transaction reading | drafted | -| Gate 3 wallet/BTC operation | `pnpm run check:v29-gate3` proves quote lifecycle, signer recovery, blocked readiness, API posture, and Terminal Wallet/BTC detail | drafted | -| Gate 4 Reading observability | `pnpm run check:v29-gate4` proves contract-aware Reading stream telemetry and Terminal rendering | drafted | -| Gate 5 AssetPack disclosure | `pnpm run check:v29-gate5` proves source-safe disclosure review, leakage detection, Terminal preview rendering, and PR title enforcement | drafted | -| Gate 7 organization authority | `pnpm run check:v29-gate7` proves shared org/interface authority across BTD, API, MCP, ChatGPT App, harness, and Terminal | drafted | -| Gate 8 commercial formalization | `pnpm run check:v29-gate8` proves package-native protocol exports, V28/V29 posture, script import cleanup, docs, tests, and CI wiring | drafted | -| Gate 9 Terminal UX browser proof | `pnpm run check:v29-gate9` proves named landmarks, explicit state semantics, responsive browser coverage, focused Jest coverage, and CI wiring | drafted | -| Gate 10 promotion readiness | `pnpm run check:v29-gate10` proves local/staging readiness, V29 promotion workflow support, runtime posture preparation, promotion dry-run, and generated-canon automation | drafted | +| Active canon pointer | `BITCODE_SPEC.txt` remains `V28` during V29 gate work | closed | +| Gate branch pattern | V29 work happens on `version/v29` or `v29/gate-N-*` branches | closed | +| Spec-family shape | V29 SPEC, DELTA, NOTES, and PARITY satisfy the full spec-family checker | closed | +| Gate 1 script | `pnpm run check:v29-gate1` fails closed on stale posture or missing gates | closed | +| Gate 2 read model | `pnpm run check:v29-gate2` proves typed route-owned Terminal transaction reading | closed | +| Gate 3 wallet/BTC operation | `pnpm run check:v29-gate3` proves quote lifecycle, signer recovery, blocked readiness, API posture, and Terminal Wallet/BTC detail | closed | +| Gate 4 Reading observability | `pnpm run check:v29-gate4` proves contract-aware Reading stream telemetry and Terminal rendering | closed | +| Gate 5 AssetPack disclosure | `pnpm run check:v29-gate5` proves source-safe disclosure review, leakage detection, Terminal preview rendering, and PR title enforcement | closed | +| Gate 7 organization authority | `pnpm run check:v29-gate7` proves shared org/interface authority across BTD, API, MCP, ChatGPT App, harness, and Terminal | closed | +| Gate 8 commercial formalization | `pnpm run check:v29-gate8` proves package-native protocol exports, V28/V29 posture, script import cleanup, docs, tests, and CI wiring | closed | +| Gate 9 Terminal UX browser proof | `pnpm run check:v29-gate9` proves named landmarks, explicit state semantics, responsive browser coverage, focused Jest coverage, and CI wiring | closed | +| Gate 10 promotion readiness | `pnpm run check:v29-gate10` proves local/staging readiness, V29 promotion workflow support, runtime posture preparation, promotion dry-run, and generated-canon automation | closed | ## Gate 1 Parity diff --git a/BITCODE_SPEC_V29_PROVEN.md b/BITCODE_SPEC_V29_PROVEN.md new file mode 100644 index 000000000..5a9eb0819 --- /dev/null +++ b/BITCODE_SPEC_V29_PROVEN.md @@ -0,0 +1,2389 @@ +# Bitcode Spec V29 Proven + +- canonicalVersion: `V29` +- canonicalCommit: `c02638a13a464b1a15430cf9072fd13a4391435d` +- canonicalCommitRecordedAt: `2026-05-21T14:33:57-03:00` +- worktreeState: `clean` +- generatorId: `bitcode.proven-generator.v1` +- generatedAt: `2026-05-21T14:33:57-03:00` +- outputPath: `BITCODE_SPEC_V29_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: `true` +- runCount: `16` +- familyCount: `9` +- theoremCount: `58` +- memberCount: `46` +- artifactDigestCount: `736` + +## 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/packages/protocol/README.md b/packages/protocol/README.md index c7864a6f8..e657fbe70 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 (`V28` active, `V29` draft during V29 work); +- active/draft canon posture (`V29` active, `V30` draft after V29 promotion); - spec-family and canonical-input validation helpers; - canon-posture drift reporting; - canonical proven-generation helpers; @@ -23,8 +23,7 @@ Current exported commercial helpers include: V29 Gate 10 treats this package as promotion-critical runtime posture. `packages/protocol/src/canon-posture.js` and `packages/protocol/data/state.json` -must remain aligned to `V28` active, `V29` draft during gate work, then be -rewritten by promotion automation to `V29` active, `V30` draft. +must remain aligned to `V29` active, `V30` draft after promotion. The package boundary is enforced by `packages/protocol` tests, the UAPI commercial protocol boundary test, and `check:v29-gate8`. diff --git a/packages/protocol/data/state.json b/packages/protocol/data/state.json index 1b9686562..dfaf976ea 100644 --- a/packages/protocol/data/state.json +++ b/packages/protocol/data/state.json @@ -1,18 +1,18 @@ { "version": 3, - "specVersion": "Bitcode Spec V28 active canon / V29 system draft", + "specVersion": "Bitcode Spec V29 active canon / V30 system draft", "canonPosture": { - "activeCanonVersion": "V28", - "draftTargetVersion": "V29", - "operatorLabel": "V28 active canon / V29 system draft", - "specVersionLabel": "Bitcode Spec V28 active canon / V29 system draft", + "activeCanonVersion": "V29", + "draftTargetVersion": "V30", + "operatorLabel": "V29 active canon / V30 system draft", + "specVersionLabel": "Bitcode Spec V29 active canon / V30 system draft", "documentTitle": "Bitcode Demonstration", - "policyRef": "policy://bitcode/spec-v28-active-v29-system-draft/current", - "activeProvenAppendixPath": "BITCODE_SPEC_V28_PROVEN.md", - "draftSpecPath": "BITCODE_SPEC_V29.md", - "draftDeltaPath": "BITCODE_SPEC_V29_DELTA.md", - "draftParityPath": "BITCODE_SPEC_V29_PARITY_MATRIX.md", - "inheritedCanonSurfaceLabel": "V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27", + "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", "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 aa5848621..61a66bc27 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 = 'V28'; -export const DRAFT_TARGET_VERSION = 'V29'; +export const ACTIVE_CANON_VERSION = 'V29'; +export const DRAFT_TARGET_VERSION = 'V30'; 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', + inheritedCanonSurfaceLabel: 'V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27/V28', 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 34761fb47..58093ac4b 100644 --- a/protocol-demonstration/README.md +++ b/protocol-demonstration/README.md @@ -1,12 +1,12 @@ -# Bitcode Protocol Demonstration - V28 canonical deterministic local prototype +# Bitcode Protocol Demonstration - V29 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 `V28`; V29 is the next draft target after this promotion. -`BITCODE_SPEC.txt -> V28`. This demo is governed by the active V28 canonical -spec and `BITCODE_SPEC_V28_PROVEN.md` as the current generated appendix. +`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. ## What This Demonstration Carries diff --git a/protocol-demonstration/src/canon-posture.js b/protocol-demonstration/src/canon-posture.js index aa5848621..61a66bc27 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 = 'V28'; -export const DRAFT_TARGET_VERSION = 'V29'; +export const ACTIVE_CANON_VERSION = 'V29'; +export const DRAFT_TARGET_VERSION = 'V30'; 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', + inheritedCanonSurfaceLabel: 'V16/V17/V18/V19/V20/V21/V22/V23/V24/V25/V26/V27/V28', 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.' From f7efcd0107a02200bc756ff9e7d236c74395a9f6 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 15:02:25 -0300 Subject: [PATCH 13/18] V29 Gate 10: Accept promoted protocol posture Make the Gate 10 promotion-readiness checker validate the protocol package posture according to the active pointer, accepting V28/V29 before promotion and V29/V30 after the generated canon commit. Document the promoted posture requirement in the V29 spec family. --- BITCODE_SPEC_V29.md | 3 +++ BITCODE_SPEC_V29_DELTA.md | 3 ++- BITCODE_SPEC_V29_PARITY_MATRIX.md | 3 ++- ...te10-local-staging-promotion-readiness.mjs | 23 +++++++++++-------- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index c096e0dca..fc32e5c91 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -277,6 +277,9 @@ The promotion-readiness contract has five parts: `packages/protocol/data/state.json` are commercial runtime posture carriers. They must align to V28 active / V29 draft during Gate 10 work and be rewritten to V29 active / V30 draft by promotion automation. +The Gate 10 checker is promotion-mode aware: it must accept the V28/V29 package +posture before the generated canon commit and the V29/V30 package posture after +the generated canon commit. Gate 10 does not itself promote `BITCODE_SPEC.txt`. It closes when `version/v29` can be pull-requested to `main` and the V29 diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index dbb50ab22..a2d221447 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -202,7 +202,8 @@ Closure acceptance: - `check:v29-gate10` validates the V29 promotion-readiness surface from a clean Gate 10 branch and can run in `--promotion-mode` after `BITCODE_SPEC.txt` - advances to `V29`. + advances to `V29`, including the promoted V29 active / V30 draft protocol + package posture. - Gate-quality CI invokes all V29 gate scripts while V29 is still a draft and switches to promoted V29 validation after the promotion workflow writes the canonical pointer commit. diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 8000e08cb..e9e8ef3e9 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -313,7 +313,8 @@ Accepted surfaces: - `scripts/check-v29-gate10-local-staging-promotion-readiness.mjs` validates the Gate 10 specification, QA ledger, scripts, workflow wiring, runtime - posture, and promotion-mode behavior. + posture, and promotion-mode behavior before and after the generated V29/V30 + protocol package posture rewrite. - `.github/workflows/bitcode-gate-quality.yml` runs all V29 gate checks in draft posture and switches to promoted V29 checks after the promotion commit. - `.github/workflows/bitcode-canon-quality.yml` accepts both V28 active / V29 diff --git a/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs b/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs index 41c30a89d..a67b54594 100644 --- a/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs +++ b/scripts/check-v29-gate10-local-staging-promotion-readiness.mjs @@ -193,20 +193,25 @@ function main() { 'Runtime promotion preparation must update commercial package posture, package data, and package README.', ); + const expectedActiveCanon = pointer === 'V29' ? 'V29' : 'V28'; + const expectedDraftTarget = pointer === 'V29' ? 'V30' : 'V29'; + const expectedProtocolReadmePosture = + pointer === 'V29' ? 'V29` active, `V30` draft after V29 promotion' : 'V28` active, `V29` draft'; + assertCheck( failures, - packageCanonPosture.includes("ACTIVE_CANON_VERSION = 'V28'") && - packageCanonPosture.includes("DRAFT_TARGET_VERSION = 'V29'") && - packageState.includes('"activeCanonVersion": "V28"') && - packageState.includes('"draftTargetVersion": "V29"') && - packageState.includes('"activeProvenAppendixPath": "BITCODE_SPEC_V28_PROVEN.md"') && - packageState.includes('"draftSpecPath": "BITCODE_SPEC_V29.md"'), - 'Protocol package posture and seed state must be aligned to V28 active / V29 draft before promotion.', + 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('V28` active, `V29` draft') && protocolReadme.includes('Gate 10'), - 'Protocol package README must name the draft posture and Gate 10 promotion boundary.', + protocolReadme.includes(expectedProtocolReadmePosture) && protocolReadme.includes('Gate 10'), + `Protocol package README must name the ${expectedActiveCanon}/${expectedDraftTarget} posture and Gate 10 promotion boundary.`, ); assertCheck( failures, From 2330a51a12383030457578a03abb9dd336febcbf Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 15:03:25 -0300 Subject: [PATCH 14/18] V29 Gate 10: Refresh promoted proof source Refresh V29 promoted spec-family status and generated PROVEN appendix so the canonical proof-source commit includes the promoted protocol posture checker fix. --- BITCODE_SPEC_V29.md | 2 +- BITCODE_SPEC_V29_DELTA.md | 2 +- BITCODE_SPEC_V29_NOTES.md | 2 +- BITCODE_SPEC_V29_PARITY_MATRIX.md | 2 +- BITCODE_SPEC_V29_PROVEN.md | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index fc32e5c91..573e137fe 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 is the active Terminal transaction-depth canon and the V29 hand-authored plus generated canon are aligned - Current canonical/latest target: `V29` -- Canonical proof-source commit: `c02638a13a464b1a15430cf9072fd13a4391435d` +- Canonical proof-source commit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index a2d221447..0c72e6cc8 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; this delta records the promoted V28-to-V29 Terminal transaction-depth and promotion-readiness closure set - Current canonical/latest target: `V29` -- Canonical proof-source commit: `c02638a13a464b1a15430cf9072fd13a4391435d` +- Canonical proof-source commit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 1389c23c1..a43c97a27 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 notes record the accepted Terminal-depth, local/staging, and promotion-readiness evidence - Current canonical/latest target: `V29` -- Canonical proof-source commit: `c02638a13a464b1a15430cf9072fd13a4391435d` +- Canonical proof-source commit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index e9e8ef3e9..2228ddbf8 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 parity truth, product-gate audit, generated proof, and promotion automation are aligned - Current canonical/latest target: `V29` -- Canonical proof-source commit: `c02638a13a464b1a15430cf9072fd13a4391435d` +- Canonical proof-source commit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_PROVEN.md b/BITCODE_SPEC_V29_PROVEN.md index 5a9eb0819..eb110d213 100644 --- a/BITCODE_SPEC_V29_PROVEN.md +++ b/BITCODE_SPEC_V29_PROVEN.md @@ -1,11 +1,11 @@ # Bitcode Spec V29 Proven - canonicalVersion: `V29` -- canonicalCommit: `c02638a13a464b1a15430cf9072fd13a4391435d` -- canonicalCommitRecordedAt: `2026-05-21T14:33:57-03:00` +- canonicalCommit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` +- canonicalCommitRecordedAt: `2026-05-21T15:02:25-03:00` - worktreeState: `clean` - generatorId: `bitcode.proven-generator.v1` -- generatedAt: `2026-05-21T14:33:57-03:00` +- generatedAt: `2026-05-21T15:02:25-03:00` - outputPath: `BITCODE_SPEC_V29_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` From b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 15:09:08 -0300 Subject: [PATCH 15/18] V29 Gate 10: Accept promoted protocol package tests Update the protocol package boundary test to accept V29/V30 promoted canon posture while preserving V29 draft-mode validation before promotion. --- .../test/protocol-package-boundary.test.js | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/packages/protocol/test/protocol-package-boundary.test.js b/packages/protocol/test/protocol-package-boundary.test.js index 97a602ee9..25429bd9c 100644 --- a/packages/protocol/test/protocol-package-boundary.test.js +++ b/packages/protocol/test/protocol-package-boundary.test.js @@ -45,9 +45,13 @@ test('@bitcode/protocol does not import the standalone protocol demonstration', test('@bitcode/protocol commercial formalization exports package-native canon helpers', async () => { const protocol = await import('../src/index.js'); + const pointer = readFileSync(path.join(repoRoot, 'BITCODE_SPEC.txt'), 'utf8').trim(); + const expectedActiveCanon = pointer === 'V29' ? 'V29' : 'V28'; + const expectedDraftTarget = pointer === 'V29' ? 'V30' : 'V29'; + const expectedSpecFamilyMode = pointer === 'V29' ? 'promoted' : 'draft'; - assert.equal(protocol.ACTIVE_CANON_VERSION, 'V28'); - assert.equal(protocol.DRAFT_TARGET_VERSION, 'V29'); + assert.equal(protocol.ACTIVE_CANON_VERSION, expectedActiveCanon); + assert.equal(protocol.DRAFT_TARGET_VERSION, expectedDraftTarget); assert.equal(typeof protocol.buildV21SpecFamilyReport, 'function'); assert.equal(typeof protocol.buildV21CanonicalInputReport, 'function'); assert.equal(typeof protocol.buildV21GeneratedArtifactContents, 'function'); @@ -55,13 +59,13 @@ test('@bitcode/protocol commercial formalization exports package-native canon he assert.equal(typeof protocol.PROVEN_GENERATOR_ID, 'string'); assert.equal(typeof protocol.defaultProvenOutputPath, 'function'); assert.equal(typeof protocol.generateCanonicalProvenMarkdown, 'function'); - assert.equal(protocol.defaultProvenOutputPath('V28'), 'BITCODE_SPEC_V28_PROVEN.md'); + assert.equal(protocol.defaultProvenOutputPath(expectedActiveCanon), `BITCODE_SPEC_${expectedActiveCanon}_PROVEN.md`); const specFamilyReport = protocol.buildV21SpecFamilyReport({ version: 'V29', - mode: 'draft', - currentTarget: 'V28', + mode: expectedSpecFamilyMode, + currentTarget: expectedActiveCanon, }); - const canonicalInputReport = protocol.buildV21CanonicalInputReport({ currentTarget: 'V28' }); + const canonicalInputReport = protocol.buildV21CanonicalInputReport({ currentTarget: expectedActiveCanon }); assert.equal(specFamilyReport.passed, true); assert.equal(canonicalInputReport.passed, true); }); From 0fa36c741e7b5af117624516d744b643e76d67e7 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 15:10:02 -0300 Subject: [PATCH 16/18] V29 Gate 10: Refresh proof after protocol test fix Refresh V29 promoted spec-family status and generated PROVEN appendix so the proof source includes the promoted protocol package boundary test update. --- BITCODE_SPEC_V29.md | 2 +- BITCODE_SPEC_V29_DELTA.md | 2 +- BITCODE_SPEC_V29_NOTES.md | 2 +- BITCODE_SPEC_V29_PARITY_MATRIX.md | 2 +- BITCODE_SPEC_V29_PROVEN.md | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index 573e137fe..c25aff2db 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 is the active Terminal transaction-depth canon and the V29 hand-authored plus generated canon are aligned - Current canonical/latest target: `V29` -- Canonical proof-source commit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` +- Canonical proof-source commit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index 0c72e6cc8..20ff236fa 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; this delta records the promoted V28-to-V29 Terminal transaction-depth and promotion-readiness closure set - Current canonical/latest target: `V29` -- Canonical proof-source commit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` +- Canonical proof-source commit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index a43c97a27..5c9fdebfa 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 notes record the accepted Terminal-depth, local/staging, and promotion-readiness evidence - Current canonical/latest target: `V29` -- Canonical proof-source commit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` +- Canonical proof-source commit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 2228ddbf8..62ab3dec1 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 parity truth, product-gate audit, generated proof, and promotion automation are aligned - Current canonical/latest target: `V29` -- Canonical proof-source commit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` +- Canonical proof-source commit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_PROVEN.md b/BITCODE_SPEC_V29_PROVEN.md index eb110d213..be855514d 100644 --- a/BITCODE_SPEC_V29_PROVEN.md +++ b/BITCODE_SPEC_V29_PROVEN.md @@ -1,11 +1,11 @@ # Bitcode Spec V29 Proven - canonicalVersion: `V29` -- canonicalCommit: `f7efcd0107a02200bc756ff9e7d236c74395a9f6` -- canonicalCommitRecordedAt: `2026-05-21T15:02:25-03:00` +- canonicalCommit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` +- canonicalCommitRecordedAt: `2026-05-21T15:09:08-03:00` - worktreeState: `clean` - generatorId: `bitcode.proven-generator.v1` -- generatedAt: `2026-05-21T15:02:25-03:00` +- generatedAt: `2026-05-21T15:09:08-03:00` - outputPath: `BITCODE_SPEC_V29_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` From 3cfa3e71ef553ecb25221ed7116e29eccbc4df24 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 15:25:23 -0300 Subject: [PATCH 17/18] V29 Gate 10: Align promoted draft notes checks Update the notes-only draft checker to use repo-relative V30 posture instead of stale absolute V27/V26 requirements. Refresh the V30 notes scaffold for active V29 / draft V30 and align the protocol demonstration canonical input artifact expectation with the promoted checker. --- BITCODE_SPEC_V30_NOTES.md | 41 ++++++++++--------- .../test/v21-specifying.test.js | 4 +- scripts/check-bitcode-draft-notes.mjs | 12 +++--- 3 files changed, 29 insertions(+), 28 deletions(-) diff --git a/BITCODE_SPEC_V30_NOTES.md b/BITCODE_SPEC_V30_NOTES.md index 187c88970..b4137a678 100644 --- a/BITCODE_SPEC_V30_NOTES.md +++ b/BITCODE_SPEC_V30_NOTES.md @@ -3,32 +3,38 @@ ## Status - Version: `V30` -- V30 state: future notes scaffold only -- Current canonical/latest target: `V27` -- Current active draft target: `V28` -- Prior canonical anchor: `BITCODE_SPEC_V27.md` -- Prior generated proof appendix: `BITCODE_SPEC_V27_PROVEN.md` +- V30 state: notes-only draft opening +- Current canonical/latest target: `V29` +- 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: none for V30 yet -- Source parity state: not opened; V30 source parity begins only after V30 draft opening +- Source parity state: notes-only draft opening; V30 source parity begins only after V30 first-gate work - 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 V28 can remain focused on commercial Protocol/Terminal MVP QA, bugfixing, audit, and hardening. +It preserves roadmap intent so V30 first-gate work can open from promoted V29 without rediscovering deferred Protocol/BTD hardening pressure. -## Notes companion rule +## Notes-only draft rule -This file is planning memory only. -Requirements become binding only when V30 is explicitly opened as the draft-target SPEC family. +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. ## Concise current-system reading -V27 is active canon. -V28 is current draft target and owns commercial Protocol implementation, Terminal MVP QA, MCP API/ChatGPT App MVP, BTD/testnet/ledgerization, and demonstration-to-commercial boundary cleanup. -V29 is expected to deepen Terminal workflows. +V29 is active canon. V30 is expected to harden Protocol/BTD surfaces after V28/V29 reveal implementation pressure. Exchange is not V30 work. -## Intended V30 focus +## Deferred from V29 + +V29 canonically closes deeper Terminal transaction depth, local/staging promotion readiness, and promotion automation. +V30 inherits deferred hardening pressure around Bitcoin fee boundaries, GitHub delivery evidence, compute/runtime capability truth, storage/readback posture, and build/process proof surfaces. + +## Candidate V30 workstreams V30 owns Protocol/BTD hardening: @@ -40,13 +46,8 @@ 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. -## Boundaries +## 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. V30 must not absorb V31 Auxillaries expansion, V32 provation/testing depth, V33 interface depth, V34 deployment depth, or V35 telemetry/documenting depth except for narrow Protocol/BTD-owned hooks. V30 must not absorb Exchange or website Conversations; those return beyond V35. - -## Return To V28 - -Do not start V30 implementation during V28. -Use this scaffold only to keep V28 focused on commercial Protocol/Terminal MVP QA and hardening. diff --git a/protocol-demonstration/test/v21-specifying.test.js b/protocol-demonstration/test/v21-specifying.test.js index 61c1a8876..24648e315 100644 --- a/protocol-demonstration/test/v21-specifying.test.js +++ b/protocol-demonstration/test/v21-specifying.test.js @@ -20,8 +20,8 @@ function projectLabel(version) { function expectedActiveCanonicalInputArtifactCount(version) { const numeric = Number.parseInt(String(version || '').replace(/^V/u, ''), 10); if (!Number.isInteger(numeric)) return 3; - if (numeric === 27 || numeric === 28) return 0; - if (numeric >= 26) return 22; + if (numeric >= 27) return 0; + if (numeric === 26) return 22; if (numeric >= 22) return 3; if (numeric === 21) return 2; return 6; diff --git a/scripts/check-bitcode-draft-notes.mjs b/scripts/check-bitcode-draft-notes.mjs index 94a864536..fb7a02be8 100644 --- a/scripts/check-bitcode-draft-notes.mjs +++ b/scripts/check-bitcode-draft-notes.mjs @@ -20,7 +20,7 @@ function parseArgs(argv) { function printHelp() { process.stdout.write( [ - 'Usage: node scripts/check-bitcode-draft-notes.mjs --version V27 --current-target V26 [options]', + 'Usage: node scripts/check-bitcode-draft-notes.mjs --version V30 --current-target V29 [options]', '', 'Options:', ' --version Draft target version to validate.', @@ -55,9 +55,9 @@ function main() { const requiredPhrases = [ `Spec ${version} Notes`, '## Status', - `Canonical pointer: \`${path.join(repoRoot, 'BITCODE_SPEC.txt')}\` -> \`${currentTarget}\``, - `Active canonical anchor: \`${path.join(repoRoot, `${activeSpecPrefix}_${currentTarget}.md`)}\``, - `Active generated proof appendix: \`${path.join(repoRoot, `${activeSpecPrefix}_${currentTarget}_PROVEN.md`)}\``, + `Canonical pointer: \`BITCODE_SPEC.txt\` -> \`${currentTarget}\``, + `Active canonical anchor: \`${activeSpecPrefix}_${currentTarget}.md\``, + `Active generated proof appendix: \`${activeSpecPrefix}_${currentTarget}_PROVEN.md\``, `${version} state: notes-only draft opening`, '## Notes-only draft rule', `## Deferred from ${currentTarget}`, @@ -67,8 +67,8 @@ function main() { 'compute', 'storage', 'build/process', - '## Candidate V27 workstreams', - '## Non-goals during V26 closure' + `## Candidate ${version} workstreams`, + `## Non-goals during ${version} opening` ]; for (const phrase of requiredPhrases) { From 416ccc5158f56852c0c9e8d366f94f1232ee682a Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 21 May 2026 15:30:04 -0300 Subject: [PATCH 18/18] V29 Gate 10: Refresh promoted proof after notes repair Regenerate the V29 promoted proof appendix and proof-source status lines after fixing promoted V30 notes validation and protocol demonstration expectations. --- BITCODE_SPEC_V29.md | 2 +- BITCODE_SPEC_V29_DELTA.md | 2 +- BITCODE_SPEC_V29_NOTES.md | 2 +- BITCODE_SPEC_V29_PARITY_MATRIX.md | 2 +- BITCODE_SPEC_V29_PROVEN.md | 6 +++--- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/BITCODE_SPEC_V29.md b/BITCODE_SPEC_V29.md index c25aff2db..2ba7f110d 100644 --- a/BITCODE_SPEC_V29.md +++ b/BITCODE_SPEC_V29.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 is the active Terminal transaction-depth canon and the V29 hand-authored plus generated canon are aligned - Current canonical/latest target: `V29` -- Canonical proof-source commit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` +- Canonical proof-source commit: `3cfa3e71ef553ecb25221ed7116e29eccbc4df24` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_DELTA.md b/BITCODE_SPEC_V29_DELTA.md index 20ff236fa..80bc57275 100644 --- a/BITCODE_SPEC_V29_DELTA.md +++ b/BITCODE_SPEC_V29_DELTA.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; this delta records the promoted V28-to-V29 Terminal transaction-depth and promotion-readiness closure set - Current canonical/latest target: `V29` -- Canonical proof-source commit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` +- Canonical proof-source commit: `3cfa3e71ef553ecb25221ed7116e29eccbc4df24` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_NOTES.md b/BITCODE_SPEC_V29_NOTES.md index 5c9fdebfa..76e37593d 100644 --- a/BITCODE_SPEC_V29_NOTES.md +++ b/BITCODE_SPEC_V29_NOTES.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 notes record the accepted Terminal-depth, local/staging, and promotion-readiness evidence - Current canonical/latest target: `V29` -- Canonical proof-source commit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` +- Canonical proof-source commit: `3cfa3e71ef553ecb25221ed7116e29eccbc4df24` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_PARITY_MATRIX.md b/BITCODE_SPEC_V29_PARITY_MATRIX.md index 62ab3dec1..acd697877 100644 --- a/BITCODE_SPEC_V29_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V29_PARITY_MATRIX.md @@ -5,7 +5,7 @@ - Version: `V29` - V29 state: canonical promotion complete; V29 parity truth, product-gate audit, generated proof, and promotion automation are aligned - Current canonical/latest target: `V29` -- Canonical proof-source commit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` +- Canonical proof-source commit: `3cfa3e71ef553ecb25221ed7116e29eccbc4df24` - Prior canonical anchor: `BITCODE_SPEC_V28.md` - Prior generated proof appendix: `BITCODE_SPEC_V28_PROVEN.md` - Generated structured artifact inventory: active canonical `.bitcode/v29-spec-family-report.json`, `.bitcode/v29-canonical-input-report.json`, `.bitcode/v29-canon-posture-drift-report.json`, V29 gate-quality and promotion workflow evidence, and `BITCODE_SPEC_V29_PROVEN.md` as the generated proof appendix for V29 promotion diff --git a/BITCODE_SPEC_V29_PROVEN.md b/BITCODE_SPEC_V29_PROVEN.md index be855514d..196354dc9 100644 --- a/BITCODE_SPEC_V29_PROVEN.md +++ b/BITCODE_SPEC_V29_PROVEN.md @@ -1,11 +1,11 @@ # Bitcode Spec V29 Proven - canonicalVersion: `V29` -- canonicalCommit: `b13d6f75488c3a9eeb8bb80c7fba20cb8f4b96e9` -- canonicalCommitRecordedAt: `2026-05-21T15:09:08-03:00` +- canonicalCommit: `3cfa3e71ef553ecb25221ed7116e29eccbc4df24` +- canonicalCommitRecordedAt: `2026-05-21T15:25:23-03:00` - worktreeState: `clean` - generatorId: `bitcode.proven-generator.v1` -- generatedAt: `2026-05-21T15:09:08-03:00` +- generatedAt: `2026-05-21T15:25:23-03:00` - outputPath: `BITCODE_SPEC_V29_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`