From 9b3f9682d5558f6091e8c6215e47e45e843b4f5e Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Thu, 11 Jun 2026 16:45:00 -0300 Subject: [PATCH] V47 Gate 7: Prove E2E IP selling and buying in the browser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Record Gate 7 E2E IP selling/buying law across BITCODE_SPEC_V47, DELTA, NOTES, PARITY, and the roadmap, and advance roadmap posture to working Gate 7 with Gate 6 recorded as latest closed. Add commercial-mvp.ip-exchange.spec.ts: a deterministic mock-mode Playwright proof that sells IP on /deposit (source connection gates synthesis, source-safe measurement review precedes approval, admission readback synchronizes to /packs, execution rows journal through a stateful execution-history mock), buys synthesized IP on /read (five-step session, fit measurement review with final BTD scalar and BTC-testnet quote basis before payment, ordered observation/finality/BTD-rights/PR-delivery readback, rights and delivery receipt roots in the expandable proof detail), and audits /packs state readback with the fail-closed repair surface — all behind a browser error trap. Expose test:e2e:ip-exchange in uapi. Add the V47E2eIpSellingBuyingTests protocol object, generator, Gate 7 checker (browser tests opt-in via --run-browser-tests), protocol tests, package exports, package.json scripts, and gate/canon workflow wiring; generate .bitcode/v47-e2e-ip-selling-buying-tests.json and refresh the Gate 2-6 artifacts against the advanced spec family. Validated with: - pnpm --dir uapi run test:e2e:ip-exchange (3 browser proofs pass) - pnpm --filter @bitcode/protocol test - node scripts/check-v47-gate1-scope-measurement-launch-freeze.mjs --skip-branch-check - pnpm run check:v47-gate2 through check:v47-gate7 - node scripts/check-bitcode-spec-family.mjs --version V46 --mode promoted --current-target V46 - node scripts/check-bitcode-spec-family.mjs --version V47 --mode draft --current-target V46 - node scripts/check-bitcode-canonical-inputs.mjs --current-target V46 - node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V46 --draft-target V47 - node scripts/run-bitcode-spec-quality.mjs --mode basic - node scripts/check-import-casing.mjs - uapi eslint and tsc --noEmit on the new spec - git diff --check Co-Authored-By: Claude Fable 5 --- .../v47-depositor-website-completion.json | 22 +- .bitcode/v47-e2e-ip-selling-buying-tests.json | 309 +++++++++++++++ .../v47-feature-excess-alignment-audit.json | 22 +- ...acks-auxillaries-commercial-dashboard.json | 22 +- .bitcode/v47-reader-website-completion.json | 22 +- .../v47-seller-buyer-state-machine-law.json | 22 +- .github/workflows/bitcode-canon-quality.yml | 3 + .github/workflows/bitcode-gate-quality.yml | 3 + BITCODE_SPEC_V47.md | 36 +- BITCODE_SPEC_V47_DELTA.md | 14 + BITCODE_SPEC_V47_NOTES.md | 9 +- BITCODE_SPEC_V47_PARITY_MATRIX.md | 14 +- SPECIFICATIONS_ROADMAP.md | 8 +- package.json | 3 + .../v47-e2e-ip-selling-buying-tests.js | 332 ++++++++++++++++ packages/protocol/src/index.d.ts | 12 + packages/protocol/src/index.js | 14 + .../v47-e2e-ip-selling-buying-tests.test.js | 52 +++ ...-v47-gate7-e2e-ip-selling-buying-tests.mjs | 187 +++++++++ ...nerate-v47-e2e-ip-selling-buying-tests.mjs | 30 ++ uapi/package.json | 1 + .../e2e/commercial-mvp.ip-exchange.spec.ts | 372 ++++++++++++++++++ 22 files changed, 1444 insertions(+), 65 deletions(-) create mode 100644 .bitcode/v47-e2e-ip-selling-buying-tests.json create mode 100644 packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js create mode 100644 packages/protocol/test/v47-e2e-ip-selling-buying-tests.test.js create mode 100644 scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs create mode 100644 scripts/generate-v47-e2e-ip-selling-buying-tests.mjs create mode 100644 uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts diff --git a/.bitcode/v47-depositor-website-completion.json b/.bitcode/v47-depositor-website-completion.json index cdbe8e787..dad9afa6a 100644 --- a/.bitcode/v47-depositor-website-completion.json +++ b/.bitcode/v47-depositor-website-completion.json @@ -363,11 +363,11 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:820a850b09546da1a1a1c447", - "spec": "BITCODE_SPEC_V47.md:568da1f91d4c1596fcc14d46", - "delta": "BITCODE_SPEC_V47_DELTA.md:da744232536c2d9261dddb13", - "notes": "BITCODE_SPEC_V47_NOTES.md:a8227a21ad1f6718a1ef9d72", - "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:5a67b61fd85ab0807bd9b3a5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:39a17e5e9e50ee030c449c04", + "spec": "BITCODE_SPEC_V47.md:c265b2287e1b56314f6db743", + "delta": "BITCODE_SPEC_V47_DELTA.md:bc0eed77ab82b10b46b1c2e4", + "notes": "BITCODE_SPEC_V47_NOTES.md:4deb3241858335335752844a", + "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:94c0ba43a1835d1d96d7153d", + "roadmap": "SPECIFICATIONS_ROADMAP.md:7b9addff32488c11634c867a", "depositRouteModel": "uapi/app/deposit/deposit-route-model.ts:6485e388dd745c79907f992c", "depositClient": "uapi/app/deposit/DepositPageClient.tsx:f01b600f9ef64cd3739460ef", "depositPage": "uapi/app/deposit/page.tsx:6bab6a9debab3f4350d0ddca", @@ -379,17 +379,17 @@ "admissionModel": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-admission.ts:4d2b0c5e6e10c2b14a75a8c8", "earningModel": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts:e0ec2d83cfaf3bfaaa126387", "authorityModel": "packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts:ed6fa07bc3f69caaca598249", - "packageJson": "package.json:5677aab11c6fbc9b132b817c", - "protocolIndex": "packages/protocol/src/index.js:25aeb8da056d865bc241aabd", - "protocolTypes": "packages/protocol/src/index.d.ts:33006f10baf9db7d513c9663", + "packageJson": "package.json:402b04d17c34a837a9c24e8f", + "protocolIndex": "packages/protocol/src/index.js:f158a931354fcb1f9ab0ee8c", + "protocolTypes": "packages/protocol/src/index.d.ts:7d9745dc5077275dd7dcd933", "protocolSource": "packages/protocol/src/canonical/v47-depositor-website-completion.js:13be769e5cbeb901de02bb8c", "protocolTest": "packages/protocol/test/v47-depositor-website-completion.test.js:227e3b47a4fbbed7cea7e642", "generator": "scripts/generate-v47-depositor-website-completion.mjs:d14545eb606901fdc4df3b08", "checker": "scripts/check-v47-gate4-depositor-website-completion.mjs:b918d7afafcad45ec6c22360", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:b9ec667950be5f6ef7d42b45", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:ef7c0f5b5cb7797a979af4aa" + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:7057bbb31ff0017a3be69601", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:1678854d45f8ec81a827625c" }, - "artifactRoot": "v47-depositor-website-completion:0083582f53fe149dc68f21a0", + "artifactRoot": "v47-depositor-website-completion:0bbaf879f1b404c524f6b6ea", "coverage": { "requiredPredicateCount": 21, "passedPredicateCount": 21, diff --git a/.bitcode/v47-e2e-ip-selling-buying-tests.json b/.bitcode/v47-e2e-ip-selling-buying-tests.json new file mode 100644 index 000000000..e9b76b940 --- /dev/null +++ b/.bitcode/v47-e2e-ip-selling-buying-tests.json @@ -0,0 +1,309 @@ +{ + "artifactId": "v47-e2e-ip-selling-buying-tests", + "schemaId": "bitcode.v47.e2eIpSellingBuyingTests.v1", + "version": "V47", + "currentTarget": "V46", + "artifactPath": ".bitcode/v47-e2e-ip-selling-buying-tests.json", + "sourceSafetyVerdict": "source-safe-e2e-ip-exchange-browser-proof", + "scenarioIds": [ + "ip-seller-deposits-assetpack", + "ip-buyer-measures-quotes-settles", + "packs-dashboard-settlement-rights-delivery-repair-readback" + ], + "routeIds": [ + "/deposit", + "/read", + "/packs" + ], + "verificationIds": [ + "source-connection-before-synthesis", + "source-safe-measurement-review-before-approval", + "journaled-execution-rows", + "fit-measurement-review-before-payment", + "deterministic-btc-testnet-quote-basis", + "settlement-observation-finality-order", + "btd-rights-receipt-readback", + "repository-pr-delivery-readback", + "packs-state-readback", + "fail-closed-repair-surface", + "browser-error-trap-clean" + ], + "forbiddenPayloadIds": [ + "protected_source_payload", + "raw_source_text", + "unpaid_assetpack_source", + "raw_protected_prompt", + "interpolated_prompt", + "raw_provider_response", + "wallet_private_material", + "settlement_private_payload", + "mainnet_value_bearing_payment_secret" + ], + "completionRows": [ + { + "rowId": "seller-flow-browser-proof", + "owner": "uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts", + "route": "/deposit", + "contract": "A browser test deposits IP the Bitcode way: source connection gates option synthesis, source-safe measurements render before approval, admission readback synchronizes to /packs, and the flow journals execution rows.", + "requiredFields": [ + "Synthesize options", + "Approve for Depository", + "/packs?type=depository-assetpack" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawSourceTextVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetEnabled": false, + "forbiddenPayloadIds": [ + "protected_source_payload", + "raw_source_text", + "unpaid_assetpack_source", + "raw_protected_prompt", + "interpolated_prompt", + "raw_provider_response", + "wallet_private_material", + "settlement_private_payload", + "mainnet_value_bearing_payment_secret" + ], + "rowRoot": "v47-e2e-ip-exchange-row:af3b9e5b68acbbf7dea11c62" + }, + { + "rowId": "buyer-flow-browser-proof", + "owner": "uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts", + "route": "/read", + "contract": "A browser test buys synthesized IP the Bitcode way: the five-step session renders the fit measurement review, final BTD scalar, and deterministic BTC-testnet quote basis before payment, then reads back payment observation, finality, BTD rights receipt, and repository PR delivery in order.", + "requiredFields": [ + "Fit measurement review", + "Final BTD scalar", + "BTD rights receipt root", + "Delivery receipt root" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawSourceTextVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetEnabled": false, + "forbiddenPayloadIds": [ + "protected_source_payload", + "raw_source_text", + "unpaid_assetpack_source", + "raw_protected_prompt", + "interpolated_prompt", + "raw_provider_response", + "wallet_private_material", + "settlement_private_payload", + "mainnet_value_bearing_payment_secret" + ], + "rowRoot": "v47-e2e-ip-exchange-row:707e1fe6acffbc0a60986d1d" + }, + { + "rowId": "packs-dashboard-browser-proof", + "owner": "uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts", + "route": "/packs", + "contract": "A browser test audits the exchange on /packs: master-detail state readback tracks settlement, BTD rights, compensation, and delivery, and repair-required activity exposes the fail-closed repair surface with commodity-state blockers.", + "requiredFields": [ + "State readback", + "Repair surface", + "btd-rights-transferred" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawSourceTextVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetEnabled": false, + "forbiddenPayloadIds": [ + "protected_source_payload", + "raw_source_text", + "unpaid_assetpack_source", + "raw_protected_prompt", + "interpolated_prompt", + "raw_provider_response", + "wallet_private_material", + "settlement_private_payload", + "mainnet_value_bearing_payment_secret" + ], + "rowRoot": "v47-e2e-ip-exchange-row:5535a1bb2d35955dca3ae97d" + }, + { + "rowId": "deterministic-mock-harness", + "owner": "uapi/tests/e2e/commercial-mvp.helpers.ts", + "route": "/deposit", + "contract": "The browser proof runs in deterministic mock mode with stateful execution-history journaling, mocked VCS/auxillary surfaces, and a browser error trap that fails the proof on framework overlays or console errors.", + "requiredFields": [ + "installCommercialMvpApiMocks", + "installCommercialBrowserErrorTrap", + "installExecutionHistoryMock" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawSourceTextVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetEnabled": false, + "forbiddenPayloadIds": [ + "protected_source_payload", + "raw_source_text", + "unpaid_assetpack_source", + "raw_protected_prompt", + "interpolated_prompt", + "raw_provider_response", + "wallet_private_material", + "settlement_private_payload", + "mainnet_value_bearing_payment_secret" + ], + "rowRoot": "v47-e2e-ip-exchange-row:a195a7a0dfa18c8363e03052" + } + ], + "predicateResults": [ + { + "id": "active-canon-pointer-remains-v46", + "sourcePath": "BITCODE_SPEC.txt", + "passed": true + }, + { + "id": "spec-records-gate7-e2e-ip-exchange-tests", + "sourcePath": "BITCODE_SPEC_V47.md", + "passed": true + }, + { + "id": "delta-records-gate7-e2e-ip-exchange-tests", + "sourcePath": "BITCODE_SPEC_V47_DELTA.md", + "passed": true + }, + { + "id": "notes-record-gate7-e2e-ip-exchange-tests", + "sourcePath": "BITCODE_SPEC_V47_NOTES.md", + "passed": true + }, + { + "id": "parity-records-gate7-e2e-ip-exchange-tests", + "sourcePath": "BITCODE_SPEC_V47_PARITY_MATRIX.md", + "passed": true + }, + { + "id": "roadmap-records-gate7-closure", + "sourcePath": "SPECIFICATIONS_ROADMAP.md", + "passed": true + }, + { + "id": "spec-proves-ip-seller-deposit-flow", + "sourcePath": "uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts", + "passed": true + }, + { + "id": "spec-proves-ip-buyer-read-flow", + "sourcePath": "uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts", + "passed": true + }, + { + "id": "spec-proves-packs-dashboard-readback", + "sourcePath": "uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts", + "passed": true + }, + { + "id": "spec-runs-deterministic-source-safe-mock-mode", + "sourcePath": "uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts", + "passed": true + }, + { + "id": "e2e-harness-binds-helpers-and-config", + "sourcePath": "uapi/tests/e2e/commercial-mvp.helpers.ts", + "passed": true + }, + { + "id": "uapi-package-exposes-ip-exchange-script", + "sourcePath": "uapi/package.json", + "passed": true + }, + { + "id": "route-clients-carry-proven-surfaces", + "sourcePath": "uapi/app/deposit/DepositPageClient.tsx", + "passed": true + }, + { + "id": "package-exports-gate7", + "sourcePath": "packages/protocol/src/index.js", + "passed": true + }, + { + "id": "package-json-exposes-gate7", + "sourcePath": "package.json", + "passed": true + }, + { + "id": "workflows-run-gate7-check", + "sourcePath": ".github/workflows/bitcode-gate-quality.yml", + "passed": true + }, + { + "id": "generator-checker-test-exist", + "sourcePath": "scripts/generate-v47-e2e-ip-selling-buying-tests.mjs", + "passed": true + } + ], + "sourceRoots": { + "activePointer": "BITCODE_SPEC.txt:820a850b09546da1a1a1c447", + "spec": "BITCODE_SPEC_V47.md:c265b2287e1b56314f6db743", + "delta": "BITCODE_SPEC_V47_DELTA.md:bc0eed77ab82b10b46b1c2e4", + "notes": "BITCODE_SPEC_V47_NOTES.md:4deb3241858335335752844a", + "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:94c0ba43a1835d1d96d7153d", + "roadmap": "SPECIFICATIONS_ROADMAP.md:7b9addff32488c11634c867a", + "ipExchangeSpec": "uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts:86af66133e5ede25935ffd9d", + "e2eHelpers": "uapi/tests/e2e/commercial-mvp.helpers.ts:5bb8c28f36170b877e8a467a", + "playwrightConfig": "uapi/playwright.config.ts:0aea6b01fa17b8c0614b2074", + "uapiPackageJson": "uapi/package.json:dc9773834cf101bb272eb07c", + "depositClient": "uapi/app/deposit/DepositPageClient.tsx:f01b600f9ef64cd3739460ef", + "readClient": "uapi/app/read/ReadPageClient.tsx:71e7c03e77104e9ab995dafb", + "packsClient": "uapi/app/packs/PacksPageClient.tsx:6314e03df5bf7c598e5b7802", + "packageJson": "package.json:402b04d17c34a837a9c24e8f", + "protocolIndex": "packages/protocol/src/index.js:f158a931354fcb1f9ab0ee8c", + "protocolTypes": "packages/protocol/src/index.d.ts:7d9745dc5077275dd7dcd933", + "protocolSource": "packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js:74a3ed6605317d28aa87f9a0", + "protocolTest": "packages/protocol/test/v47-e2e-ip-selling-buying-tests.test.js:4faaa57ae3a59253e6f1cb7e", + "generator": "scripts/generate-v47-e2e-ip-selling-buying-tests.mjs:c0c83f7b37d8db3db755d1c5", + "checker": "scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs:a4cda45b853fd314679baab4", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:7057bbb31ff0017a3be69601", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:1678854d45f8ec81a827625c" + }, + "artifactRoot": "v47-e2e-ip-selling-buying-tests:fc0dd10f419bcc6f5fc206f8", + "coverage": { + "requiredPredicateCount": 17, + "passedPredicateCount": 17, + "failedPredicateIds": [], + "sellerFlowProofComplete": true, + "buyerFlowProofComplete": true, + "packsDashboardProofComplete": true, + "deterministicMockHarnessComplete": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawSourceTextVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetEnabled": false + }, + "passed": true +} diff --git a/.bitcode/v47-feature-excess-alignment-audit.json b/.bitcode/v47-feature-excess-alignment-audit.json index ae03797a3..53a4ceb20 100644 --- a/.bitcode/v47-feature-excess-alignment-audit.json +++ b/.bitcode/v47-feature-excess-alignment-audit.json @@ -5,7 +5,7 @@ "currentTarget": "V46", "sourceSafetyVerdict": "source-safe-launch-scope-metadata", "generatedAt": "deterministic", - "artifactRoot": "v47-feature-excess-alignment-audit:999f95cb36715ba4f8b25e9d", + "artifactRoot": "v47-feature-excess-alignment-audit:4e2b861b4f0479d0106d1df2", "passed": true, "launchRouteIds": [ "/deposit", @@ -166,11 +166,11 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:820a850b09546da1a1a1c447", - "spec": "BITCODE_SPEC_V47.md:568da1f91d4c1596fcc14d46", - "delta": "BITCODE_SPEC_V47_DELTA.md:da744232536c2d9261dddb13", - "notes": "BITCODE_SPEC_V47_NOTES.md:a8227a21ad1f6718a1ef9d72", - "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:5a67b61fd85ab0807bd9b3a5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:39a17e5e9e50ee030c449c04", + "spec": "BITCODE_SPEC_V47.md:c265b2287e1b56314f6db743", + "delta": "BITCODE_SPEC_V47_DELTA.md:bc0eed77ab82b10b46b1c2e4", + "notes": "BITCODE_SPEC_V47_NOTES.md:4deb3241858335335752844a", + "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:94c0ba43a1835d1d96d7153d", + "roadmap": "SPECIFICATIONS_ROADMAP.md:7b9addff32488c11634c867a", "publicCopy": "uapi/components/base/bitcode/layout/bitcode-public-copy.ts:9b39322f872b899e1c752701", "nav": "uapi/components/base/bitcode/layout/nav.tsx:2b2eaaf65982969883af8d1e", "features": "uapi/config/features.ts:6ff2da113ab17dfc468d7461", @@ -186,15 +186,15 @@ "exchangePage": "uapi/app/exchange/page.tsx:be7a744d1f9c9252d1b6eba9", "exchangeReadme": "uapi/app/exchange/README.md:3a0b7052de6be76fcda2b094", "btdDetailPage": "uapi/app/btd/[assetPackId]/page.tsx:b94efe66179c2a2a27bde659", - "packageJson": "package.json:5677aab11c6fbc9b132b817c", - "protocolIndex": "packages/protocol/src/index.js:25aeb8da056d865bc241aabd", - "protocolTypes": "packages/protocol/src/index.d.ts:33006f10baf9db7d513c9663", + "packageJson": "package.json:402b04d17c34a837a9c24e8f", + "protocolIndex": "packages/protocol/src/index.js:f158a931354fcb1f9ab0ee8c", + "protocolTypes": "packages/protocol/src/index.d.ts:7d9745dc5077275dd7dcd933", "protocolSource": "packages/protocol/src/canonical/v47-feature-excess-alignment-audit.js:b816208bf2ff100ad0ed6542", "protocolTest": "packages/protocol/test/v47-feature-excess-alignment-audit.test.js:d4eb230b98bcbc3ee18af459", "generator": "scripts/generate-v47-feature-excess-alignment-audit.mjs:1132b37cd29dddc216db998d", "checker": "scripts/check-v47-gate2-feature-excess-alignment-audit.mjs:007c139e5c0a60e0d621e7f4", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:b9ec667950be5f6ef7d42b45", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:ef7c0f5b5cb7797a979af4aa" + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:7057bbb31ff0017a3be69601", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:1678854d45f8ec81a827625c" }, "predicateResults": [ { diff --git a/.bitcode/v47-packs-auxillaries-commercial-dashboard.json b/.bitcode/v47-packs-auxillaries-commercial-dashboard.json index 332653826..a828d770a 100644 --- a/.bitcode/v47-packs-auxillaries-commercial-dashboard.json +++ b/.bitcode/v47-packs-auxillaries-commercial-dashboard.json @@ -348,11 +348,11 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:820a850b09546da1a1a1c447", - "spec": "BITCODE_SPEC_V47.md:568da1f91d4c1596fcc14d46", - "delta": "BITCODE_SPEC_V47_DELTA.md:da744232536c2d9261dddb13", - "notes": "BITCODE_SPEC_V47_NOTES.md:a8227a21ad1f6718a1ef9d72", - "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:5a67b61fd85ab0807bd9b3a5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:39a17e5e9e50ee030c449c04", + "spec": "BITCODE_SPEC_V47.md:c265b2287e1b56314f6db743", + "delta": "BITCODE_SPEC_V47_DELTA.md:bc0eed77ab82b10b46b1c2e4", + "notes": "BITCODE_SPEC_V47_NOTES.md:4deb3241858335335752844a", + "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:94c0ba43a1835d1d96d7153d", + "roadmap": "SPECIFICATIONS_ROADMAP.md:7b9addff32488c11634c867a", "packsClient": "uapi/app/packs/PacksPageClient.tsx:6314e03df5bf7c598e5b7802", "packsPage": "uapi/app/packs/page.tsx:1b3d7a1cc00500a13042e8dd", "packActivityModel": "uapi/components/base/bitcode/activity/pack-activity-model.ts:5505d016bb0af42b461d98bb", @@ -368,17 +368,17 @@ "packsClientTest": "uapi/tests/packsPageClient.test.tsx:65fdbfca8be6f0b11ed59576", "auxillariesWalletPaneTest": "uapi/tests/auxillariesWalletPane.test.tsx:6eb2466152a6eede16e95863", "auxillariesWorkspaceTest": "uapi/tests/auxillariesWorkspacePanels.test.tsx:8feac0b9ea0b109749402d65", - "packageJson": "package.json:5677aab11c6fbc9b132b817c", - "protocolIndex": "packages/protocol/src/index.js:25aeb8da056d865bc241aabd", - "protocolTypes": "packages/protocol/src/index.d.ts:33006f10baf9db7d513c9663", + "packageJson": "package.json:402b04d17c34a837a9c24e8f", + "protocolIndex": "packages/protocol/src/index.js:f158a931354fcb1f9ab0ee8c", + "protocolTypes": "packages/protocol/src/index.d.ts:7d9745dc5077275dd7dcd933", "protocolSource": "packages/protocol/src/canonical/v47-packs-auxillaries-commercial-dashboard.js:f163a375879747b16954010d", "protocolTest": "packages/protocol/test/v47-packs-auxillaries-commercial-dashboard.test.js:51c1c6c89b1002dc637161dc", "generator": "scripts/generate-v47-packs-auxillaries-commercial-dashboard.mjs:c743ce9b2e298da9add2e2cb", "checker": "scripts/check-v47-gate6-packs-auxillaries-commercial-dashboard.mjs:84e5efc2b954e1295bcdf3d8", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:b9ec667950be5f6ef7d42b45", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:ef7c0f5b5cb7797a979af4aa" + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:7057bbb31ff0017a3be69601", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:1678854d45f8ec81a827625c" }, - "artifactRoot": "v47-packs-auxillaries-commercial-dashboard:b5c69be5c51986eb9100546a", + "artifactRoot": "v47-packs-auxillaries-commercial-dashboard:0b4fc663a324dd23be713014", "coverage": { "requiredPredicateCount": 19, "passedPredicateCount": 19, diff --git a/.bitcode/v47-reader-website-completion.json b/.bitcode/v47-reader-website-completion.json index edb92ac32..413e0f89e 100644 --- a/.bitcode/v47-reader-website-completion.json +++ b/.bitcode/v47-reader-website-completion.json @@ -364,11 +364,11 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:820a850b09546da1a1a1c447", - "spec": "BITCODE_SPEC_V47.md:568da1f91d4c1596fcc14d46", - "delta": "BITCODE_SPEC_V47_DELTA.md:da744232536c2d9261dddb13", - "notes": "BITCODE_SPEC_V47_NOTES.md:a8227a21ad1f6718a1ef9d72", - "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:5a67b61fd85ab0807bd9b3a5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:39a17e5e9e50ee030c449c04", + "spec": "BITCODE_SPEC_V47.md:c265b2287e1b56314f6db743", + "delta": "BITCODE_SPEC_V47_DELTA.md:bc0eed77ab82b10b46b1c2e4", + "notes": "BITCODE_SPEC_V47_NOTES.md:4deb3241858335335752844a", + "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:94c0ba43a1835d1d96d7153d", + "roadmap": "SPECIFICATIONS_ROADMAP.md:7b9addff32488c11634c867a", "readRouteModel": "uapi/app/read/read-route-model.ts:d033da8b41b8116c65cbcc7f", "readClient": "uapi/app/read/ReadPageClient.tsx:71e7c03e77104e9ab995dafb", "readPage": "uapi/app/read/page.tsx:37a723ed87feac05c0504249", @@ -380,17 +380,17 @@ "needReviewModel": "packages/pipelines/asset-pack/src/read-need-review-resynthesis.ts:347bd88040c9456420e03c0e", "fitsFindingModel": "packages/pipelines/asset-pack/src/read-fits-finding-runtime.ts:4e89eacdc2b73bd6bc70a085", "authorityModel": "packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts:ed6fa07bc3f69caaca598249", - "packageJson": "package.json:5677aab11c6fbc9b132b817c", - "protocolIndex": "packages/protocol/src/index.js:25aeb8da056d865bc241aabd", - "protocolTypes": "packages/protocol/src/index.d.ts:33006f10baf9db7d513c9663", + "packageJson": "package.json:402b04d17c34a837a9c24e8f", + "protocolIndex": "packages/protocol/src/index.js:f158a931354fcb1f9ab0ee8c", + "protocolTypes": "packages/protocol/src/index.d.ts:7d9745dc5077275dd7dcd933", "protocolSource": "packages/protocol/src/canonical/v47-reader-website-completion.js:143350da6d05f8cf4232376d", "protocolTest": "packages/protocol/test/v47-reader-website-completion.test.js:067393dc86876d820d83b6e3", "generator": "scripts/generate-v47-reader-website-completion.mjs:396705fdf05e3a58d2dd1c59", "checker": "scripts/check-v47-gate5-reader-website-completion.mjs:22d541c91d1666bc190dbbb4", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:b9ec667950be5f6ef7d42b45", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:ef7c0f5b5cb7797a979af4aa" + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:7057bbb31ff0017a3be69601", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:1678854d45f8ec81a827625c" }, - "artifactRoot": "v47-reader-website-completion:bbb40cd329646f494744afaf", + "artifactRoot": "v47-reader-website-completion:ed1a12b30bae50515126dc81", "coverage": { "requiredPredicateCount": 20, "passedPredicateCount": 20, diff --git a/.bitcode/v47-seller-buyer-state-machine-law.json b/.bitcode/v47-seller-buyer-state-machine-law.json index a08abe1d0..b7bbbcd5e 100644 --- a/.bitcode/v47-seller-buyer-state-machine-law.json +++ b/.bitcode/v47-seller-buyer-state-machine-law.json @@ -449,11 +449,11 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:820a850b09546da1a1a1c447", - "spec": "BITCODE_SPEC_V47.md:568da1f91d4c1596fcc14d46", - "delta": "BITCODE_SPEC_V47_DELTA.md:da744232536c2d9261dddb13", - "notes": "BITCODE_SPEC_V47_NOTES.md:a8227a21ad1f6718a1ef9d72", - "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:5a67b61fd85ab0807bd9b3a5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:39a17e5e9e50ee030c449c04", + "spec": "BITCODE_SPEC_V47.md:c265b2287e1b56314f6db743", + "delta": "BITCODE_SPEC_V47_DELTA.md:bc0eed77ab82b10b46b1c2e4", + "notes": "BITCODE_SPEC_V47_NOTES.md:4deb3241858335335752844a", + "parity": "BITCODE_SPEC_V47_PARITY_MATRIX.md:94c0ba43a1835d1d96d7153d", + "roadmap": "SPECIFICATIONS_ROADMAP.md:7b9addff32488c11634c867a", "depositRouteModel": "uapi/app/deposit/deposit-route-model.ts:6485e388dd745c79907f992c", "readRouteModel": "uapi/app/read/read-route-model.ts:d033da8b41b8116c65cbcc7f", "packActivityModel": "uapi/components/base/bitcode/activity/pack-activity-model.ts:5505d016bb0af42b461d98bb", @@ -461,17 +461,17 @@ "btdSettlement": "packages/btd/src/settlement.ts:871ea57357f464d8fbb0c6af", "btdSourceToShares": "packages/btd/src/source-to-shares.ts:6e2e84251b29ba2477766708", "btdSemanticVolume": "packages/btd/src/semantic-volume.ts:d428a420e7e1e2f2d958c5ea", - "packageJson": "package.json:5677aab11c6fbc9b132b817c", - "protocolIndex": "packages/protocol/src/index.js:25aeb8da056d865bc241aabd", - "protocolTypes": "packages/protocol/src/index.d.ts:33006f10baf9db7d513c9663", + "packageJson": "package.json:402b04d17c34a837a9c24e8f", + "protocolIndex": "packages/protocol/src/index.js:f158a931354fcb1f9ab0ee8c", + "protocolTypes": "packages/protocol/src/index.d.ts:7d9745dc5077275dd7dcd933", "protocolSource": "packages/protocol/src/canonical/v47-seller-buyer-state-machine-law.js:5693270ee09e104fe7b70ed5", "protocolTest": "packages/protocol/test/v47-seller-buyer-state-machine-law.test.js:de93bfe59fad2e7a9a2a3ce7", "generator": "scripts/generate-v47-seller-buyer-state-machine-law.mjs:256bbbf5ca089285f27fcad7", "checker": "scripts/check-v47-gate3-seller-buyer-state-machine-law.mjs:fa453f967b42423e4ee0bfc1", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:b9ec667950be5f6ef7d42b45", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:ef7c0f5b5cb7797a979af4aa" + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:7057bbb31ff0017a3be69601", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:1678854d45f8ec81a827625c" }, - "artifactRoot": "v47-seller-buyer-state-machine-law:40b4a06076fb12af1750e06d", + "artifactRoot": "v47-seller-buyer-state-machine-law:adbaf639034ef7b680ad66b8", "coverage": { "requiredPredicateCount": 18, "passedPredicateCount": 18, diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index 67d2038bd..889b692f4 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -469,6 +469,9 @@ jobs: if [ -f scripts/check-v47-gate6-packs-auxillaries-commercial-dashboard.mjs ]; then node scripts/check-v47-gate6-packs-auxillaries-commercial-dashboard.mjs --skip-branch-check --skip-package-tests --skip-uapi-tests fi + if [ -f scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs ]; then + node scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs --skip-branch-check --skip-package-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 diff --git a/.github/workflows/bitcode-gate-quality.yml b/.github/workflows/bitcode-gate-quality.yml index a325dd4f2..1436ffd80 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -598,6 +598,9 @@ jobs: if [ -f scripts/check-v47-gate6-packs-auxillaries-commercial-dashboard.mjs ]; then node scripts/check-v47-gate6-packs-auxillaries-commercial-dashboard.mjs --skip-branch-check --skip-package-tests --skip-uapi-tests fi + if [ -f scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs ]; then + node scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs --skip-branch-check --skip-package-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 diff --git a/BITCODE_SPEC_V47.md b/BITCODE_SPEC_V47.md index ff750c0f7..87fd8d49b 100644 --- a/BITCODE_SPEC_V47.md +++ b/BITCODE_SPEC_V47.md @@ -8,7 +8,7 @@ - Prior canonical anchor: `BITCODE_SPEC_V46.md` - Prior generated proof appendix: `BITCODE_SPEC_V46_PROVEN.md` - Generated structured artifact inventory: planned draft `.bitcode/v47-spec-family-report.json`, `.bitcode/v47-canonical-input-report.json`, `.bitcode/v47-feature-excess-alignment-audit.json`, `.bitcode/v47-seller-buyer-state-machine-law.json`, V47 launch-readiness artifacts, V47 commercial website testnet rehearsal artifacts, and `BITCODE_SPEC_V47_PROVEN.md` after promotion readiness -- Source parity state: V47 source parity is in progress; Gate 1 opens the draft family, testnet semantics, measurement law, launch freeze, and closure gates over promoted V46; Gate 2 adds source-safe feature-excess and launch-alignment audit coverage; Gate 3 adds seller/buyer state-machine law; Gate 4 completes the depositor website; Gate 5 completes the reader website; Gate 6 completes the packs and Auxillaries commercial dashboard +- Source parity state: V47 source parity is in progress; Gate 1 opens the draft family, testnet semantics, measurement law, launch freeze, and closure gates over promoted V46; Gate 2 adds source-safe feature-excess and launch-alignment audit coverage; Gate 3 adds seller/buyer state-machine law; Gate 4 completes the depositor website; Gate 5 completes the reader website; Gate 6 completes the packs and Auxillaries commercial dashboard; Gate 7 proves IP selling and buying in the browser - Notes companion: `BITCODE_SPEC_V47_NOTES.md` - Delta companion: `BITCODE_SPEC_V47_DELTA.md` - Parity companion: `BITCODE_SPEC_V47_PARITY_MATRIX.md` @@ -706,7 +706,10 @@ V47 gates: `.bitcode/v47-packs-auxillaries-commercial-dashboard.json`, the `buildV47PacksAuxillariesCommercialDashboard` package object, and `check:v47-gate6`. -7. E2E IP Selling And Buying Tests. +7. E2E IP Selling And Buying Tests. Gate 7 owns + `.bitcode/v47-e2e-ip-selling-buying-tests.json`, the + `buildV47E2eIpSellingBuyingTests` package object, and + `check:v47-gate7`. 8. Landing Page And Public Launch Messaging. 9. Staging-Testnet Deployment Rehearsal. 10. Promotion Readiness. @@ -777,6 +780,21 @@ classes, source-root digests, and predicate results without serializing protected source, unpaid AssetPack source, raw prompts, raw provider responses, wallet private material, or settlement private payloads. +V47 Gate 7 source-safe generated artifact: +`.bitcode/v47-e2e-ip-selling-buying-tests.json`. It records the browser-proof +scenarios (IP seller deposits an AssetPack on `/deposit`; IP buyer reviews +fit measurements, quote basis, settlement finality, BTD rights, and +repository delivery on `/read`; `/packs` reads back settlement, rights, +compensation, delivery, and the fail-closed repair surface), the +deterministic mock-mode harness bindings (stateful execution-history +journaling, VCS/auxillary mocks, browser error trap), the verification ids +covering source-connection-before-synthesis through +fail-closed-repair-surface, forbidden payload classes, source-root digests, +and predicate results without serializing protected source, unpaid AssetPack +source, raw prompts, raw provider responses, wallet private material, or +settlement private payloads. The browser proof runs on BTC-testnet semantics +only. + ### Appendix F. Subsystem totality and derivability matrix Required coverage phrases: repo supply and depositing; reading and measured @@ -914,3 +932,17 @@ organization team and treasury settings; `.bitcode/v47-packs-auxillaries-commercial-dashboard.json` is generated; `check:v47-gate6` validates the completion; and gate/canon workflows run the Gate 6 checker while V46 remains active canon. + +V47 Gate 7 is complete when browser-level tests prove both sides of Bitcode +in deterministic mock mode: depositing IP through source connection, option +synthesis, source-safe measurement review, and Depository admission on +`/deposit` with journaled execution rows; buying synthesized IP through the +five-step `/read` session with the fit measurement review, final BTD scalar, +and deterministic BTC-testnet quote basis rendered before payment and with +payment observation, finality, BTD rights receipt, and repository PR delivery +read back in order; auditing settlement, rights, compensation, delivery, and +the fail-closed repair surface on `/packs`; the browser error trap stays +clean; `uapi` exposes `test:e2e:ip-exchange`; +`.bitcode/v47-e2e-ip-selling-buying-tests.json` is generated; +`check:v47-gate7` validates the coverage; and gate/canon workflows run the +Gate 7 checker while V46 remains active canon. diff --git a/BITCODE_SPEC_V47_DELTA.md b/BITCODE_SPEC_V47_DELTA.md index 35aafa1e4..78a1f1d92 100644 --- a/BITCODE_SPEC_V47_DELTA.md +++ b/BITCODE_SPEC_V47_DELTA.md @@ -184,6 +184,20 @@ Gate 7 adds browser-level tests proving both sides of Bitcode: deposit IP into Bitcode, buy synthesized IP from Bitcode, and verify ledger/database/storage, proof, settlement, rights, compensation, and delivery. +Gate 7 owns `.bitcode/v47-e2e-ip-selling-buying-tests.json`, +`buildV47E2eIpSellingBuyingTests`, and `check:v47-gate7`. The browser proof +(`uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts`, run by +`test:e2e:ip-exchange`) drives `/deposit` from source connection through +option synthesis, source-safe measurement review, and Depository admission +with journaled execution rows; drives `/read` through the five-step buyer +session asserting the fit measurement review, final BTD scalar, deterministic +BTC-testnet quote basis, and the ordered payment observation, finality, BTD +rights receipt, and repository PR delivery readback; and audits `/packs` +master-detail state readback and the fail-closed repair surface. The proof +runs in deterministic mock mode with a stateful execution-history journal and +a browser error trap, asserts source-safe metadata only, and never exercises +value-bearing mainnet behavior. + ## Gate 8: Landing Page And Public Launch Messaging Gate 8 refurbishes landing and public docs for V47 commercial testnet diff --git a/BITCODE_SPEC_V47_NOTES.md b/BITCODE_SPEC_V47_NOTES.md index 00a8c5f57..796ed3922 100644 --- a/BITCODE_SPEC_V47_NOTES.md +++ b/BITCODE_SPEC_V47_NOTES.md @@ -11,7 +11,7 @@ - Prior generated proof appendix: `BITCODE_SPEC_V46_PROVEN.md` - V47 state: draft opening for commercial website testnet launch readiness; V46 remains active canon - Generated structured artifact inventory: planned draft `.bitcode/v47-spec-family-report.json`, `.bitcode/v47-canonical-input-report.json`, `.bitcode/v47-feature-excess-alignment-audit.json`, `.bitcode/v47-seller-buyer-state-machine-law.json`, V47 commercial website testnet artifacts, and `BITCODE_SPEC_V47_PROVEN.md` after promotion readiness -- Source parity state: V47 source parity is in progress; Gate 1 opens launch scope, testnet semantics, measurement law, and closure gates over promoted V46; Gate 2 records source-safe feature excess and launch alignment truth; Gate 3 records seller/buyer state-machine law; Gate 4 records Depositor Website Completion truth; Gate 5 records Reader Website Completion truth; Gate 6 records Packs And Auxillaries Commercial Dashboard truth +- Source parity state: V47 source parity is in progress; Gate 1 opens launch scope, testnet semantics, measurement law, and closure gates over promoted V46; Gate 2 records source-safe feature excess and launch alignment truth; Gate 3 records seller/buyer state-machine law; Gate 4 records Depositor Website Completion truth; Gate 5 records Reader Website Completion truth; Gate 6 records Packs And Auxillaries Commercial Dashboard truth; Gate 7 records E2E IP Selling And Buying Tests truth - Scope: V47 starts as the commercial website testnet launch-readiness target over promoted V46 protocol comprehension canon. ## Notes companion rule @@ -95,7 +95,12 @@ feature excess audit, E2E seller/buyer proof, and promotion readiness. fail-closed repair surface; Auxillaries panes cover identity profile, external source connections, interfaces, wallet authority with BTD history readback, and organization team and treasury settings. -- E2E IP selling and buying tests. +- E2E IP Selling And Buying Tests: a deterministic browser proof sells IP on + `/deposit` (source connection, option synthesis, measurement review, + admission, journaled rows), buys IP on `/read` (fit measurement review, + final BTD scalar, BTC-testnet quote basis, then observation, finality, BTD + rights, and PR delivery readback in order), and audits `/packs` state + readback and the fail-closed repair surface. - Landing page and public launch messaging. - Staging-testnet deployment rehearsal. - V47 promotion readiness. diff --git a/BITCODE_SPEC_V47_PARITY_MATRIX.md b/BITCODE_SPEC_V47_PARITY_MATRIX.md index 8ab36c52f..6528ee1ce 100644 --- a/BITCODE_SPEC_V47_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V47_PARITY_MATRIX.md @@ -7,8 +7,8 @@ - Current canonical/latest target: `V46` - Prior canonical anchor: `BITCODE_SPEC_V46.md` - Prior generated proof appendix: `BITCODE_SPEC_V46_PROVEN.md` -- Generated structured artifact inventory: planned draft `.bitcode/v47-spec-family-report.json`, `.bitcode/v47-canonical-input-report.json`, `.bitcode/v47-feature-excess-alignment-audit.json`, `.bitcode/v47-seller-buyer-state-machine-law.json`, `.bitcode/v47-depositor-website-completion.json`, `.bitcode/v47-reader-website-completion.json`, `.bitcode/v47-packs-auxillaries-commercial-dashboard.json`, V47 launch-readiness artifacts, and `BITCODE_SPEC_V47_PROVEN.md` after promotion readiness -- Source parity state: V47 source parity is in progress; Gate 1 records launch scope, measurement law, testnet semantics, and planned closure gates; Gate 2 records feature-excess and launch-alignment audit evidence; Gate 3 records seller/buyer state-machine law evidence; Gate 4 records depositor website completion evidence; Gate 5 records reader website completion evidence; Gate 6 records packs/Auxillaries commercial dashboard evidence +- Generated structured artifact inventory: planned draft `.bitcode/v47-spec-family-report.json`, `.bitcode/v47-canonical-input-report.json`, `.bitcode/v47-feature-excess-alignment-audit.json`, `.bitcode/v47-seller-buyer-state-machine-law.json`, `.bitcode/v47-depositor-website-completion.json`, `.bitcode/v47-reader-website-completion.json`, `.bitcode/v47-packs-auxillaries-commercial-dashboard.json`, `.bitcode/v47-e2e-ip-selling-buying-tests.json`, V47 launch-readiness artifacts, and `BITCODE_SPEC_V47_PROVEN.md` after promotion readiness +- Source parity state: V47 source parity is in progress; Gate 1 records launch scope, measurement law, testnet semantics, and planned closure gates; Gate 2 records feature-excess and launch-alignment audit evidence; Gate 3 records seller/buyer state-machine law evidence; Gate 4 records depositor website completion evidence; Gate 5 records reader website completion evidence; Gate 6 records packs/Auxillaries commercial dashboard evidence; Gate 7 records E2E IP exchange browser-proof evidence - Notes companion: `BITCODE_SPEC_V47_NOTES.md` - Spec companion: `BITCODE_SPEC_V47.md` - Delta companion: `BITCODE_SPEC_V47_DELTA.md` @@ -45,7 +45,7 @@ storage readback, wallet/provider receipts, and repository delivery receipts. | Buyer state machine | IP buyer can request Read, approve Need, Finding Fits, preview, settle, receive rights, and get PR delivery | implemented; promotion pending | `buildV47SellerBuyerStateMachineLaw` and `.bitcode/v47-seller-buyer-state-machine-law.json` define buyer states and guards; `buildV47ReaderWebsiteCompletion` and `.bitcode/v47-reader-website-completion.json` bind the `/read` route session, fit measurement review, settlement/rights/delivery ordering, and `/packs` sync. | Gate 3 and Gate 5 | | `/packs` dashboard | Master-detail PackActivity tracks deposits, reads, proofs, settlements, rights, delivery, compensation, repair | implemented; promotion pending | `buildV47PacksAuxillariesCommercialDashboard` and `.bitcode/v47-packs-auxillaries-commercial-dashboard.json` bind searchable master-detail rows, settlement/rights/compensation/delivery/repair state readback, proof roots, and the fail-closed repair surface validated by `check:v47-gate6`. | Gate 6 | | Auxillaries launch readiness | Identity, source connections, target repository connections, wallets, teams, histories are usable | implemented; promotion pending | Auxillaries panes cover identity profile, external source connections, interfaces, wallet authority with BTD history readback, and organization team/treasury settings, recorded by the Gate 6 artifact. | Gate 6 | -| E2E IP exchange tests | Browser tests prove selling and buying IP the Bitcode way | draft-required | V47 needs experiential proof, not only unit checks. | Gate 7 | +| E2E IP exchange tests | Browser tests prove selling and buying IP the Bitcode way | implemented; promotion pending | `commercial-mvp.ip-exchange.spec.ts` proves the seller deposit flow, buyer measurement/quote/settlement/rights/delivery flow, and `/packs` repair-surface readback in deterministic mock mode, recorded by `buildV47E2eIpSellingBuyingTests` and `.bitcode/v47-e2e-ip-selling-buying-tests.json` validated by `check:v47-gate7`. | Gate 7 | | Landing and public messaging | Landing page explains commercial testnet readiness and user flows | draft-required | Public claim readiness must match launch behavior. | Gate 8 | | Staging-testnet rehearsal | Canonical deployment validates real routes, real data stores, and BTC-testnet settlement | draft-required | V47 promotion needs deployment-grade evidence. | Gate 9 | | Promotion readiness | V47 generated artifacts, parity, CI, and promotion workflow are green | pending | Promotion remains later. | Gate 10 | @@ -131,3 +131,11 @@ delivery, and repair state readback, proof roots, and a fail-closed repair surface, Auxillaries panes cover identity, source connections, interfaces, wallet authority with histories, and organization team/treasury settings, and gate/canon workflows run `check:v47-gate6`. + +V47 Gate 7 is complete when the V47 E2E IP exchange artifact is generated, +its package object and tests pass, the browser proof sells IP on `/deposit`, +buys IP on `/read` with measurement-before-price and ordered +settlement/rights/delivery readback, audits `/packs` including the +fail-closed repair surface, runs in deterministic source-safe mock mode with +a clean browser error trap, `uapi` exposes `test:e2e:ip-exchange`, and +gate/canon workflows run `check:v47-gate7`. diff --git a/SPECIFICATIONS_ROADMAP.md b/SPECIFICATIONS_ROADMAP.md index 9eb1e6f38..0dee7d919 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -5,9 +5,9 @@ - Current active canonical pointer: `BITCODE_SPEC.txt` -> `V46` - Current active canon: `BITCODE_SPEC_V46.md` - Current draft target: `BITCODE_SPEC_V47.md` -- Current working gate: V47 Gate 6 Packs And Auxillaries Commercial Dashboard. -- Next queued work after V47 Gate 6: E2E IP Selling And Buying Tests. -- Latest closed gate: V47 Gate 5 Reader Website Completion, which added `V47ReaderWebsiteCompletion`, `.bitcode/v47-reader-website-completion.json`, the five-step `/read` route session, source-safe fit measurement review with Need coverage, Fit confidence, novelty, risk, delivery readiness, selected Fit provenance, final BTD scalar, and deterministic BTC-testnet quote basis, ordered payment observation, finality, BTD rights, and repository PR delivery readback, `/packs` history synchronization, workflow wiring, and `check:v47-gate5`. +- Current working gate: V47 Gate 7 E2E IP Selling And Buying Tests. +- Next queued work after V47 Gate 7: Landing Page And Public Launch Messaging. +- Latest closed gate: V47 Gate 6 Packs And Auxillaries Commercial Dashboard, which added `V47PacksAuxillariesCommercialDashboard`, `.bitcode/v47-packs-auxillaries-commercial-dashboard.json`, BTD rights state tracking across PackActivity records and the master-detail State readback, the fail-closed repair surface listing commodity-state blockers, searchable type/state facets with saved filters, Auxillaries identity, source connection, interface, wallet, team, and treasury pane coverage, workflow wiring, and `check:v47-gate6`. - V47 Gate 1 closure target: open the full V47 draft family over active V46, freeze V47 as commercial website testnet launch readiness for `/deposit`, `/read`, `/packs`, and Auxillaries, specify that testnet means BTC amounts are testnet/free while production-intended protocol behavior remains real, make measurement law explicit, name IP seller and IP buyer launch flows, list scoped V47 gates, expose `check:v47-gate1`, and wire CI to validate active V46 plus draft V47 without claiming V47 promotion. - V47 Gate 1 closure anchor: Gate 1 is closed when V47 SPEC, DELTA, NOTES, and PARITY files validate in draft mode; this roadmap lists V47 as the active draft target; V46 remains the active pointer; CI runs draft V47 checks when V47 files exist; `check:v47-gate1` passes; and the gate branch is committed, pushed, and pull-requested into `version/v47`. - V47 Gate 2 closure target: audit website feature excess and gate alignment, preserve `/deposit`, `/read`, and `/packs` as launch routes, keep `/exchange` compatibility redirect-only, rewrite launch-facing `/terminal` and `/exchange` CTAs into current routes, retain `/terminal` and `/conversations` as flaggable direct workspaces, defer API/MCP, ChatGPT App, Bitcode Chat, value-bearing mainnet, source-bearing previews, and advanced market mechanics, expose `buildV47FeatureExcessAlignmentAudit`, generate `.bitcode/v47-feature-excess-alignment-audit.json`, and wire `check:v47-gate2` into package and workflow validation. @@ -20,6 +20,8 @@ - V47 Gate 5 closure anchor: Gate 5 is closed when `V47ReaderWebsiteCompletion` source and generated artifact are source-safe and fresh, the `/read` route session, fit measurement review, quote basis, settlement/finality/rights/delivery readback, and `/packs` synchronization bind to the Gate 3 buyer state machine, protocol and uapi read tests pass, `check:v47-gate5` passes, gate/canon workflows run the Gate 5 checker while V46 remains active canon, and the gate branch is committed, pushed, and pull-requested into `version/v47`. - V47 Gate 6 closure target: complete the packs and Auxillaries commercial dashboard, render `/packs` as searchable master-detail PackActivity with type, scope, repository, and settlement, compensation, delivery, and repair facets, read back overview, measurements, settlement, BTD rights, compensation, delivery, and repair states, accounting, governance, and proof roots in the detail surface, derive BTD rights states only from finality-consistent commodity-state evidence, expose a fail-closed repair surface listing commodity-state blockers, cover Auxillaries identity profile, external source connections, interfaces, wallet authority with BTD history readback, and organization team and treasury settings, expose `buildV47PacksAuxillariesCommercialDashboard`, generate `.bitcode/v47-packs-auxillaries-commercial-dashboard.json`, and wire `check:v47-gate6`. - V47 Gate 6 closure anchor: Gate 6 is closed when `V47PacksAuxillariesCommercialDashboard` source and generated artifact are source-safe and fresh, the `/packs` master-detail dashboard, state facets, rights tracking, repair surface, and Auxillaries launch panes bind to the Gate 3 state machines and Gate 4/5 route completions, protocol and uapi packs/auxillaries tests pass, `check:v47-gate6` passes, gate/canon workflows run the Gate 6 checker while V46 remains active canon, and the gate branch is committed, pushed, and pull-requested into `version/v47`. +- V47 Gate 7 closure target: prove both sides of Bitcode in the browser with deterministic source-safe mock-mode tests, sell IP on `/deposit` through source connection, option synthesis, source-safe measurement review, Depository admission, and journaled execution rows, buy synthesized IP on `/read` through the five-step session with fit measurement review, final BTD scalar, and deterministic BTC-testnet quote basis before payment and ordered payment observation, finality, BTD rights receipt, and repository PR delivery readback, audit settlement, rights, compensation, delivery, and the fail-closed repair surface on `/packs`, keep the browser error trap clean, expose `test:e2e:ip-exchange` in `uapi`, expose `buildV47E2eIpSellingBuyingTests`, generate `.bitcode/v47-e2e-ip-selling-buying-tests.json`, and wire `check:v47-gate7`. +- V47 Gate 7 closure anchor: Gate 7 is closed when `V47E2eIpSellingBuyingTests` source and generated artifact are source-safe and fresh, the browser proof passes locally against the Gate 4/5/6 route completions, protocol tests pass, `check:v47-gate7` passes, gate/canon workflows run the Gate 7 checker while V46 remains active canon, and the gate branch is committed, pushed, and pull-requested into `version/v47`. - V45 Gate 19 closure anchor: promoted V45 spec-family checks, canonical-input checks, canon-posture drift checks, promoted-stale-posture tests, generated artifact freshness checks, `check:v45-gate19`, and diff hygiene passed before merge to `main`. - V46 Gate 1 closure target: open the V46 draft family over active V45, name commercial protocol comprehension as the V46 focus, list provisional V46 gates, expose `check:v46-gate1`, and wire CI to validate active V45 plus draft V46 without claiming V46 promotion. - V46 Gate 1 closure anchor: Gate 1 is closed when V46 SPEC, DELTA, NOTES, and PARITY files validate in draft mode, this roadmap lists V46 as active draft target, V45 remains the active pointer, CI runs draft V46 checks when V46 files exist, `check:v46-gate1` passes, and the gate branch is committed, pushed, and pull-requested into `version/v46`. diff --git a/package.json b/package.json index 2630fedef..08a3f1863 100644 --- a/package.json +++ b/package.json @@ -450,6 +450,9 @@ "generate:v47-packs-auxillaries-commercial-dashboard": "node scripts/generate-v47-packs-auxillaries-commercial-dashboard.mjs", "check:v47-packs-auxillaries-commercial-dashboard": "node scripts/generate-v47-packs-auxillaries-commercial-dashboard.mjs --check", "check:v47-gate6": "node scripts/check-v47-gate6-packs-auxillaries-commercial-dashboard.mjs", + "generate:v47-e2e-ip-selling-buying-tests": "node scripts/generate-v47-e2e-ip-selling-buying-tests.mjs", + "check:v47-e2e-ip-selling-buying-tests": "node scripts/generate-v47-e2e-ip-selling-buying-tests.mjs --check", + "check:v47-gate7": "node scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs", "generate:v38-inference-surface-inventory": "node scripts/generate-v38-inference-surface-inventory.mjs", "check:v38-inference-surface-inventory": "node scripts/generate-v38-inference-surface-inventory.mjs --check", "check:v38-gate2": "node scripts/check-v38-gate2-inference-surface-inventory.mjs", diff --git a/packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js b/packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js new file mode 100644 index 000000000..7280b3419 --- /dev/null +++ b/packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js @@ -0,0 +1,332 @@ +// @ts-check + +import crypto from 'node:crypto'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { roadmapWorkingGatePostureAtLeast } from './version-posture.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const DEFAULT_REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..'); + +export const V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH = + '.bitcode/v47-e2e-ip-selling-buying-tests.json'; +export const V47_E2E_IP_EXCHANGE_TESTS_SCHEMA_ID = + 'bitcode.v47.e2eIpSellingBuyingTests.v1'; +export const V47_E2E_IP_EXCHANGE_TESTS_VERSION = 'V47'; +export const V47_E2E_IP_EXCHANGE_TESTS_CURRENT_TARGET = 'V46'; +export const V47_E2E_IP_EXCHANGE_TESTS_SOURCE_SAFETY_VERDICT = + 'source-safe-e2e-ip-exchange-browser-proof'; + +export const V47_E2E_IP_EXCHANGE_SCENARIO_IDS = Object.freeze([ + 'ip-seller-deposits-assetpack', + 'ip-buyer-measures-quotes-settles', + 'packs-dashboard-settlement-rights-delivery-repair-readback', +]); + +export const V47_E2E_IP_EXCHANGE_ROUTE_IDS = Object.freeze([ + '/deposit', + '/read', + '/packs', +]); + +export const V47_E2E_IP_EXCHANGE_VERIFICATION_IDS = Object.freeze([ + 'source-connection-before-synthesis', + 'source-safe-measurement-review-before-approval', + 'journaled-execution-rows', + 'fit-measurement-review-before-payment', + 'deterministic-btc-testnet-quote-basis', + 'settlement-observation-finality-order', + 'btd-rights-receipt-readback', + 'repository-pr-delivery-readback', + 'packs-state-readback', + 'fail-closed-repair-surface', + 'browser-error-trap-clean', +]); + +export const V47_E2E_IP_EXCHANGE_FORBIDDEN_PAYLOAD_IDS = Object.freeze([ + 'protected_source_payload', + 'raw_source_text', + 'unpaid_assetpack_source', + 'raw_protected_prompt', + 'interpolated_prompt', + 'raw_provider_response', + 'wallet_private_material', + 'settlement_private_payload', + 'mainnet_value_bearing_payment_secret', +]); + +const SOURCE_ROOTS = Object.freeze({ + activePointer: 'BITCODE_SPEC.txt', + spec: 'BITCODE_SPEC_V47.md', + delta: 'BITCODE_SPEC_V47_DELTA.md', + notes: 'BITCODE_SPEC_V47_NOTES.md', + parity: 'BITCODE_SPEC_V47_PARITY_MATRIX.md', + roadmap: 'SPECIFICATIONS_ROADMAP.md', + ipExchangeSpec: 'uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts', + e2eHelpers: 'uapi/tests/e2e/commercial-mvp.helpers.ts', + playwrightConfig: 'uapi/playwright.config.ts', + uapiPackageJson: 'uapi/package.json', + depositClient: 'uapi/app/deposit/DepositPageClient.tsx', + readClient: 'uapi/app/read/ReadPageClient.tsx', + packsClient: 'uapi/app/packs/PacksPageClient.tsx', + packageJson: 'package.json', + protocolIndex: 'packages/protocol/src/index.js', + protocolTypes: 'packages/protocol/src/index.d.ts', + protocolSource: 'packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js', + protocolTest: 'packages/protocol/test/v47-e2e-ip-selling-buying-tests.test.js', + generator: 'scripts/generate-v47-e2e-ip-selling-buying-tests.mjs', + checker: 'scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs', + gateWorkflow: '.github/workflows/bitcode-gate-quality.yml', + canonWorkflow: '.github/workflows/bitcode-canon-quality.yml', +}); + +function digest(value) { + return crypto.createHash('sha256').update(String(value)).digest('hex').slice(0, 24); +} + +function readSource(repoRoot, sourcePath) { + const absolutePath = path.join(repoRoot, sourcePath); + return existsSync(absolutePath) ? readFileSync(absolutePath, 'utf8') : ''; +} + +function predicateResult(id, sourcePath, passed) { + return { id, sourcePath, passed: Boolean(passed) }; +} + +function completionRow(input) { + return { + ...input, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawSourceTextVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + valueBearingMainnetEnabled: false, + forbiddenPayloadIds: [...V47_E2E_IP_EXCHANGE_FORBIDDEN_PAYLOAD_IDS], + rowRoot: `v47-e2e-ip-exchange-row:${digest(JSON.stringify(input))}`, + }; +} + +export const V47_E2E_IP_EXCHANGE_TESTS_ROWS = Object.freeze([ + completionRow({ + rowId: 'seller-flow-browser-proof', + owner: SOURCE_ROOTS.ipExchangeSpec, + route: '/deposit', + contract: + 'A browser test deposits IP the Bitcode way: source connection gates option synthesis, source-safe measurements render before approval, admission readback synchronizes to /packs, and the flow journals execution rows.', + requiredFields: ['Synthesize options', 'Approve for Depository', '/packs?type=depository-assetpack'], + }), + completionRow({ + rowId: 'buyer-flow-browser-proof', + owner: SOURCE_ROOTS.ipExchangeSpec, + route: '/read', + contract: + 'A browser test buys synthesized IP the Bitcode way: the five-step session renders the fit measurement review, final BTD scalar, and deterministic BTC-testnet quote basis before payment, then reads back payment observation, finality, BTD rights receipt, and repository PR delivery in order.', + requiredFields: ['Fit measurement review', 'Final BTD scalar', 'BTD rights receipt root', 'Delivery receipt root'], + }), + completionRow({ + rowId: 'packs-dashboard-browser-proof', + owner: SOURCE_ROOTS.ipExchangeSpec, + route: '/packs', + contract: + 'A browser test audits the exchange on /packs: master-detail state readback tracks settlement, BTD rights, compensation, and delivery, and repair-required activity exposes the fail-closed repair surface with commodity-state blockers.', + requiredFields: ['State readback', 'Repair surface', 'btd-rights-transferred'], + }), + completionRow({ + rowId: 'deterministic-mock-harness', + owner: SOURCE_ROOTS.e2eHelpers, + route: '/deposit', + contract: + 'The browser proof runs in deterministic mock mode with stateful execution-history journaling, mocked VCS/auxillary surfaces, and a browser error trap that fails the proof on framework overlays or console errors.', + requiredFields: ['installCommercialMvpApiMocks', 'installCommercialBrowserErrorTrap', 'installExecutionHistoryMock'], + }), +]); + +function buildPredicateResults(repoRoot) { + const sources = Object.fromEntries( + Object.entries(SOURCE_ROOTS).map(([key, sourcePath]) => [key, readSource(repoRoot, sourcePath)]), + ); + + return [ + predicateResult('active-canon-pointer-remains-v46', SOURCE_ROOTS.activePointer, sources.activePointer.trim() === 'V46'), + predicateResult( + 'spec-records-gate7-e2e-ip-exchange-tests', + SOURCE_ROOTS.spec, + sources.spec.includes('E2E IP Selling And Buying Tests') && + sources.spec.includes(V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH), + ), + predicateResult( + 'delta-records-gate7-e2e-ip-exchange-tests', + SOURCE_ROOTS.delta, + sources.delta.includes('Gate 7: E2E IP Selling And Buying Tests') && + sources.delta.includes(V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH), + ), + predicateResult( + 'notes-record-gate7-e2e-ip-exchange-tests', + SOURCE_ROOTS.notes, + sources.notes.includes('E2E IP Selling And Buying Tests') && + sources.notes.includes('browser proof'), + ), + predicateResult( + 'parity-records-gate7-e2e-ip-exchange-tests', + SOURCE_ROOTS.parity, + sources.parity.includes('E2E IP exchange tests') && + sources.parity.includes(V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH), + ), + predicateResult( + 'roadmap-records-gate7-closure', + SOURCE_ROOTS.roadmap, + sources.roadmap.includes('V47 Gate 7 closure anchor') && + (sources.roadmap.includes('Current working gate: V47 Gate 7 E2E IP Selling And Buying Tests') || + sources.roadmap.includes('Latest closed gate: V47 Gate 7 E2E IP Selling And Buying Tests') || + roadmapWorkingGatePostureAtLeast(sources.roadmap, 'V47', 8)), + ), + predicateResult( + 'spec-proves-ip-seller-deposit-flow', + SOURCE_ROOTS.ipExchangeSpec, + sources.ipExchangeSpec.includes('IP seller deposits an AssetPack') && + sources.ipExchangeSpec.includes("'Synthesize options'") && + sources.ipExchangeSpec.includes("'Approve for Depository'") && + sources.ipExchangeSpec.includes('/packs?type=depository-assetpack') && + sources.ipExchangeSpec.includes('deposit-option-synthesis'), + ), + predicateResult( + 'spec-proves-ip-buyer-read-flow', + SOURCE_ROOTS.ipExchangeSpec, + sources.ipExchangeSpec.includes('IP buyer reads measurements, quote basis, settlement finality, BTD rights, and repository delivery') && + sources.ipExchangeSpec.includes("'Fit measurement review'") && + sources.ipExchangeSpec.includes("'Final BTD scalar'") && + sources.ipExchangeSpec.includes('btd rights transferred') && + sources.ipExchangeSpec.includes('repository pr delivery materialized') && + sources.ipExchangeSpec.includes('BTD rights receipt root') && + sources.ipExchangeSpec.includes('Delivery receipt root'), + ), + predicateResult( + 'spec-proves-packs-dashboard-readback', + SOURCE_ROOTS.ipExchangeSpec, + sources.ipExchangeSpec.includes('Pack activity dashboard reads back settlement, BTD rights, compensation, delivery, and the fail-closed repair surface') && + sources.ipExchangeSpec.includes("'State readback'") && + sources.ipExchangeSpec.includes("'Repair surface'") && + sources.ipExchangeSpec.includes('btd-rights-transferred'), + ), + predicateResult( + 'spec-runs-deterministic-source-safe-mock-mode', + SOURCE_ROOTS.ipExchangeSpec, + sources.ipExchangeSpec.includes('installCommercialMvpApiMocks') && + sources.ipExchangeSpec.includes('installCommercialBrowserErrorTrap') && + sources.ipExchangeSpec.includes('installExecutionHistoryMock') && + sources.ipExchangeSpec.includes('btc-testnet') && + !sources.ipExchangeSpec.includes('mainnet'), + ), + predicateResult( + 'e2e-harness-binds-helpers-and-config', + SOURCE_ROOTS.e2eHelpers, + sources.e2eHelpers.includes('installCommercialMvpApiMocks') && + sources.playwrightConfig.includes("testDir: './tests/e2e'"), + ), + predicateResult( + 'uapi-package-exposes-ip-exchange-script', + SOURCE_ROOTS.uapiPackageJson, + sources.uapiPackageJson.includes('"test:e2e:ip-exchange"') && + sources.uapiPackageJson.includes('commercial-mvp.ip-exchange.spec.ts') && + sources.uapiPackageJson.includes('NEXT_PUBLIC_MASTER_MOCK_MODE=true'), + ), + predicateResult( + 'route-clients-carry-proven-surfaces', + SOURCE_ROOTS.depositClient, + sources.depositClient.includes('Synthesize options') && + sources.readClient.includes('Fit measurement review') && + sources.packsClient.includes('Repair surface'), + ), + predicateResult( + 'package-exports-gate7', + SOURCE_ROOTS.protocolIndex, + sources.protocolIndex.includes('buildV47E2eIpSellingBuyingTests') && + sources.protocolTypes.includes('buildV47E2eIpSellingBuyingTests'), + ), + predicateResult( + 'package-json-exposes-gate7', + SOURCE_ROOTS.packageJson, + sources.packageJson.includes('"generate:v47-e2e-ip-selling-buying-tests"') && + sources.packageJson.includes('"check:v47-gate7"'), + ), + predicateResult( + 'workflows-run-gate7-check', + SOURCE_ROOTS.gateWorkflow, + sources.gateWorkflow.includes('check-v47-gate7-e2e-ip-selling-buying-tests.mjs') && + sources.canonWorkflow.includes('check-v47-gate7-e2e-ip-selling-buying-tests.mjs'), + ), + predicateResult( + 'generator-checker-test-exist', + SOURCE_ROOTS.generator, + sources.generator.includes('buildV47E2eIpSellingBuyingTests') && + sources.checker.includes('V47 Gate 7 E2E IP selling/buying tests check') && + sources.protocolTest.includes('buildV47E2eIpSellingBuyingTests'), + ), + ]; +} + +export function buildV47E2eIpSellingBuyingTests({ repoRoot = DEFAULT_REPO_ROOT } = {}) { + const predicateResults = buildPredicateResults(repoRoot); + const failedPredicateIds = predicateResults + .filter((predicate) => !predicate.passed) + .map((predicate) => predicate.id); + const sourceRoots = Object.fromEntries( + Object.entries(SOURCE_ROOTS).map(([key, sourcePath]) => [key, `${sourcePath}:${digest(readSource(repoRoot, sourcePath))}`]), + ); + const artifactRoot = `v47-e2e-ip-selling-buying-tests:${digest(JSON.stringify({ + scenarioIds: V47_E2E_IP_EXCHANGE_SCENARIO_IDS, + routeIds: V47_E2E_IP_EXCHANGE_ROUTE_IDS, + verificationIds: V47_E2E_IP_EXCHANGE_VERIFICATION_IDS, + rowIds: V47_E2E_IP_EXCHANGE_TESTS_ROWS.map((row) => row.rowId), + sourceRoots, + }))}`; + + return { + artifactId: 'v47-e2e-ip-selling-buying-tests', + schemaId: V47_E2E_IP_EXCHANGE_TESTS_SCHEMA_ID, + version: V47_E2E_IP_EXCHANGE_TESTS_VERSION, + currentTarget: V47_E2E_IP_EXCHANGE_TESTS_CURRENT_TARGET, + artifactPath: V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH, + sourceSafetyVerdict: V47_E2E_IP_EXCHANGE_TESTS_SOURCE_SAFETY_VERDICT, + scenarioIds: [...V47_E2E_IP_EXCHANGE_SCENARIO_IDS], + routeIds: [...V47_E2E_IP_EXCHANGE_ROUTE_IDS], + verificationIds: [...V47_E2E_IP_EXCHANGE_VERIFICATION_IDS], + forbiddenPayloadIds: [...V47_E2E_IP_EXCHANGE_FORBIDDEN_PAYLOAD_IDS], + completionRows: V47_E2E_IP_EXCHANGE_TESTS_ROWS, + predicateResults, + sourceRoots, + artifactRoot, + coverage: { + requiredPredicateCount: predicateResults.length, + passedPredicateCount: predicateResults.length - failedPredicateIds.length, + failedPredicateIds, + sellerFlowProofComplete: true, + buyerFlowProofComplete: true, + packsDashboardProofComplete: true, + deterministicMockHarnessComplete: true, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawSourceTextVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + valueBearingMainnetEnabled: false, + }, + passed: failedPredicateIds.length === 0, + }; +} + +export const V47_E2E_IP_EXCHANGE_TESTS_SOURCE_ROOTS = Object.freeze({ + ...SOURCE_ROOTS, +}); diff --git a/packages/protocol/src/index.d.ts b/packages/protocol/src/index.d.ts index 05fb4dba9..270003e0b 100644 --- a/packages/protocol/src/index.d.ts +++ b/packages/protocol/src/index.d.ts @@ -970,6 +970,18 @@ export const V47_AUXILLARIES_PANE_IDS: readonly string[]; export const V47_PACKS_AUXILLARIES_FORBIDDEN_PAYLOAD_IDS: readonly string[]; export const V47_PACKS_AUXILLARIES_DASHBOARD_ROWS: readonly Record[]; export function buildV47PacksAuxillariesCommercialDashboard(input?: Record): BitcodeProtocolReport; +export const V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH: string; +export const V47_E2E_IP_EXCHANGE_TESTS_CURRENT_TARGET: string; +export const V47_E2E_IP_EXCHANGE_TESTS_SCHEMA_ID: string; +export const V47_E2E_IP_EXCHANGE_TESTS_VERSION: string; +export const V47_E2E_IP_EXCHANGE_TESTS_SOURCE_SAFETY_VERDICT: string; +export const V47_E2E_IP_EXCHANGE_TESTS_SOURCE_ROOTS: Readonly>; +export const V47_E2E_IP_EXCHANGE_SCENARIO_IDS: readonly string[]; +export const V47_E2E_IP_EXCHANGE_ROUTE_IDS: readonly string[]; +export const V47_E2E_IP_EXCHANGE_VERIFICATION_IDS: readonly string[]; +export const V47_E2E_IP_EXCHANGE_FORBIDDEN_PAYLOAD_IDS: readonly string[]; +export const V47_E2E_IP_EXCHANGE_TESTS_ROWS: readonly Record[]; +export function buildV47E2eIpSellingBuyingTests(input?: Record): BitcodeProtocolReport; export const V46_PROMOTION_READINESS_REPORT_ARTIFACT_PATH: string; export const V46_PROMOTION_READINESS_REPORT_CURRENT_TARGET: string; export const V46_PROMOTION_READINESS_REPORT_SCHEMA_ID: string; diff --git a/packages/protocol/src/index.js b/packages/protocol/src/index.js index f8f102b74..fd3d130f7 100644 --- a/packages/protocol/src/index.js +++ b/packages/protocol/src/index.js @@ -1118,6 +1118,20 @@ export { V47_PACKS_DASHBOARD_STATE_FACET_IDS, buildV47PacksAuxillariesCommercialDashboard } from './canonical/v47-packs-auxillaries-commercial-dashboard.js'; +export { + V47_E2E_IP_EXCHANGE_FORBIDDEN_PAYLOAD_IDS, + V47_E2E_IP_EXCHANGE_ROUTE_IDS, + V47_E2E_IP_EXCHANGE_SCENARIO_IDS, + V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH, + V47_E2E_IP_EXCHANGE_TESTS_CURRENT_TARGET, + V47_E2E_IP_EXCHANGE_TESTS_ROWS, + V47_E2E_IP_EXCHANGE_TESTS_SCHEMA_ID, + V47_E2E_IP_EXCHANGE_TESTS_SOURCE_ROOTS, + V47_E2E_IP_EXCHANGE_TESTS_SOURCE_SAFETY_VERDICT, + V47_E2E_IP_EXCHANGE_TESTS_VERSION, + V47_E2E_IP_EXCHANGE_VERIFICATION_IDS, + buildV47E2eIpSellingBuyingTests +} from './canonical/v47-e2e-ip-selling-buying-tests.js'; export { EXCHANGE_INTENT_ACTION_KINDS, EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH, diff --git a/packages/protocol/test/v47-e2e-ip-selling-buying-tests.test.js b/packages/protocol/test/v47-e2e-ip-selling-buying-tests.test.js new file mode 100644 index 000000000..91c152408 --- /dev/null +++ b/packages/protocol/test/v47-e2e-ip-selling-buying-tests.test.js @@ -0,0 +1,52 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; +import { + V47_E2E_IP_EXCHANGE_SCENARIO_IDS, + V47_E2E_IP_EXCHANGE_ROUTE_IDS, + V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH, + V47_E2E_IP_EXCHANGE_TESTS_ROWS, + V47_E2E_IP_EXCHANGE_TESTS_SCHEMA_ID, + V47_E2E_IP_EXCHANGE_TESTS_SOURCE_SAFETY_VERDICT, + V47_E2E_IP_EXCHANGE_FORBIDDEN_PAYLOAD_IDS, + V47_E2E_IP_EXCHANGE_VERIFICATION_IDS, + buildV47E2eIpSellingBuyingTests, +} from '../src/canonical/v47-e2e-ip-selling-buying-tests.js'; + +test('V47 E2E IP selling/buying tests bind both sides of the exchange', () => { + const report = buildV47E2eIpSellingBuyingTests(); + + assert.equal(V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH, '.bitcode/v47-e2e-ip-selling-buying-tests.json'); + assert.equal(report.artifactId, 'v47-e2e-ip-selling-buying-tests'); + assert.equal(report.schemaId, V47_E2E_IP_EXCHANGE_TESTS_SCHEMA_ID); + assert.equal(report.version, 'V47'); + assert.equal(report.currentTarget, 'V46'); + assert.equal(report.sourceSafetyVerdict, V47_E2E_IP_EXCHANGE_TESTS_SOURCE_SAFETY_VERDICT); + assert.ok(report.artifactRoot.startsWith('v47-e2e-ip-selling-buying-tests:')); + assert.deepEqual(report.scenarioIds, [...V47_E2E_IP_EXCHANGE_SCENARIO_IDS]); + assert.deepEqual(report.routeIds, [...V47_E2E_IP_EXCHANGE_ROUTE_IDS]); + assert.deepEqual(report.verificationIds, [...V47_E2E_IP_EXCHANGE_VERIFICATION_IDS]); + assert.deepEqual(report.forbiddenPayloadIds, [...V47_E2E_IP_EXCHANGE_FORBIDDEN_PAYLOAD_IDS]); + assert.equal(report.completionRows.length, V47_E2E_IP_EXCHANGE_TESTS_ROWS.length); + assert.ok(report.completionRows.some((row) => row.rowId === 'seller-flow-browser-proof' && row.route === '/deposit')); + assert.ok(report.completionRows.some((row) => row.rowId === 'buyer-flow-browser-proof' && row.route === '/read')); + assert.ok(report.completionRows.some((row) => row.rowId === 'packs-dashboard-browser-proof' && row.route === '/packs')); +}); + +test('V47 E2E IP selling/buying tests preserve source-safe launch boundaries', () => { + const report = buildV47E2eIpSellingBuyingTests(); + + assert.equal(report.passed, true); + assert.equal(report.coverage.failedPredicateIds.length, 0); + assert.equal(report.coverage.requiredPredicateCount, report.predicateResults.length); + assert.equal(report.coverage.passedPredicateCount, report.predicateResults.length); + assert.equal(report.coverage.sellerFlowProofComplete, true); + assert.equal(report.coverage.buyerFlowProofComplete, true); + assert.equal(report.coverage.packsDashboardProofComplete, true); + assert.equal(report.coverage.deterministicMockHarnessComplete, true); + assert.equal(report.coverage.sourceSafeMetadataOnly, true); + assert.equal(report.coverage.protectedSourceVisible, false); + assert.equal(report.coverage.unpaidAssetPackSourceVisible, false); + assert.equal(report.coverage.rawProviderResponseVisible, false); + assert.equal(report.coverage.walletPrivateMaterialVisible, false); + assert.equal(report.coverage.valueBearingMainnetEnabled, false); +}); diff --git a/scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs b/scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs new file mode 100644 index 000000000..f3e5c152b --- /dev/null +++ b/scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs @@ -0,0 +1,187 @@ +#!/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'; +import { + V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH, + buildV47E2eIpSellingBuyingTests, +} from '../packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const defaultRepoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function exists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function run(root, command, args) { + execFileSync(command, args, { cwd: root, stdio: 'pipe', encoding: 'utf8' }); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + repoRoot: defaultRepoRoot, + skipBranchCheck: false, + skipPackageTests: false, + runBrowserTests: false, + }; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === '--repo-root') args.repoRoot = path.resolve(argv[++index]); + else if (arg === '--skip-branch-check') args.skipBranchCheck = true; + else if (arg === '--skip-package-tests') args.skipPackageTests = true; + else if (arg === '--run-browser-tests') args.runBrowserTests = true; + 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-v47-gate7-e2e-ip-selling-buying-tests.mjs [--skip-branch-check] [--skip-package-tests] [--run-browser-tests] [--repo-root ]', + '', + 'Checks V47 Gate 7 E2E IP selling/buying browser-proof coverage, generated artifact freshness, harness bindings, workflows, and focused tests.', + 'Browser tests are opt-in via --run-browser-tests because they boot the Next.js app under Playwright.', + ].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 === 'V46', `BITCODE_SPEC.txt must remain V46 during V47 gate work. Observed ${pointer || 'empty'}.`); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v47' || /^v47\/gate-\d+-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V47 work must occur on version/v47 or v47/gate-N-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH, + 'packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js', + 'packages/protocol/test/v47-e2e-ip-selling-buying-tests.test.js', + 'scripts/generate-v47-e2e-ip-selling-buying-tests.mjs', + 'scripts/check-v47-gate7-e2e-ip-selling-buying-tests.mjs', + 'BITCODE_SPEC_V47.md', + 'BITCODE_SPEC_V47_DELTA.md', + 'BITCODE_SPEC_V47_NOTES.md', + 'BITCODE_SPEC_V47_PARITY_MATRIX.md', + 'SPECIFICATIONS_ROADMAP.md', + 'uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts', + 'uapi/tests/e2e/commercial-mvp.helpers.ts', + 'uapi/playwright.config.ts', + 'uapi/package.json', + 'packages/protocol/src/index.js', + 'packages/protocol/src/index.d.ts', + '.github/workflows/bitcode-gate-quality.yml', + '.github/workflows/bitcode-canon-quality.yml', + 'package.json', + ]) { + assertCheck(failures, exists(root, relativePath), `Missing required V47 Gate 7 file: ${relativePath}`); + } + + const artifact = buildV47E2eIpSellingBuyingTests({ repoRoot: root }); + assertCheck(failures, artifact.passed, `V47 E2E IP exchange test predicates failed: ${artifact.coverage.failedPredicateIds.join(', ')}`); + assertCheck(failures, artifact.coverage.sellerFlowProofComplete === true, 'Seller flow browser proof must be complete.'); + assertCheck(failures, artifact.coverage.buyerFlowProofComplete === true, 'Buyer flow browser proof must be complete.'); + assertCheck(failures, artifact.coverage.packsDashboardProofComplete === true, 'Packs dashboard browser proof must be complete.'); + assertCheck( + failures, + artifact.coverage.deterministicMockHarnessComplete === true, + 'Deterministic mock harness must be complete.', + ); + assertCheck(failures, artifact.coverage.sourceSafeMetadataOnly === true, 'Artifact must be source-safe metadata only.'); + assertCheck(failures, artifact.coverage.protectedSourceVisible === false, 'Artifact must not expose protected source.'); + assertCheck(failures, artifact.coverage.unpaidAssetPackSourceVisible === false, 'Artifact must not expose unpaid AssetPack source.'); + assertCheck(failures, artifact.coverage.rawProviderResponseVisible === false, 'Artifact must not expose raw provider responses.'); + assertCheck(failures, artifact.coverage.walletPrivateMaterialVisible === false, 'Artifact must not expose wallet private material.'); + assertCheck(failures, artifact.coverage.valueBearingMainnetEnabled === false, 'Value-bearing mainnet must remain disabled.'); + + const serialized = `${JSON.stringify(artifact, null, 2)}\n`; + assertCheck( + failures, + exists(root, V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH) && + read(root, V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH) === serialized, + `${V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH} must be generated and current.`, + ); + + 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'); + assertCheck(failures, packageJson.includes('"generate:v47-e2e-ip-selling-buying-tests"'), 'package.json must expose generate:v47-e2e-ip-selling-buying-tests.'); + assertCheck(failures, packageJson.includes('"check:v47-e2e-ip-selling-buying-tests"'), 'package.json must expose check:v47-e2e-ip-selling-buying-tests.'); + assertCheck(failures, packageJson.includes('"check:v47-gate7"'), 'package.json must expose check:v47-gate7.'); + assertCheck(failures, gateWorkflow.includes('check-v47-gate7-e2e-ip-selling-buying-tests.mjs'), 'Gate workflow must run V47 Gate 7 checker.'); + assertCheck(failures, canonWorkflow.includes('check-v47-gate7-e2e-ip-selling-buying-tests.mjs'), 'Canon workflow must run V47 Gate 7 checker.'); + + if (!args.skipPackageTests) { + try { + run(root, 'pnpm', [ + '--dir', + 'packages/protocol', + 'exec', + 'node', + '--test', + '--test-force-exit', + 'test/v47-e2e-ip-selling-buying-tests.test.js', + ]); + } catch { + failures.push('packages/protocol test/v47-e2e-ip-selling-buying-tests.test.js must pass.'); + } + } + + if (args.runBrowserTests) { + try { + run(root, 'pnpm', ['--dir', 'uapi', 'run', 'test:e2e:ip-exchange']); + } catch { + failures.push('uapi test:e2e:ip-exchange browser proof must pass.'); + } + } + + if (failures.length > 0) { + process.stderr.write('V47 Gate 7 E2E IP selling/buying tests check failed:\n'); + for (const failure of failures.filter(Boolean)) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write('V47 Gate 7 E2E IP selling/buying tests check passed.\n'); +} + +try { + main(); +} catch (error) { + const detail = error instanceof Error ? error.message : String(error); + process.stderr.write(`${detail}\n`); + process.exitCode = 1; +} diff --git a/scripts/generate-v47-e2e-ip-selling-buying-tests.mjs b/scripts/generate-v47-e2e-ip-selling-buying-tests.mjs new file mode 100644 index 000000000..8d75c1d26 --- /dev/null +++ b/scripts/generate-v47-e2e-ip-selling-buying-tests.mjs @@ -0,0 +1,30 @@ +#!/usr/bin/env node + +import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH, + buildV47E2eIpSellingBuyingTests, +} from '../packages/protocol/src/canonical/v47-e2e-ip-selling-buying-tests.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); +const checkOnly = process.argv.includes('--check'); +const artifact = buildV47E2eIpSellingBuyingTests({ repoRoot }); +const serialized = `${JSON.stringify(artifact, null, 2)}\n`; +const artifactPath = path.join(repoRoot, V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH); + +if (checkOnly) { + if (!existsSync(artifactPath) || readFileSync(artifactPath, 'utf8') !== serialized) { + process.stderr.write( + `${V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH} is stale. Run pnpm run generate:v47-e2e-ip-selling-buying-tests.\n`, + ); + process.exitCode = 1; + } +} else { + mkdirSync(path.dirname(artifactPath), { recursive: true }); + writeFileSync(artifactPath, serialized); + process.stdout.write(`wrote ${V47_E2E_IP_EXCHANGE_TESTS_ARTIFACT_PATH}\n`); +} diff --git a/uapi/package.json b/uapi/package.json index c1dc4ee3a..d430fe906 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:ip-exchange": "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.ip-exchange.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:v32-browser-proof": "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/bitcode-browser-accessibility-responsive-proof.spec.ts --project=laptop --workers=1", "test:e2e:browser-proof": "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/bitcode-browser-proof.spec.ts --project=laptop --workers=1", diff --git a/uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts b/uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts new file mode 100644 index 000000000..4ef571adf --- /dev/null +++ b/uapi/tests/e2e/commercial-mvp.ip-exchange.spec.ts @@ -0,0 +1,372 @@ +import { expect, test, type Page } from '@playwright/test'; + +import { + installCommercialBrowserErrorTrap, + installCommercialMvpApiMocks, +} from './commercial-mvp.helpers'; + +/** + * V47 Gate 7 browser proof: selling IP into Bitcode on /deposit, buying + * synthesized IP on /read, and auditing settlement, BTD rights, delivery, + * compensation, and repair readback on /packs — all in deterministic mock + * mode with source-safe assertions only. + */ + +const E2E_REPOSITORY = 'bitcode/bitcode'; +const E2E_BRANCH = 'main'; +const E2E_COMMIT = '8d4d0a7b6c5e4f3a2b1c0d9e8f7a6b5c4d3e2f1a'; + +type SeedExecution = Record; + +type ExecutionHistoryMock = { + journaledRequests: () => Array>; +}; + +function readAdmissionSeed(): SeedExecution { + return { + id: 'e2e-read-admission', + created_at: '2026-06-11T10:00:00.000Z', + status: 'completed', + type: 'agentic-execution:read-measurement', + agentic_execution: { + canonicalType: 'agentic-execution:read-measurement', + lens: 'read', + proofStatus: 'read Need accepted', + closureFocus: 'read measurement + Finding Fits admission', + }, + context: { + source: 'terminal-deposit-read-workbench', + workbench: 'read-admission', + }, + repo_snapshot: { + org: 'bitcode', + repo: 'bitcode', + branch: E2E_BRANCH, + commit: E2E_COMMIT, + }, + output: {}, + items: [], + }; +} + +function settledAssetPackSeed(): SeedExecution { + return { + id: 'e2e-read-settled', + created_at: '2026-06-11T10:05:00.000Z', + status: 'completed', + type: 'agentic-execution:asset-pack', + agentic_execution: { + canonicalType: 'agentic-execution:asset-pack', + lens: 'read', + proofStatus: 'settlement finalized and rights transferred', + closureFocus: 'settlement finality + wallet authority + delivery', + }, + processing_stats: { measuredBtd: 120 }, + context: { + source: 'terminal-deposit-read-workbench', + workbench: 'read-admission', + }, + repo_snapshot: { + org: 'bitcode', + repo: 'bitcode', + branch: E2E_BRANCH, + commit: E2E_COMMIT, + }, + output: {}, + items: [], + }; +} + +async function installExecutionHistoryMock( + page: Page, + seeds: SeedExecution[], +): Promise { + const rows: SeedExecution[] = [...seeds]; + const journaled: Array> = []; + let sequence = 0; + + await page.route('**/api/executions/history**', async (route) => { + if (route.request().method() === 'POST') { + const body = (route.request().postDataJSON() || {}) as Record; + journaled.push(body); + sequence += 1; + const context = (body.context || {}) as Record; + const output = (body.output || {}) as Record; + const repoSnapshot = (output.repo_snapshot || context.repoSnapshot || { + org: 'bitcode', + repo: 'bitcode', + branch: E2E_BRANCH, + commit: E2E_COMMIT, + }) as Record; + const execution: SeedExecution = { + id: `e2e-journal-${sequence}`, + created_at: new Date(2026, 5, 11, 11, sequence).toISOString(), + status: body.status || 'completed', + type: body.pipeline_type || 'agentic-execution:deposit', + agentic_execution: { + canonicalType: body.pipeline_type || 'agentic-execution:deposit', + lens: 'deposit', + proofStatus: String((output.summary as string) || 'journaled'), + closureFocus: String(context.closureFocus || 'deposit posture'), + }, + context, + repo_snapshot: repoSnapshot, + output, + items: body.items || [], + }; + rows.unshift(execution); + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ execution }), + }); + return; + } + + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify(rows), + }); + }); + + return { journaledRequests: () => journaled }; +} + +test.describe('commercial MVP IP exchange browser proof', () => { + test.setTimeout(180_000); + + test.beforeEach(async ({ page }) => { + await installCommercialMvpApiMocks(page); + }); + + test('IP seller deposits an AssetPack: source connection, option synthesis, source-safe review, admission, compensation visibility', async ({ + page, + }, testInfo) => { + const trap = installCommercialBrowserErrorTrap(page, testInfo); + const history = await installExecutionHistoryMock(page, []); + + await page.goto( + `/deposit?provider=github&repo=${encodeURIComponent(E2E_REPOSITORY)}&sourceBranch=${E2E_BRANCH}`, + ); + await expect(page.getByTestId('route-shell-deposit')).toBeVisible({ timeout: 90_000 }); + + // Source connection precedes synthesis: the synthesize action stays + // disabled until the route session resolves a repository source. + const synthesizeButton = page.getByRole('button', { name: 'Synthesize options' }); + await expect(synthesizeButton).toBeEnabled({ timeout: 30_000 }); + + await synthesizeButton.click(); + + // Source-safe measurement review renders before any approval decision. + const optionCard = page.locator('[data-testid^="deposit-option-"]').first(); + await expect(optionCard).toBeVisible({ timeout: 30_000 }); + await expect(optionCard.getByText('BTD potential').first()).toBeVisible(); + await expect(optionCard.getByText('BTC source-to-shares preview').first()).toBeVisible(); + await expect(optionCard.getByText('Option roots').first()).toBeVisible(); + + // Approve for Depository admission and observe admission readback. + await optionCard.getByRole('button', { name: 'Approve for Depository' }).click(); + await expect(optionCard.getByRole('button', { name: 'Approved for Depository' })).toBeVisible({ + timeout: 30_000, + }); + + // Compensation visibility and /packs synchronization remain reachable. + await expect(page.getByText('Recent Deposit activity')).toBeVisible(); + await expect(page.getByRole('link', { name: 'Open pack activity' })).toHaveAttribute( + 'href', + '/packs?type=depository-assetpack', + ); + + // The deposit flow journaled source-safe execution rows: synthesis first, + // then the review/admission decisions. + expect.poll(() => history.journaledRequests().length).toBeGreaterThanOrEqual(2); + const journaledTypes = history + .journaledRequests() + .map((request) => String(request.pipeline_type || '')); + expect(journaledTypes.some((type) => type.includes('deposit-option-synthesis'))).toBe(true); + + await trap.assertClean(); + }); + + test('IP buyer reads measurements, quote basis, settlement finality, BTD rights, and repository delivery on /read', async ({ + page, + }, testInfo) => { + const trap = installCommercialBrowserErrorTrap(page, testInfo); + await installExecutionHistoryMock(page, [settledAssetPackSeed(), readAdmissionSeed()]); + + await page.goto( + `/read?provider=github&repo=${encodeURIComponent(E2E_REPOSITORY)}&sourceBranch=${E2E_BRANCH}&transactionId=e2e-read-settled`, + ); + await expect(page.getByTestId('route-shell-read')).toBeVisible({ timeout: 90_000 }); + + // Five-step buyer session is route-owned. + for (const stepId of [ + 'request-read', + 'review-synthesized-need', + 'request-fit', + 'review-synthesized-asset-pack', + 'buy-asset-pack-settle', + ]) { + await expect(page.getByTestId(`read-route-step-${stepId}`)).toBeVisible(); + } + + // Measurement before price: the fit measurement review renders Need + // coverage through delivery readiness with the final BTD scalar and the + // deterministic BTC-testnet quote basis. + await expect( + page.getByRole('heading', { name: 'Fit measurement review' }), + ).toBeVisible({ timeout: 30_000 }); + await expect(page.getByText('Need coverage', { exact: true })).toBeVisible(); + await expect(page.getByText('Fit confidence', { exact: true })).toBeVisible(); + await expect(page.getByText('Delivery readiness', { exact: true })).toBeVisible(); + await expect(page.getByText('Final BTD scalar', { exact: true })).toBeVisible(); + await expect(page.getByText(/120\s*BTD knowledge-volume/u)).toBeVisible(); + await expect(page.getByText('Quote basis', { exact: true })).toBeVisible(); + await expect(page.getByText(/on btc-testnet/u)).toBeVisible(); + await expect(page.getByText('Selected Fit provenance', { exact: true })).toBeVisible(); + + // Settlement ordering readback: observation, finality, rights, delivery. + await expect( + page.getByRole('heading', { name: 'Settlement, rights, and delivery' }), + ).toBeVisible(); + await expect(page.getByText('btc testnet payment observed')).toBeVisible(); + await expect(page.getByText(/btc testnet finality confirmed/u).first()).toBeVisible(); + await expect(page.getByText(/btd rights transferred/u).first()).toBeVisible(); + await expect(page.getByText(/repository pr delivery materialized/u).first()).toBeVisible(); + + // Proof-backed readback: rights and delivery receipt roots are exposed in + // the expandable source-safe proof detail. + await page.getByText('Reading proof detail', { exact: true }).click(); + const proofDetail = page.getByTestId('read-expandable-proof-detail'); + await expect(proofDetail).toBeVisible(); + await expect(proofDetail.getByText('BTD rights receipt root')).toBeVisible(); + await expect(proofDetail.getByText('Delivery receipt root')).toBeVisible(); + + // Settled AssetPacks remain auditable through /packs. + await expect(page.getByRole('link', { name: 'Open settled pack activity' })).toHaveAttribute( + 'href', + '/packs?type=settled-assetpack', + ); + + await trap.assertClean(); + }); + + test('Pack activity dashboard reads back settlement, BTD rights, compensation, delivery, and the fail-closed repair surface', async ({ + page, + }, testInfo) => { + const trap = installCommercialBrowserErrorTrap(page, testInfo); + + const record = { + id: 'e2e-pack-settled', + type: 'settled-assetpack', + scope: 'network', + title: 'Auth rollback proof pack', + description: 'Settled AssetPack with transferred BTD rights.', + timestamp: '2026-06-11T10:05:00.000Z', + state: 'btd-settled-rights-transferred', + repository: E2E_REPOSITORY, + assetPackTitle: 'Auth rollback proof pack', + settlementState: 'btc-finality-confirmed', + rightsState: 'btd-rights-transferred', + compensationState: 'allocated', + deliveryState: 'repository-pr-delivery-materialized', + repairState: 'not_required', + measurements: [ + { id: 'measured-btd', label: 'Measured btd', value: 120, unit: 'BTD', root: null }, + ], + values: [{ id: 'btc-fee', label: 'Btc fee', amount: 3200, unit: 'sats' }], + accounting: null, + governance: null, + proofRoots: [ + { id: 'rights-root', label: 'Rights receipt root', root: 'read-btd-rights-receipt-e2e' }, + ], + sourceSafety: { + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + sourceSnippetVisible: false, + }, + metadata: {}, + }; + const detail = { + id: record.id, + type: record.type, + title: record.title, + description: record.description, + timestamp: record.timestamp, + sourceSafety: record.sourceSafety, + overview: { + state: record.state, + scope: record.scope, + repository: record.repository, + assetPackTitle: record.assetPackTitle, + }, + measurements: record.measurements, + values: record.values, + accounting: null, + governance: null, + proofRoots: record.proofRoots, + commodityState: { + repairRequired: true, + blockers: ['compensation statement evidence missing'], + }, + states: { + settlement: record.settlementState, + rights: record.rightsState, + compensation: record.compensationState, + delivery: record.deliveryState, + repair: 'repair-required', + }, + telemetry: { + sourceEventId: record.id, + sourceKind: 'execution', + sourceChannel: 'system-surface', + }, + metadata: {}, + }; + + await page.route('**/api/packs/activity**', async (route) => { + await route.fulfill({ + status: 200, + contentType: 'application/json', + body: JSON.stringify({ + ok: true, + records: [record], + detail, + summary: { + total: 1, + types: { 'settled-assetpack': 1 }, + states: { 'btd-settled-rights-transferred': 1 }, + repositories: [E2E_REPOSITORY], + settlementReady: 1, + compensationReady: 1, + deliveryReady: 1, + repairOpen: 1, + }, + }), + }); + }); + + await page.goto('/packs?type=settled-assetpack'); + await expect(page.getByTestId('route-shell-packs')).toBeVisible({ timeout: 90_000 }); + await expect(page.getByText('Auth rollback proof pack').first()).toBeVisible({ + timeout: 30_000, + }); + + // Master-detail state readback tracks the full lifecycle order. + await expect(page.getByText('State readback')).toBeVisible(); + await expect(page.getByText('btc-finality-confirmed').first()).toBeVisible(); + await expect(page.getByText('btd-rights-transferred').first()).toBeVisible(); + await expect(page.getByText('repository-pr-delivery-materialized').first()).toBeVisible(); + + // The fail-closed repair surface lists commodity-state blockers. + await expect(page.getByText('Repair surface')).toBeVisible(); + await expect(page.getByText('compensation statement evidence missing')).toBeVisible(); + + await trap.assertClean(); + }); +});