From be9ace26d67a474267c4280069d0c6c86b109a7d Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Tue, 2 Jun 2026 07:54:27 -0300 Subject: [PATCH] V46 Gate 4: Bind product route comprehension readback Adds V46ProductRouteComprehensionReadback, generated route metadata, checker, package exports, tests, and workflow wiring. Advances V46 spec and roadmap to Gate 4 and binds /packs, /read, and /deposit to source-safe low-detail route readback with expandable proof details and no-source/no-secret boundaries. --- ...-product-route-comprehension-readback.json | 564 ++++++++++++++++++ ...6-protocol-comprehension-object-model.json | 24 +- .../v46-public-operator-claim-boundaries.json | 30 +- .github/workflows/bitcode-canon-quality.yml | 3 + .github/workflows/bitcode-gate-quality.yml | 6 + BITCODE_SPEC_V46.md | 51 +- BITCODE_SPEC_V46_DELTA.md | 26 + BITCODE_SPEC_V46_NOTES.md | 44 ++ BITCODE_SPEC_V46_PARITY_MATRIX.md | 16 +- README.md | 10 + SPECIFICATIONS_ROADMAP.md | 8 +- package.json | 3 + packages/protocol/README.md | 13 + ...46-product-route-comprehension-readback.js | 492 +++++++++++++++ .../v46-public-operator-claim-boundaries.js | 4 +- packages/protocol/src/index.d.ts | 11 + packages/protocol/src/index.js | 13 + ...oduct-route-comprehension-readback.test.js | 92 +++ ...4-product-route-comprehension-readback.mjs | 188 ++++++ ...6-product-route-comprehension-readback.mjs | 30 + 20 files changed, 1585 insertions(+), 43 deletions(-) create mode 100644 .bitcode/v46-product-route-comprehension-readback.json create mode 100644 packages/protocol/src/canonical/v46-product-route-comprehension-readback.js create mode 100644 packages/protocol/test/v46-product-route-comprehension-readback.test.js create mode 100644 scripts/check-v46-gate4-product-route-comprehension-readback.mjs create mode 100644 scripts/generate-v46-product-route-comprehension-readback.mjs diff --git a/.bitcode/v46-product-route-comprehension-readback.json b/.bitcode/v46-product-route-comprehension-readback.json new file mode 100644 index 000000000..6aba53965 --- /dev/null +++ b/.bitcode/v46-product-route-comprehension-readback.json @@ -0,0 +1,564 @@ +{ + "artifactId": "v46-product-route-comprehension-readback", + "artifactPath": ".bitcode/v46-product-route-comprehension-readback.json", + "artifactRoot": "v46-product-route-comprehension-readback:5bc3193c537a60994221614c", + "schemaId": "bitcode.v46.productRouteComprehensionReadback.v1", + "version": "V46", + "currentTarget": "V45", + "sourceSafetyVerdict": "source-safe-product-route-comprehension-readback", + "sourceRoots": { + "activePointer": "BITCODE_SPEC.txt:674f33696f4048b636f67e13", + "spec": "BITCODE_SPEC_V46.md:4cc45d3f347055f6e1c41dfb", + "delta": "BITCODE_SPEC_V46_DELTA.md:d3a9827a2ab22d7586c9068a", + "notes": "BITCODE_SPEC_V46_NOTES.md:ec27a9894f9b42082fce5ceb", + "parity": "BITCODE_SPEC_V46_PARITY_MATRIX.md:fa329d3d950173391cc942b5", + "roadmap": "SPECIFICATIONS_ROADMAP.md:5c6e23123d158007377d52ec", + "packageJson": "package.json:a45f631d26b4b87124be7849", + "packageIndex": "packages/protocol/src/index.js:60ed0a4f219845b39e07e4bb", + "packageTypes": "packages/protocol/src/index.d.ts:1dddeb9bb40d80b131a30ce5", + "packageSource": "packages/protocol/src/canonical/v46-product-route-comprehension-readback.js:373f5861ee772d21f052de38", + "packageTest": "packages/protocol/test/v46-product-route-comprehension-readback.test.js:3118d40ad600a9fb1d025bf6", + "generator": "scripts/generate-v46-product-route-comprehension-readback.mjs:131473a8dcd0d665f74f56a7", + "checker": "scripts/check-v46-gate4-product-route-comprehension-readback.mjs:483822ed6cd2809c20ee8fe5", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:5ce1c8681bb2ef5d0ac25066", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:0b6dfb96c5cbee7d42652666", + "productRouteShell": "uapi/components/base/bitcode/routes/product-route-shell.tsx:e71f90c289dec52fd158568a", + "packsClient": "uapi/app/packs/PacksPageClient.tsx:68c61c8fd312e6c750d742ba", + "packsModel": "uapi/components/base/bitcode/activity/pack-activity-model.ts:88d0334af8bc699e071ca2a1", + "packsApi": "uapi/app/api/packs/activity/route.ts:97c5a4539d48562eb5de66e8", + "packsTest": "uapi/tests/packsPageClient.test.tsx:3fba7a8cabfefd257882490e", + "readClient": "uapi/app/read/ReadPageClient.tsx:860bec675640bf466752bc7e", + "readModel": "uapi/app/read/read-route-model.ts:670e1abd63cccea6365a491f", + "readStepModel": "uapi/app/terminal/terminal-enterprise-reading-ux-state.ts:fb152fb0cc1d0799d1d616d6", + "readClientTest": "uapi/tests/readPageClient.test.tsx:45cea103fa46706d1f39c4f4", + "readModelTest": "uapi/tests/readRouteModel.test.ts:5ad610c538f65fb0c860777f", + "depositClient": "uapi/app/deposit/DepositPageClient.tsx:8526b7980e568ab7d5228e8f", + "depositModel": "uapi/app/deposit/deposit-route-model.ts:6485e388dd745c79907f992c", + "depositClientTest": "uapi/tests/depositPageClient.test.tsx:3385b14ea538e4ea1bb3ed01", + "depositModelTest": "uapi/tests/depositRouteModel.test.ts:3f7377f8c55ce132f970ad09" + }, + "routeIds": [ + "packs", + "read", + "deposit" + ], + "routePaths": [ + "/packs", + "/read", + "/deposit" + ], + "capabilityIds": [ + "low-detail-default", + "route-owned-state", + "search-filter-sort", + "five-step-reading", + "five-step-depositing", + "source-safe-preview", + "expandable-proof-readback", + "keyboard-navigation", + "proof-root-readback", + "settlement-rights-delivery-boundary", + "compensation-readback", + "terminal-debug-compatibility" + ], + "privatePayloadIdsNeverSerialized": [ + "protected-source-payloads", + "unpaid-assetpack-source", + "source-snippets", + "raw-prompts", + "interpolated-prompts", + "raw-provider-responses", + "credentials", + "wallet-private-material", + "private-settlement-payloads", + "private-read-context", + "value-bearing-mainnet-admission" + ], + "routeRows": [ + { + "routeId": "packs", + "routePath": "/packs", + "routeRole": "searchable source-safe PackActivity master-detail and market activity readback", + "sourcePaths": [ + "uapi/app/packs/PacksPageClient.tsx", + "uapi/components/base/bitcode/activity/pack-activity-model.ts", + "uapi/app/api/packs/activity/route.ts", + "uapi/tests/packsPageClient.test.tsx", + "uapi/components/base/bitcode/routes/product-route-shell.tsx" + ], + "claimIds": [ + "assetpack-is-commodity", + "operator-evidence-is-source-safe-readback", + "preview-is-source-safe-measurement", + "finality-authorizes-rights-and-delivery", + "compensation-follows-source-to-shares", + "repair-fails-closed", + "telemetry-is-observability-only" + ], + "claimCategoryIds": [ + "protocol-law", + "product-guidance", + "operator-evidence", + "preview-claim", + "rights-claim", + "compensation-claim", + "repair-claim", + "telemetry-observability" + ], + "authorityIds": [ + "canonical-specification", + "generated-proof", + "ledger-readback", + "database-projection", + "interface-guidance-only" + ], + "capabilityIds": [ + "low-detail-default", + "route-owned-state", + "search-filter-sort", + "source-safe-preview", + "expandable-proof-readback", + "keyboard-navigation", + "proof-root-readback", + "settlement-rights-delivery-boundary", + "compensation-readback" + ], + "requiredCopyTokens": [ + "Pack activity", + "Portfolio positions, market signals, proof roots, settlement, compensation, delivery, repair.", + "Search titles, measurements, values, proof roots", + "Source-safe detail", + "Expandable proof detail", + "packs-enterprise-activity-grid", + "PackActivityRecord" + ], + "readbackRoots": [ + "proofRoots", + "accounting.statementRoot", + "governance.authorityRoot", + "commodityState" + ], + "operatorReading": "/packs is the source-safe master-detail readback for PackActivity, not a source disclosure surface or ledger source of truth.", + "lowDetailDefault": true, + "expandableSourceSafeDetail": true, + "routeOwnedState": true, + "proofReadbackVisible": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetAdmitted": false, + "privatePayloadIdsNeverSerialized": [ + "protected-source-payloads", + "unpaid-assetpack-source", + "source-snippets", + "raw-prompts", + "interpolated-prompts", + "raw-provider-responses", + "credentials", + "wallet-private-material", + "private-settlement-payloads", + "private-read-context", + "value-bearing-mainnet-admission" + ], + "rowRoot": "v46-product-route-row:223c20737781d34d6384de98" + }, + { + "routeId": "read", + "routePath": "/read", + "routeRole": "five-step Reading procurement route from Read Request to settled delivery", + "sourcePaths": [ + "uapi/app/read/ReadPageClient.tsx", + "uapi/app/read/read-route-model.ts", + "uapi/app/terminal/terminal-enterprise-reading-ux-state.ts", + "uapi/tests/readPageClient.test.tsx", + "uapi/tests/readRouteModel.test.ts", + "uapi/components/base/bitcode/routes/product-route-shell.tsx" + ], + "claimIds": [ + "assetpack-is-commodity", + "btd-is-weighted-scalar-volume-and-settled-rights", + "preview-is-source-safe-measurement", + "quote-is-source-safe-offer", + "payment-observation-is-not-finality", + "finality-authorizes-rights-and-delivery", + "delivery-is-entitled-source-unlock", + "operator-evidence-is-source-safe-readback" + ], + "claimCategoryIds": [ + "protocol-law", + "product-guidance", + "preview-claim", + "quote-claim", + "settlement-claim", + "rights-claim", + "delivery-claim", + "operator-evidence" + ], + "authorityIds": [ + "canonical-specification", + "generated-proof", + "ledger-readback", + "wallet-provider-receipt", + "repository-delivery-receipt", + "interface-guidance-only" + ], + "capabilityIds": [ + "low-detail-default", + "route-owned-state", + "five-step-reading", + "source-safe-preview", + "expandable-proof-readback", + "keyboard-navigation", + "proof-root-readback", + "settlement-rights-delivery-boundary", + "terminal-debug-compatibility" + ], + "requiredCopyTokens": [ + "Read request -> Need -> Finding Fits -> Preview -> Settlement.", + "ReadNeedComprehensionSynthesis", + "ReadFitsFindingSynthesis", + "Withheld until paid rights: source-bearing AssetPack contents", + "read-route-step-request-read", + "read-expandable-proof-detail", + "measurement-weight-volume" + ], + "readbackRoots": [ + "readRouteSession.proofRoot", + "budgetPolicy.policyRoot", + "quotePolicy.quoteRoot", + "settlement.readinessRoot", + "authorityRoot" + ], + "operatorReading": "/read keeps the buyer path in five steps and withholds source-bearing AssetPack contents until BTC finality, BTD rights transfer, and entitled delivery readback.", + "lowDetailDefault": true, + "expandableSourceSafeDetail": true, + "routeOwnedState": true, + "proofReadbackVisible": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetAdmitted": false, + "privatePayloadIdsNeverSerialized": [ + "protected-source-payloads", + "unpaid-assetpack-source", + "source-snippets", + "raw-prompts", + "interpolated-prompts", + "raw-provider-responses", + "credentials", + "wallet-private-material", + "private-settlement-payloads", + "private-read-context", + "value-bearing-mainnet-admission" + ], + "rowRoot": "v46-product-route-row:a4fe186278d1ba2c719c18b6" + }, + { + "routeId": "deposit", + "routePath": "/deposit", + "routeRole": "five-step Depositing route from connected source to Depository admission", + "sourcePaths": [ + "uapi/app/deposit/DepositPageClient.tsx", + "uapi/app/deposit/deposit-route-model.ts", + "uapi/tests/depositPageClient.test.tsx", + "uapi/tests/depositRouteModel.test.ts", + "uapi/components/base/bitcode/routes/product-route-shell.tsx" + ], + "claimIds": [ + "assetpack-is-commodity", + "deposit-option-is-potential-supply", + "operator-evidence-is-source-safe-readback", + "compensation-follows-source-to-shares", + "repair-fails-closed", + "telemetry-is-observability-only" + ], + "claimCategoryIds": [ + "protocol-law", + "product-guidance", + "operator-evidence", + "compensation-claim", + "repair-claim", + "telemetry-observability" + ], + "authorityIds": [ + "canonical-specification", + "generated-proof", + "database-projection", + "object-storage-root", + "interface-guidance-only" + ], + "capabilityIds": [ + "low-detail-default", + "route-owned-state", + "five-step-depositing", + "source-safe-preview", + "expandable-proof-readback", + "keyboard-navigation", + "proof-root-readback", + "compensation-readback", + "terminal-debug-compatibility" + ], + "requiredCopyTokens": [ + "Source -> Options -> Review -> Admission -> Depository.", + "DepositAssetPackOptionSynthesis", + "Reviewable AssetPack supply options.", + "Withheld: raw source", + "deposit-route-step-connect-source", + "deposit-expandable-proof-detail", + "Expected compensation" + ], + "readbackRoots": [ + "depositRouteSession.proofRoot", + "synthesis.roots.synthesisRoot", + "policy.roots.policyReportRoot", + "admission.roots.admissionReportRoot", + "earningSupplyIntelligence.roots.intelligenceRoot" + ], + "operatorReading": "/deposit is the source-safe supply route; it forms reviewable options and admission readback without exposing protected source or claiming final Need-relative BTD at option time.", + "lowDetailDefault": true, + "expandableSourceSafeDetail": true, + "routeOwnedState": true, + "proofReadbackVisible": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetAdmitted": false, + "privatePayloadIdsNeverSerialized": [ + "protected-source-payloads", + "unpaid-assetpack-source", + "source-snippets", + "raw-prompts", + "interpolated-prompts", + "raw-provider-responses", + "credentials", + "wallet-private-material", + "private-settlement-payloads", + "private-read-context", + "value-bearing-mainnet-admission" + ], + "rowRoot": "v46-product-route-row:d29d236288eb4794e4699d3f" + } + ], + "coverage": { + "routeCount": 3, + "routeIds": [ + "packs", + "read", + "deposit" + ], + "routePaths": [ + "/packs", + "/read", + "/deposit" + ], + "capabilityIds": [ + "low-detail-default", + "route-owned-state", + "search-filter-sort", + "five-step-reading", + "five-step-depositing", + "source-safe-preview", + "expandable-proof-readback", + "keyboard-navigation", + "proof-root-readback", + "settlement-rights-delivery-boundary", + "compensation-readback", + "terminal-debug-compatibility" + ], + "capabilityIdsUsed": [ + "low-detail-default", + "route-owned-state", + "search-filter-sort", + "source-safe-preview", + "expandable-proof-readback", + "keyboard-navigation", + "proof-root-readback", + "settlement-rights-delivery-boundary", + "compensation-readback", + "five-step-reading", + "terminal-debug-compatibility", + "five-step-depositing" + ], + "claimIdsUsed": [ + "assetpack-is-commodity", + "operator-evidence-is-source-safe-readback", + "preview-is-source-safe-measurement", + "finality-authorizes-rights-and-delivery", + "compensation-follows-source-to-shares", + "repair-fails-closed", + "telemetry-is-observability-only", + "btd-is-weighted-scalar-volume-and-settled-rights", + "quote-is-source-safe-offer", + "payment-observation-is-not-finality", + "delivery-is-entitled-source-unlock", + "deposit-option-is-potential-supply" + ], + "categoryIdsUsed": [ + "protocol-law", + "product-guidance", + "operator-evidence", + "preview-claim", + "rights-claim", + "compensation-claim", + "repair-claim", + "telemetry-observability", + "quote-claim", + "settlement-claim", + "delivery-claim" + ], + "authorityIdsUsed": [ + "canonical-specification", + "generated-proof", + "ledger-readback", + "database-projection", + "interface-guidance-only", + "wallet-provider-receipt", + "repository-delivery-receipt", + "object-storage-root" + ], + "privatePayloadIds": [ + "protected-source-payloads", + "unpaid-assetpack-source", + "source-snippets", + "raw-prompts", + "interpolated-prompts", + "raw-provider-responses", + "credentials", + "wallet-private-material", + "private-settlement-payloads", + "private-read-context", + "value-bearing-mainnet-admission" + ], + "allRoutesCovered": true, + "allRoutePathsCovered": true, + "lowDetailDefaultsCovered": true, + "expandableProofReadbackCovered": true, + "routeOwnedStateCovered": true, + "requiredCapabilitiesCovered": true, + "routeSpecificCapabilitiesCovered": true, + "allClaimIdsKnown": true, + "allCategoryIdsKnown": true, + "allAuthorityIdsKnown": true, + "sourcePredicates": [ + { + "id": "active-pointer-remains-v45", + "sourcePath": "BITCODE_SPEC.txt", + "passed": true + }, + { + "id": "spec-records-route-readback-law", + "sourcePath": "BITCODE_SPEC_V46.md", + "passed": true + }, + { + "id": "delta-records-gate4", + "sourcePath": "BITCODE_SPEC_V46_DELTA.md", + "passed": true + }, + { + "id": "notes-record-gate4", + "sourcePath": "BITCODE_SPEC_V46_NOTES.md", + "passed": true + }, + { + "id": "parity-records-gate4", + "sourcePath": "BITCODE_SPEC_V46_PARITY_MATRIX.md", + "passed": true + }, + { + "id": "roadmap-records-current-gate4", + "sourcePath": "SPECIFICATIONS_ROADMAP.md", + "passed": true + }, + { + "id": "package-source-exists", + "sourcePath": "packages/protocol/src/canonical/v46-product-route-comprehension-readback.js", + "passed": true + }, + { + "id": "package-test-exists", + "sourcePath": "packages/protocol/test/v46-product-route-comprehension-readback.test.js", + "passed": true + }, + { + "id": "generator-exists", + "sourcePath": "scripts/generate-v46-product-route-comprehension-readback.mjs", + "passed": true + }, + { + "id": "checker-exists", + "sourcePath": "scripts/check-v46-gate4-product-route-comprehension-readback.mjs", + "passed": true + }, + { + "id": "package-json-exposes-gate4", + "sourcePath": "package.json", + "passed": true + }, + { + "id": "package-exports-gate4", + "sourcePath": "packages/protocol/src/index.js", + "passed": true + }, + { + "id": "package-types-export-gate4", + "sourcePath": "packages/protocol/src/index.d.ts", + "passed": true + }, + { + "id": "gate-and-canon-workflows-run-gate4", + "sourcePath": ".github/workflows/bitcode-gate-quality.yml", + "passed": true + }, + { + "id": "packs-route-uses-shared-shell", + "sourcePath": "uapi/app/packs/PacksPageClient.tsx", + "passed": true + }, + { + "id": "read-route-uses-five-step-shell", + "sourcePath": "uapi/app/read/ReadPageClient.tsx", + "passed": true + }, + { + "id": "deposit-route-uses-five-step-shell", + "sourcePath": "uapi/app/deposit/DepositPageClient.tsx", + "passed": true + } + ], + "failedPredicateIds": [], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetAdmitted": false, + "forbiddenPhraseHits": [], + "secretMarkerHits": [], + "rowsMissingRequiredCopy": [] + }, + "passed": true, + "closureReading": "V46 Gate 4 closes source-safe route comprehension readback for /packs, /read, and /deposit without changing active V45 canon or admitting value-bearing mainnet operation." +} diff --git a/.bitcode/v46-protocol-comprehension-object-model.json b/.bitcode/v46-protocol-comprehension-object-model.json index b0d3a5c1a..8250b2736 100644 --- a/.bitcode/v46-protocol-comprehension-object-model.json +++ b/.bitcode/v46-protocol-comprehension-object-model.json @@ -8,18 +8,18 @@ "sourceSafetyVerdict": "source-safe-protocol-comprehension-metadata", "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:674f33696f4048b636f67e13", - "spec": "BITCODE_SPEC_V46.md:88f151307f51425c7a75e83e", - "delta": "BITCODE_SPEC_V46_DELTA.md:697e453746a722211efac77d", - "notes": "BITCODE_SPEC_V46_NOTES.md:a1200a8492649c3719945728", - "parity": "BITCODE_SPEC_V46_PARITY_MATRIX.md:b54865e53a2537e4fe07d30e", - "roadmap": "SPECIFICATIONS_ROADMAP.md:8dc49ea14afd5142a2f5d544", - "readme": "README.md:bb5b694da7ceb200a156c238", - "protocolReadme": "packages/protocol/README.md:e6431b343834666a1098989a", - "packageJson": "package.json:25d48242e422647b6b3d744b", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:8e8cc738714773e4d1b67e26", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:1245012ffbcca69b6ed9c4d0", - "packageIndex": "packages/protocol/src/index.js:f1093949979f4a218f646e02", - "packageTypes": "packages/protocol/src/index.d.ts:f423e5dd6568a21c7eefecc2", + "spec": "BITCODE_SPEC_V46.md:4cc45d3f347055f6e1c41dfb", + "delta": "BITCODE_SPEC_V46_DELTA.md:d3a9827a2ab22d7586c9068a", + "notes": "BITCODE_SPEC_V46_NOTES.md:ec27a9894f9b42082fce5ceb", + "parity": "BITCODE_SPEC_V46_PARITY_MATRIX.md:fa329d3d950173391cc942b5", + "roadmap": "SPECIFICATIONS_ROADMAP.md:5c6e23123d158007377d52ec", + "readme": "README.md:316f79e40a6922fa0bf29961", + "protocolReadme": "packages/protocol/README.md:3a3d3a1340fb98b87f722375", + "packageJson": "package.json:a45f631d26b4b87124be7849", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:5ce1c8681bb2ef5d0ac25066", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:0b6dfb96c5cbee7d42652666", + "packageIndex": "packages/protocol/src/index.js:60ed0a4f219845b39e07e4bb", + "packageTypes": "packages/protocol/src/index.d.ts:1dddeb9bb40d80b131a30ce5", "packageSource": "packages/protocol/src/canonical/v46-protocol-comprehension-object-model.js:a55974c399c15656961c7370", "packageTest": "packages/protocol/test/v46-protocol-comprehension-object-model.test.js:b3dd4b276e9c00b76becb15e", "generator": "scripts/generate-v46-protocol-comprehension-object-model.mjs:814f07e809e47d359485ba46", diff --git a/.bitcode/v46-public-operator-claim-boundaries.json b/.bitcode/v46-public-operator-claim-boundaries.json index 406ce5c5d..fa1150af7 100644 --- a/.bitcode/v46-public-operator-claim-boundaries.json +++ b/.bitcode/v46-public-operator-claim-boundaries.json @@ -1,29 +1,29 @@ { "artifactId": "v46-public-operator-claim-boundaries", "artifactPath": ".bitcode/v46-public-operator-claim-boundaries.json", - "artifactRoot": "v46-public-operator-claim-boundaries:cc4ae5c8d5f91d4dcc95994b", + "artifactRoot": "v46-public-operator-claim-boundaries:8058b36a137942405d45bf4d", "schemaId": "bitcode.v46.publicOperatorClaimBoundaries.v1", "version": "V46", "currentTarget": "V45", "sourceSafetyVerdict": "source-safe-public-operator-claim-boundary-metadata", "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:674f33696f4048b636f67e13", - "spec": "BITCODE_SPEC_V46.md:88f151307f51425c7a75e83e", - "delta": "BITCODE_SPEC_V46_DELTA.md:697e453746a722211efac77d", - "notes": "BITCODE_SPEC_V46_NOTES.md:a1200a8492649c3719945728", - "parity": "BITCODE_SPEC_V46_PARITY_MATRIX.md:b54865e53a2537e4fe07d30e", - "roadmap": "SPECIFICATIONS_ROADMAP.md:8dc49ea14afd5142a2f5d544", - "readme": "README.md:bb5b694da7ceb200a156c238", - "protocolReadme": "packages/protocol/README.md:e6431b343834666a1098989a", - "packageJson": "package.json:25d48242e422647b6b3d744b", - "packageIndex": "packages/protocol/src/index.js:f1093949979f4a218f646e02", - "packageTypes": "packages/protocol/src/index.d.ts:f423e5dd6568a21c7eefecc2", - "packageSource": "packages/protocol/src/canonical/v46-public-operator-claim-boundaries.js:0f812e9c2b5d41848fcf609e", + "spec": "BITCODE_SPEC_V46.md:4cc45d3f347055f6e1c41dfb", + "delta": "BITCODE_SPEC_V46_DELTA.md:d3a9827a2ab22d7586c9068a", + "notes": "BITCODE_SPEC_V46_NOTES.md:ec27a9894f9b42082fce5ceb", + "parity": "BITCODE_SPEC_V46_PARITY_MATRIX.md:fa329d3d950173391cc942b5", + "roadmap": "SPECIFICATIONS_ROADMAP.md:5c6e23123d158007377d52ec", + "readme": "README.md:316f79e40a6922fa0bf29961", + "protocolReadme": "packages/protocol/README.md:3a3d3a1340fb98b87f722375", + "packageJson": "package.json:a45f631d26b4b87124be7849", + "packageIndex": "packages/protocol/src/index.js:60ed0a4f219845b39e07e4bb", + "packageTypes": "packages/protocol/src/index.d.ts:1dddeb9bb40d80b131a30ce5", + "packageSource": "packages/protocol/src/canonical/v46-public-operator-claim-boundaries.js:c13ecca31452effec4966ea7", "packageTest": "packages/protocol/test/v46-public-operator-claim-boundaries.test.js:0afae65791ef7d7081b2a87a", "generator": "scripts/generate-v46-public-operator-claim-boundaries.mjs:5a7e5f8c9013c83e3c3818fb", "checker": "scripts/check-v46-gate3-public-operator-claim-boundaries.mjs:b958086681492633958639bf", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:8e8cc738714773e4d1b67e26", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:1245012ffbcca69b6ed9c4d0", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:5ce1c8681bb2ef5d0ac25066", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:0b6dfb96c5cbee7d42652666", "publicCopy": "uapi/components/base/bitcode/layout/bitcode-public-copy.ts:9b39322f872b899e1c752701", "publicExplainers": "uapi/components/base/bitcode/layout/bitcode-public-explainers.ts:4e3b84dda50607ea8ea2b73e", "landingShared": "uapi/app/(root)/components/landing/marketing-landing-shared.tsx:27c33bd46ea46fd7608fd093", @@ -654,7 +654,7 @@ "V46 public/operator claim boundary law", "Gate 3: Public Docs, Landing, And Operator Claim Boundaries", ".bitcode/v46-public-operator-claim-boundaries.json", - "Current working gate: V46 Gate 3 Public Docs, Landing, And Operator Claim Boundaries." + "V46 Gate 3 closure anchor" ], "allowedDataClasses": [ "claim-categories", diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index 7ca11bd7b..f2459cbd8 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -428,6 +428,9 @@ jobs: if [ -f scripts/check-v46-gate3-public-operator-claim-boundaries.mjs ]; then node scripts/check-v46-gate3-public-operator-claim-boundaries.mjs --skip-branch-check --skip-package-tests fi + if [ -f scripts/check-v46-gate4-product-route-comprehension-readback.mjs ]; then + node scripts/check-v46-gate4-product-route-comprehension-readback.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 57a3112cc..abf892c18 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -557,6 +557,9 @@ jobs: if [ -f scripts/check-v46-gate3-public-operator-claim-boundaries.mjs ]; then node scripts/check-v46-gate3-public-operator-claim-boundaries.mjs --skip-branch-check --skip-package-tests fi + if [ -f scripts/check-v46-gate4-product-route-comprehension-readback.mjs ]; then + node scripts/check-v46-gate4-product-route-comprehension-readback.mjs --skip-branch-check --skip-package-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 @@ -604,6 +607,9 @@ jobs: if [ -f BITCODE_SPEC_V46.md ] && [ -f scripts/check-v46-gate3-public-operator-claim-boundaries.mjs ]; then node scripts/check-v46-gate3-public-operator-claim-boundaries.mjs --skip-branch-check --skip-package-tests fi + if [ -f BITCODE_SPEC_V46.md ] && [ -f scripts/check-v46-gate4-product-route-comprehension-readback.mjs ]; then + node scripts/check-v46-gate4-product-route-comprehension-readback.mjs --skip-branch-check --skip-package-tests + fi fi if [ "$POINTER" = "V43" ] && [ -f scripts/check-v44-gate1-scaled-economy-roadmap-opening.mjs ]; then node scripts/check-v44-gate1-scaled-economy-roadmap-opening.mjs --skip-branch-check diff --git a/BITCODE_SPEC_V46.md b/BITCODE_SPEC_V46.md index ed77c064d..46f6473b2 100644 --- a/BITCODE_SPEC_V46.md +++ b/BITCODE_SPEC_V46.md @@ -279,6 +279,42 @@ The source-safe generated artifact for this Gate 3 atom is `.bitcode/v46-public-operator-claim-boundaries.json`; it is generated by `buildV46PublicOperatorClaimBoundaries` and checked by `check:v46-gate3`. +## V46 product route comprehension readback law + +Gate 4: `/packs`, `/read`, And `/deposit` Comprehension UX Readback binds the +three commercial website routes to the Gate 2 claim taxonomy and Gate 3 +public/operator boundaries. These routes may simplify the operator view into a +low-detail default, but each simplification must have expandable source-safe +readback for proof roots, route-owned state, settlement posture, delivery +posture, compensation posture, and repair blockers. + +`/packs` is the searchable PackActivity master-detail surface for source-safe +market and portfolio activity. It may expose PackActivity rows, source-safe +measurements, proof roots, market signals, settlement state, compensation +state, delivery state, repair state, governance readback, and accounting +readback. It must not expose protected source, unpaid AssetPack source, raw +prompts, provider responses, credentials, private settlement payloads, or +wallet private material. + +`/read` is the five-step Reading route: request Read, review synthesized Need, +request Finding Fits, review source-safe AssetPack preview, and buy +AssetPack/settle. It must name `ReadNeedComprehensionSynthesis` and +`ReadFitsFindingSynthesis` as the route-owned pipeline ownership readback, +block Finding Fits until a Need is accepted, keep source-bearing AssetPack +contents withheld before payment, and require BTC finality plus BTD rights and +delivery readback before source unlock. + +`/deposit` is the five-step source-supply route: connect source, synthesize +AssetPack options, review source-safe options, submit deposit, and read +Depository state. It may expose option measurements, demand roots, policy +roots, estimated ROI, BTD potential, and compensation metadata. It must not +claim final Need-relative BTD at option time and must keep raw source withheld +from the product readback boundary. + +The source-safe generated artifact for this Gate 4 atom is +`.bitcode/v46-product-route-comprehension-readback.json`; it is generated by +`buildV46ProductRouteComprehensionReadback` and checked by `check:v46-gate4`. + ## V46 whole Bitcode operator chain The V46 operator chain is: connect source and organization policy, synthesize @@ -772,6 +808,9 @@ and quality summary. | --- | --- | --- | | `.bitcode/v46-spec-family-report.json` | draft spec-family validation report | Gate 1 planned | | `.bitcode/v46-canonical-input-report.json` | draft canonical input report | Gate 1 planned | +| `.bitcode/v46-protocol-comprehension-object-model.json` | protocol comprehension object and claim taxonomy artifact | Gate 2 | +| `.bitcode/v46-public-operator-claim-boundaries.json` | public/operator claim-boundary artifact | Gate 3 | +| `.bitcode/v46-product-route-comprehension-readback.json` | product route comprehension readback artifact | Gate 4 | | `.bitcode/v46-inference-synthesis-proof.json` | inference proof-family artifact | future proof gate | | `.bitcode/v46-prompt-completeness-proof.json` | prompt proof-family artifact | future proof gate | | `.bitcode/v46-static-code-analysis-proof.json` | static-code proof-family artifact | future proof gate | @@ -788,11 +827,14 @@ and quality summary. ### V46 specifying generated artifacts V46 specifying generated artifacts must include `.bitcode/v46-spec-family-report.json`, -`.bitcode/v46-canonical-input-report.json`, all nine V46 proof-family -artifacts, `.bitcode/v46-source-safe-e2e-rehearsal.json`, +`.bitcode/v46-canonical-input-report.json`, +`.bitcode/v46-protocol-comprehension-object-model.json`, +`.bitcode/v46-public-operator-claim-boundaries.json`, +`.bitcode/v46-product-route-comprehension-readback.json`, all nine V46 +proof-family artifacts, `.bitcode/v46-source-safe-e2e-rehearsal.json`, `.bitcode/v46-promotion-readiness-report.json`, and future -`BITCODE_SPEC_V46_PROVEN.md`; each artifact becomes required only when its -own gate closes. +`BITCODE_SPEC_V46_PROVEN.md`; each artifact becomes required only when its own +gate closes. ### Shared generated-artifact fields @@ -843,6 +885,7 @@ Gate 1 validates only active V45 plus draft V46 posture: - `pnpm run check:v46-gate1` - `pnpm run check:v46-gate2` - `pnpm run check:v46-gate3` +- `pnpm run check:v46-gate4` ## V46 promotion canon diff --git a/BITCODE_SPEC_V46_DELTA.md b/BITCODE_SPEC_V46_DELTA.md index c1845e9ed..fe11cbeb0 100644 --- a/BITCODE_SPEC_V46_DELTA.md +++ b/BITCODE_SPEC_V46_DELTA.md @@ -119,6 +119,32 @@ Accepted Gate 3 decisions: - Gate 3 does not authorize runtime, route-state, settlement, delivery, or value-bearing mainnet behavior changes. +## Gate 4: `/packs`, `/read`, And `/deposit` Comprehension UX Readback + +Gate 4 adds `V46ProductRouteComprehensionReadback` as a source-safe generated +artifact at `.bitcode/v46-product-route-comprehension-readback.json`. It binds +the three product routes to Gate 2 claim authority and Gate 3 public/operator +boundaries so route UX can stay low-detail by default while preserving +expandable proof readback. + +Accepted Gate 4 decisions: + +- `/packs` is the searchable PackActivity master-detail readback for + source-safe market, portfolio, settlement, compensation, delivery, repair, + governance, and proof-root activity. +- `/read` remains the five-step Reading route: request Read, review + synthesized Need, request Finding Fits, review source-safe AssetPack preview, + and buy/settle. +- `/deposit` remains the five-step source-supply route: connect source, + synthesize AssetPack options, review source-safe options, submit deposit, and + read Depository state. +- Low-detail route summaries are allowed only when expandable source-safe + detail preserves route-owned state, proof roots, disclosure boundaries, and + repair blockers. +- Gate 4 does not expose protected source, unpaid AssetPack source, raw + prompts, raw provider responses, credentials, wallet private material, + private settlement payloads, or value-bearing mainnet authority. + ## Commit-Body Direction V46 commit bodies should name the gate class, protocol law or interface claim diff --git a/BITCODE_SPEC_V46_NOTES.md b/BITCODE_SPEC_V46_NOTES.md index 3e5300540..974a2ab3a 100644 --- a/BITCODE_SPEC_V46_NOTES.md +++ b/BITCODE_SPEC_V46_NOTES.md @@ -101,6 +101,50 @@ operator notes. It remains draft-target metadata over active V45: no route behavior, API behavior, settlement behavior, delivery behavior, source disclosure, or value-bearing mainnet admission is authorized by this gate. +## Gate 4: `/packs`, `/read`, And `/deposit` Comprehension UX Readback + +Gate 4 records the product-route comprehension atom. It creates a source-safe +route readback artifact for `/packs`, `/read`, and `/deposit`. It remains +draft-target metadata over active V45: it may audit and clarify route copy, +state labels, readback roots, and tests, but it does not authorize source +disclosure, payment finality, delivery, or value-bearing mainnet admission. + +## V46 product route comprehension atom: route readback for Packs, Reading, and Depositing + +Audit classification: V43 through V45 created the route-product skeleton and +economic law, but product routes still need one V46 comprehension contract that +binds their low-detail UX to proof readback. The route should be easy to scan +in collapsed/default form, while every commercial claim must remain expandable +to source-safe proof, route-owned state, and repair posture. + +Product-route law: + +`/packs` is the searchable PackActivity master-detail surface. It is allowed +to show rows, filters, sorting, source-safe measurements, proof roots, +settlement state, compensation state, delivery state, repair state, governance +readback, accounting readback, portfolio positions, and market signals. It is +not a source disclosure surface and cannot override ledger or proof readback. + +`/read` is the five-step Reading route. It moves from Read Request to reviewed +Need, Finding Fits, source-safe AssetPack preview, and buy/settle. It must name +`ReadNeedComprehensionSynthesis` and `ReadFitsFindingSynthesis`, preserve the +accepted-Need blocker before Finding Fits, show preview and quote metadata +without source, and keep source-bearing AssetPack contents withheld until BTC +finality, BTD rights transfer, and entitled repository delivery. + +`/deposit` is the five-step source-supply route. It moves from connected +source to AssetPack option synthesis, source-safe option review, deposit +submission, and Depository state readback. It may show measurements, demand +roots, policy roots, estimated ROI, BTD potential, and compensation metadata. +It must not claim final Need-relative BTD or expose raw source at option time. + +Acceptance for this atom: `V46ProductRouteComprehensionReadback` must bind +`/packs`, `/read`, and `/deposit` route ids, route paths, low-detail defaults, +route-owned state, search/filter/sort, Reading and Depositing five-step flows, +expandable proof readback, source-safe disclosure exclusions, package exports, +generated artifact freshness, workflow wiring, and focused protocol tests. The +artifact path is `.bitcode/v46-product-route-comprehension-readback.json`. + ## V46 public/operator claim-boundary atom: public/operator claim boundaries Audit classification: Gate 2 defines the typed claim taxonomy, but public and diff --git a/BITCODE_SPEC_V46_PARITY_MATRIX.md b/BITCODE_SPEC_V46_PARITY_MATRIX.md index 7ac8a0906..4c8c69acf 100644 --- a/BITCODE_SPEC_V46_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V46_PARITY_MATRIX.md @@ -62,7 +62,7 @@ source files and generated artifacts that implement or explain each row. | Commercial protocol comprehension | Explain Bitcode as knowledge commoditization without reducing BTD to a read-right or AssetPack to raw source | draft-required | V45 law is precise but launch-facing surfaces need a shared claim taxonomy and readback language. | Gate 2 | | Claim taxonomy | Separate protocol law, product guidance, operator evidence, investor framing, telemetry, preview, quote, settlement, rights, delivery, compensation, and repair claims | implemented prerequisite | Gate 2 owns package-backed `V46ProtocolComprehensionObjectModel`, deterministic `.bitcode/v46-protocol-comprehension-object-model.json`, object rows, claim rows, evidence-specific authority ids, disclosure boundary ids, forbidden claim collapse ids, source-safe generated artifact freshness, protocol tests, docs, and workflow wiring. | Gate 2 | | Public and operator docs | Public docs, landing copy, README/operator docs, and route help stay accurate, source-safe, and non-overclaiming | implemented prerequisite | Gate 3 owns package-backed `V46PublicOperatorClaimBoundaries`, deterministic `.bitcode/v46-public-operator-claim-boundaries.json`, public docs, landing, operator docs, README anchors, protocol docs compatibility alias, forbidden overclaim scans, source-safety exclusions, focused tests, package exports, and workflow wiring. | Gate 3 | -| Product route comprehension | `/packs`, `/read`, and `/deposit` expose low-detail default UX with expandable proof and consistent commercial terms | implemented prerequisite | V43-V45 product routes exist; V46 must audit copy, state labels, and proof readback against commercial comprehension. | Gate 4 | +| Product route comprehension | `/packs`, `/read`, and `/deposit` expose low-detail default UX with expandable proof and consistent commercial terms | implemented prerequisite | Gate 4 owns package-backed `V46ProductRouteComprehensionReadback`, deterministic `.bitcode/v46-product-route-comprehension-readback.json`, route ids, route paths, low-detail defaults, route-owned state, Packs search/filter/sort, Reading five-step readback, Depositing five-step readback, source-safe proof detail, package exports, focused tests, and workflow wiring. | Gate 4 | | Machine and conversation interfaces | API/MCP, ChatGPT App, Bitcode Chat, and package consumers expose the same claim boundaries as website routes | draft-required | Prior interface parity exists, but V46 needs launch-facing readback contracts. | Gate 5 | | Proof readback explanation | Users and operators can understand why proof, ledger, database, storage, wallet/provider, and repository receipts have different authority | draft-required | V45 requires proof-backed state advancement; V46 must make it externally legible. | Gate 6 | | Local interface rehearsal | A source-safe local rehearsal verifies docs/routes/interfaces explain the protocol without exposing unpaid source | pending | No V46 rehearsal is authorized in Gate 1. | Gate 7 | @@ -80,6 +80,7 @@ source files and generated artifacts that implement or explain each row. | Implementation scope | Runtime work begins only after formal specification and parity gates authorize it | accepted boundary | Gate 1 is roadmap/spec/checking only. | Gate 4+ | | Protocol comprehension object model | V46 explanation surfaces share object ids, claim categories, claim authority ids, disclosure boundaries, and forbidden interpretation ids | implemented prerequisite | `V46ProtocolComprehensionObjectModel` binds AssetPack, BTD, BTC, preview, quote, settlement, rights, delivery, compensation, proof, repair, and InterfaceClaim rows without source-bearing payloads. | Gate 2 | | Public/operator claim-boundary artifact | Public and operator surfaces expose only source-safe guidance and proof posture while avoiding stale vocabulary and overclaims | implemented prerequisite | `V46PublicOperatorClaimBoundaries` binds landing, docs home, docs content, docs protocol page, operator README, root README, package README, and V46 spec-family rows to required copy anchors, claim authorities, forbidden overclaim scans, and `.bitcode/v46-public-operator-claim-boundaries.json`. | Gate 3 | +| Product route comprehension readback artifact | `/packs`, `/read`, and `/deposit` expose route-specific source-safe readback without collapsing preview, quote, finality, delivery, compensation, or repair claims | implemented prerequisite | `V46ProductRouteComprehensionReadback` binds route rows to claim ids, authority ids, required copy anchors, low-detail defaults, expandable proof readback, route-owned state, no-source/no-secret checks, and `.bitcode/v46-product-route-comprehension-readback.json`. | Gate 4 | ## Grouped Closure Gates @@ -112,11 +113,12 @@ more maintainable closure order. ## Current completion condition -V46 Gate 3 is complete when `V46PublicOperatorClaimBoundaries`, -`.bitcode/v46-public-operator-claim-boundaries.json`, public docs, landing -copy, operator docs, README anchors, route compatibility docs, package exports, -workflow checks, focused tests, and `check:v46-gate3` validate active V45 plus -draft V46 and the gate branch is committed, pushed, and pull-requested into -`version/v46`. +V46 Gate 4 is complete when `V46ProductRouteComprehensionReadback`, +`.bitcode/v46-product-route-comprehension-readback.json`, `/packs`, `/read`, +and `/deposit` route readback anchors, package exports, workflow checks, +focused tests, and `check:v46-gate4` validate active V45 plus draft V46 and +the gate branch is committed, pushed, and pull-requested into `version/v46`. + +Historical Gate 3 completion condition: V46 Gate 3 is complete when `V46PublicOperatorClaimBoundaries`, `.bitcode/v46-public-operator-claim-boundaries.json`, public docs, landing copy, operator docs, README anchors, route compatibility docs, package exports, workflow checks, focused tests, and `check:v46-gate3` validate active V45 plus draft V46 and the gate branch is committed, pushed, and pull-requested into `version/v46`. Historical Gate 1 completion condition: V46 Gate 1 is complete when the V46 draft spec family, roadmap, package script, Gate 1 checker, and CI workflow hooks validate active V45 plus draft V46 and the gate branch is committed, pushed, and pull-requested into `version/v46`. diff --git a/README.md b/README.md index f65b60e16..f42e86a6a 100644 --- a/README.md +++ b/README.md @@ -30,6 +30,16 @@ keeping protected source, unpaid AssetPack source, raw prompts, raw provider responses, credentials, wallet private material, and value-bearing mainnet operation out of generated metadata. +V46 Gate 4 adds `V46ProductRouteComprehensionReadback` through +`packages/protocol/src/canonical/v46-product-route-comprehension-readback.js`, +`.bitcode/v46-product-route-comprehension-readback.json`, +`generate:v46-product-route-comprehension-readback`, +`check:v46-product-route-comprehension-readback`, and `check:v46-gate4`. It +binds `/packs`, `/read`, and `/deposit` to low-detail route defaults, +route-owned state, searchable PackActivity readback, Reading and Depositing +five-step flows, expandable proof detail, settlement/delivery boundaries, +compensation readback, and no-source/no-secret route metadata. + V41 Gate 1 opens the prompts-as-programs specification family over active V40 with `check:v41-gate1`. V41 will catalogue every raw PromptPart and composed Prompt, map registry composition and interpolation contracts, benchmark Reading diff --git a/SPECIFICATIONS_ROADMAP.md b/SPECIFICATIONS_ROADMAP.md index 26a5ffcef..9ff458080 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -5,9 +5,9 @@ - Current active canonical pointer: `BITCODE_SPEC.txt` -> `V45` - Current active canon: `BITCODE_SPEC_V45.md` - Current draft target: `BITCODE_SPEC_V46.md` -- Current working gate: V46 Gate 3 Public Docs, Landing, And Operator Claim Boundaries. -- Next queued work after V46 Gate 3: V46 Gate 4 `/packs`, `/read`, And `/deposit` Comprehension UX Readback. -- Latest closed gate: V46 Gate 2 Protocol Comprehension Object Model And Claim Taxonomy, which added `V46ProtocolComprehensionObjectModel`, `.bitcode/v46-protocol-comprehension-object-model.json`, Gate 2 claim taxonomy law, package exports, focused tests, docs, workflow wiring, and `check:v46-gate2`. +- Current working gate: V46 Gate 4 `/packs`, `/read`, And `/deposit` Comprehension UX Readback. +- Next queued work after V46 Gate 4: V46 Gate 5 API/MCP, ChatGPT App, And Bitcode Chat Claim Contracts. +- Latest closed gate: V46 Gate 3 Public Docs, Landing, And Operator Claim Boundaries, which added `V46PublicOperatorClaimBoundaries`, `.bitcode/v46-public-operator-claim-boundaries.json`, public/operator claim boundary law, public docs and landing copy updates, README/operator docs anchors, protocol docs compatibility alias, package exports, focused tests, workflow wiring, and `check:v46-gate3`. - 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`. @@ -15,6 +15,8 @@ - V46 Gate 2 closure anchor: Gate 2 is closed when AssetPack, BTD scalar-volume, BTC quote/settlement, source unlock delivery, source-to-shares compensation, proof, repair, and `InterfaceClaim` objects are source-safe; claim categories distinguish protocol law, product guidance, operator evidence, investor framing, telemetry, preview, quote, settlement, rights, delivery, compensation, and repair; forbidden claim collapses are modeled; the generated artifact is fresh; focused protocol tests pass; gate/canon workflows run the checker; and the gate branch is committed, pushed, and pull-requested into `version/v46`. - V46 Gate 3 closure target: add package-backed `V46PublicOperatorClaimBoundaries`, deterministic `.bitcode/v46-public-operator-claim-boundaries.json`, public docs, landing, operator docs, README anchors, protocol docs compatibility alias, source-safe forbidden overclaim scans, workflow wiring, focused tests, and `check:v46-gate3` while preserving `BITCODE_SPEC.txt` -> `V45`. - V46 Gate 3 closure anchor: Gate 3 is closed when public docs, landing copy, README/operator docs, and route docs explain AssetPack, BTD scalar volume and rights, BTC settlement, proof readback, and route compatibility without stale Source Shares/Exchange-first framing or overclaiming; operator notes may name proof roots but not secret values; generated metadata is fresh and source-safe; focused public docs/protocol tests pass; gate/canon workflows run the checker; and the gate branch is committed, pushed, and pull-requested into `version/v46`. +- V46 Gate 4 closure target: add package-backed `V46ProductRouteComprehensionReadback`, deterministic `.bitcode/v46-product-route-comprehension-readback.json`, `/packs`, `/read`, and `/deposit` source-safe route readback rows, low-detail defaults, route-owned state, expandable proof detail, workflow wiring, focused tests, and `check:v46-gate4` while preserving `BITCODE_SPEC.txt` -> `V45`. +- V46 Gate 4 closure anchor: Gate 4 is closed when `/packs` binds searchable PackActivity master-detail readback; `/read` binds the five-step Reading route, `ReadNeedComprehensionSynthesis`, `ReadFitsFindingSynthesis`, source-safe preview, quote, BTC settlement, BTD rights, and delivery boundary; `/deposit` binds the five-step source-supply route, option synthesis, source-safe option review, admission, Depository state, and compensation metadata; generated metadata is fresh and source-safe; focused route/protocol tests pass; gate/canon workflows run the checker; and the gate branch is committed, pushed, and pull-requested into `version/v46`. - V45 Gate 18 closure anchor: promotion readiness closed with a source-safe artifact, `BITCODE_SPEC_V45_PROVEN.md`, V45 promotion workflow, promotion dry-run, gate/canon workflow posture, package exports, tests, docs, and `check:v45-gate18` current and green. - Latest closed version: V43 Route Product Cleanup, which promoted `/packs`, `/read`, and `/deposit`; PackActivity master-detail; five-step Reading route UX; deposit AssetPack option synthesis; deposit criticality/ROI/compensation policy; option admission; product route UX; cross-route rehearsal; and V43 promotion readiness. - Recent V43 canonical promotion anchor: V43 canonical promotion updated `BITCODE_SPEC.txt` to `V43`, generated `BITCODE_SPEC_V43_PROVEN.md`, preserved active V43 / draft V44 runtime posture, and closed route-product cleanup canon. diff --git a/package.json b/package.json index a409552e9..e5ad9244c 100644 --- a/package.json +++ b/package.json @@ -419,6 +419,9 @@ "generate:v46-public-operator-claim-boundaries": "node scripts/generate-v46-public-operator-claim-boundaries.mjs", "check:v46-public-operator-claim-boundaries": "node scripts/generate-v46-public-operator-claim-boundaries.mjs --check", "check:v46-gate3": "node scripts/check-v46-gate3-public-operator-claim-boundaries.mjs", + "generate:v46-product-route-comprehension-readback": "node scripts/generate-v46-product-route-comprehension-readback.mjs", + "check:v46-product-route-comprehension-readback": "node scripts/generate-v46-product-route-comprehension-readback.mjs --check", + "check:v46-gate4": "node scripts/check-v46-gate4-product-route-comprehension-readback.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/README.md b/packages/protocol/README.md index 4631f214b..7fb0ff52d 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -66,6 +66,7 @@ Current exported commercial helpers include: - `V43RouteVocabularyInventory` helpers for V43 source-safe route vocabulary inventory, source-safe file/token counts, `/exchange` to `/packs` planning, `/terminal` to `/read` and `/deposit` planning, retained debug cockpit boundary, redirect compatibility, self-referential copy cleanup, and migration matrix proof; - `V43PacksActivityMasterDetail` helpers for V43 source-safe PackActivity contracts, `/api/packs/activity`, `/packs` master-detail search/filter/sort/detail projection, proof roots, settlement/compensation/delivery/repair readback, and `/exchange` compatibility redirection; - `V46PublicOperatorClaimBoundaries` helpers for V46 source-safe public/operator claim boundary metadata across public docs, landing, operator docs, README surfaces, workflow checks, and forbidden overclaim scans; +- `V46ProductRouteComprehensionReadback` helpers for V46 source-safe `/packs`, `/read`, and `/deposit` route comprehension metadata, low-detail defaults, expandable proof readback, route-owned state, and forbidden product-route overclaim scans; - canonical proven-generation helpers; - the package app/server context used by commercial interfaces. @@ -352,6 +353,18 @@ forbidden overclaim scans without serializing protected source, unpaid AssetPack source, raw prompts, raw provider responses, credentials, wallet private material, or value-bearing mainnet authority. +V46 Gate 4 adds `V46ProductRouteComprehensionReadback` through +`packages/protocol/src/canonical/v46-product-route-comprehension-readback.js`, +`packages/protocol/test/v46-product-route-comprehension-readback.test.js`, +`.bitcode/v46-product-route-comprehension-readback.json`, +`generate:v46-product-route-comprehension-readback`, +`check:v46-product-route-comprehension-readback`, and `check:v46-gate4`. It +binds `/packs`, `/read`, and `/deposit` to source-safe low-detail defaults, +route-owned state, expandable proof readback, Reading and Depositing five-step +flows, Packs search/filter/sort, proof-root readback, settlement/delivery +boundaries, contributor compensation readback, and no-source/no-secret product +route scans. + Historical V39 promotion moved this package through the `V39` active, `V40` draft posture. V40 promotion has since advanced the current package posture to `V40` active, `V41` draft. diff --git a/packages/protocol/src/canonical/v46-product-route-comprehension-readback.js b/packages/protocol/src/canonical/v46-product-route-comprehension-readback.js new file mode 100644 index 000000000..5269e2f8e --- /dev/null +++ b/packages/protocol/src/canonical/v46-product-route-comprehension-readback.js @@ -0,0 +1,492 @@ +// @ts-check + +import crypto from 'node:crypto'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +import { + V46_PROTOCOL_CLAIM_AUTHORITY_IDS, + V46_PROTOCOL_CLAIM_CATEGORY_IDS, + V46_PROTOCOL_CLAIM_ROWS, + V46_PROTOCOL_PRIVATE_PAYLOAD_IDS, +} from './v46-protocol-comprehension-object-model.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const DEFAULT_REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..'); + +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH = + '.bitcode/v46-product-route-comprehension-readback.json'; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SCHEMA_ID = + 'bitcode.v46.productRouteComprehensionReadback.v1'; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_VERSION = 'V46'; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_CURRENT_TARGET = 'V45'; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_SAFETY_VERDICT = + 'source-safe-product-route-comprehension-readback'; + +export const V46_PRODUCT_ROUTE_IDS = Object.freeze(['packs', 'read', 'deposit']); +export const V46_PRODUCT_ROUTE_PATHS = Object.freeze(['/packs', '/read', '/deposit']); +export const V46_PRODUCT_ROUTE_CAPABILITY_IDS = Object.freeze([ + 'low-detail-default', + 'route-owned-state', + 'search-filter-sort', + 'five-step-reading', + 'five-step-depositing', + 'source-safe-preview', + 'expandable-proof-readback', + 'keyboard-navigation', + 'proof-root-readback', + 'settlement-rights-delivery-boundary', + 'compensation-readback', + 'terminal-debug-compatibility', +]); + +const SOURCE_PATHS = Object.freeze({ + activePointer: 'BITCODE_SPEC.txt', + spec: 'BITCODE_SPEC_V46.md', + delta: 'BITCODE_SPEC_V46_DELTA.md', + notes: 'BITCODE_SPEC_V46_NOTES.md', + parity: 'BITCODE_SPEC_V46_PARITY_MATRIX.md', + roadmap: 'SPECIFICATIONS_ROADMAP.md', + packageJson: 'package.json', + packageIndex: 'packages/protocol/src/index.js', + packageTypes: 'packages/protocol/src/index.d.ts', + packageSource: 'packages/protocol/src/canonical/v46-product-route-comprehension-readback.js', + packageTest: 'packages/protocol/test/v46-product-route-comprehension-readback.test.js', + generator: 'scripts/generate-v46-product-route-comprehension-readback.mjs', + checker: 'scripts/check-v46-gate4-product-route-comprehension-readback.mjs', + gateWorkflow: '.github/workflows/bitcode-gate-quality.yml', + canonWorkflow: '.github/workflows/bitcode-canon-quality.yml', + productRouteShell: 'uapi/components/base/bitcode/routes/product-route-shell.tsx', + packsClient: 'uapi/app/packs/PacksPageClient.tsx', + packsModel: 'uapi/components/base/bitcode/activity/pack-activity-model.ts', + packsApi: 'uapi/app/api/packs/activity/route.ts', + packsTest: 'uapi/tests/packsPageClient.test.tsx', + readClient: 'uapi/app/read/ReadPageClient.tsx', + readModel: 'uapi/app/read/read-route-model.ts', + readStepModel: 'uapi/app/terminal/terminal-enterprise-reading-ux-state.ts', + readClientTest: 'uapi/tests/readPageClient.test.tsx', + readModelTest: 'uapi/tests/readRouteModel.test.ts', + depositClient: 'uapi/app/deposit/DepositPageClient.tsx', + depositModel: 'uapi/app/deposit/deposit-route-model.ts', + depositClientTest: 'uapi/tests/depositPageClient.test.tsx', + depositModelTest: 'uapi/tests/depositRouteModel.test.ts', +}); + +const SECRET_MARKERS = Object.freeze([ + `${['sk', 'proj'].join('-')}-`, + `${['sb', 'secret'].join('_')}__`, + ['service', 'role'].join('_'), + ['eyJhbGciOiJI', 'UzI1NiIsInR5cCI6IkpXVCJ9'].join(''), + ['SUPABASE', 'SERVICE', 'ROLE'].join('_'), + ['OPENAI', 'API', 'KEY'].join('_'), + ['VERCEL', 'TOKEN'].join('_'), + ['VERCEL', 'OIDC', 'TOKEN'].join('_'), + ['PRIVATE', 'KEY'].join('_'), +]); + +const FORBIDDEN_PRODUCT_ROUTE_PHRASES = Object.freeze([ + 'Source Shares and the Bitcode Exchange', + 'Learn Bitcode from Source Shares to proof', + 'BTD is money', + 'BTD is only a read right', + 'preview discloses source', + 'quote is payment', + 'payment observation is finality', + 'database is ledger truth', + 'telemetry advances state', + 'server custodies wallet private material', + 'value-bearing mainnet operation is live', +]); + +function digest(value) { + return crypto.createHash('sha256').update(value).digest('hex').slice(0, 24); +} + +function readSource(repoRoot, sourcePath) { + const absolutePath = path.join(repoRoot, sourcePath); + return existsSync(absolutePath) ? readFileSync(absolutePath, 'utf8') : ''; +} + +function sourceExists(repoRoot, sourcePath) { + return existsSync(path.join(repoRoot, sourcePath)); +} + +function sourceRoot(repoRoot, sourcePath) { + return `${sourcePath}:${digest(readSource(repoRoot, sourcePath))}`; +} + +function predicateResult(id, sourcePath, passed) { + return { id, sourcePath, passed: Boolean(passed) }; +} + +function scanSourcesForMarkers(repoRoot, sourcePaths, markers) { + const joined = sourcePaths.map((sourcePath) => readSource(repoRoot, sourcePath)).join('\n'); + return markers.filter((marker) => marker && joined.includes(marker)); +} + +function claimExists(claimId) { + return V46_PROTOCOL_CLAIM_ROWS.some((row) => row.claimId === claimId); +} + +function categoryExists(categoryId) { + return V46_PROTOCOL_CLAIM_CATEGORY_IDS.includes(categoryId); +} + +function authorityExists(authorityId) { + return V46_PROTOCOL_CLAIM_AUTHORITY_IDS.includes(authorityId); +} + +function requiredTokensPresent(repoRoot, row) { + const joined = row.sourcePaths.map((sourcePath) => readSource(repoRoot, sourcePath)).join('\n'); + return row.requiredCopyTokens.every((token) => joined.includes(token)); +} + +function routeRow({ + routeId, + routePath, + routeRole, + sourcePaths, + claimIds, + claimCategoryIds, + authorityIds, + capabilityIds, + requiredCopyTokens, + readbackRoots, + operatorReading, +}) { + return { + routeId, + routePath, + routeRole, + sourcePaths, + claimIds, + claimCategoryIds, + authorityIds, + capabilityIds, + requiredCopyTokens, + readbackRoots, + operatorReading, + lowDetailDefault: true, + expandableSourceSafeDetail: true, + routeOwnedState: true, + proofReadbackVisible: true, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + credentialsSerialized: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + valueBearingMainnetAdmitted: false, + privatePayloadIdsNeverSerialized: [...V46_PROTOCOL_PRIVATE_PAYLOAD_IDS], + rowRoot: `v46-product-route-row:${digest(JSON.stringify({ routeId, sourcePaths, capabilityIds, readbackRoots }))}`, + }; +} + +export const V46_PRODUCT_ROUTE_READBACK_ROWS = Object.freeze([ + routeRow({ + routeId: 'packs', + routePath: '/packs', + routeRole: 'searchable source-safe PackActivity master-detail and market activity readback', + sourcePaths: [SOURCE_PATHS.packsClient, SOURCE_PATHS.packsModel, SOURCE_PATHS.packsApi, SOURCE_PATHS.packsTest, SOURCE_PATHS.productRouteShell], + claimIds: [ + 'assetpack-is-commodity', + 'operator-evidence-is-source-safe-readback', + 'preview-is-source-safe-measurement', + 'finality-authorizes-rights-and-delivery', + 'compensation-follows-source-to-shares', + 'repair-fails-closed', + 'telemetry-is-observability-only', + ], + claimCategoryIds: [ + 'protocol-law', + 'product-guidance', + 'operator-evidence', + 'preview-claim', + 'rights-claim', + 'compensation-claim', + 'repair-claim', + 'telemetry-observability', + ], + authorityIds: ['canonical-specification', 'generated-proof', 'ledger-readback', 'database-projection', 'interface-guidance-only'], + capabilityIds: [ + 'low-detail-default', + 'route-owned-state', + 'search-filter-sort', + 'source-safe-preview', + 'expandable-proof-readback', + 'keyboard-navigation', + 'proof-root-readback', + 'settlement-rights-delivery-boundary', + 'compensation-readback', + ], + requiredCopyTokens: [ + 'Pack activity', + 'Portfolio positions, market signals, proof roots, settlement, compensation, delivery, repair.', + 'Search titles, measurements, values, proof roots', + 'Source-safe detail', + 'Expandable proof detail', + 'packs-enterprise-activity-grid', + 'PackActivityRecord', + ], + readbackRoots: ['proofRoots', 'accounting.statementRoot', 'governance.authorityRoot', 'commodityState'], + operatorReading: + '/packs is the source-safe master-detail readback for PackActivity, not a source disclosure surface or ledger source of truth.', + }), + routeRow({ + routeId: 'read', + routePath: '/read', + routeRole: 'five-step Reading procurement route from Read Request to settled delivery', + sourcePaths: [ + SOURCE_PATHS.readClient, + SOURCE_PATHS.readModel, + SOURCE_PATHS.readStepModel, + SOURCE_PATHS.readClientTest, + SOURCE_PATHS.readModelTest, + SOURCE_PATHS.productRouteShell, + ], + claimIds: [ + 'assetpack-is-commodity', + 'btd-is-weighted-scalar-volume-and-settled-rights', + 'preview-is-source-safe-measurement', + 'quote-is-source-safe-offer', + 'payment-observation-is-not-finality', + 'finality-authorizes-rights-and-delivery', + 'delivery-is-entitled-source-unlock', + 'operator-evidence-is-source-safe-readback', + ], + claimCategoryIds: [ + 'protocol-law', + 'product-guidance', + 'preview-claim', + 'quote-claim', + 'settlement-claim', + 'rights-claim', + 'delivery-claim', + 'operator-evidence', + ], + authorityIds: [ + 'canonical-specification', + 'generated-proof', + 'ledger-readback', + 'wallet-provider-receipt', + 'repository-delivery-receipt', + 'interface-guidance-only', + ], + capabilityIds: [ + 'low-detail-default', + 'route-owned-state', + 'five-step-reading', + 'source-safe-preview', + 'expandable-proof-readback', + 'keyboard-navigation', + 'proof-root-readback', + 'settlement-rights-delivery-boundary', + 'terminal-debug-compatibility', + ], + requiredCopyTokens: [ + 'Read request -> Need -> Finding Fits -> Preview -> Settlement.', + 'ReadNeedComprehensionSynthesis', + 'ReadFitsFindingSynthesis', + 'Withheld until paid rights: source-bearing AssetPack contents', + 'read-route-step-request-read', + 'read-expandable-proof-detail', + 'measurement-weight-volume', + ], + readbackRoots: ['readRouteSession.proofRoot', 'budgetPolicy.policyRoot', 'quotePolicy.quoteRoot', 'settlement.readinessRoot', 'authorityRoot'], + operatorReading: + '/read keeps the buyer path in five steps and withholds source-bearing AssetPack contents until BTC finality, BTD rights transfer, and entitled delivery readback.', + }), + routeRow({ + routeId: 'deposit', + routePath: '/deposit', + routeRole: 'five-step Depositing route from connected source to Depository admission', + sourcePaths: [ + SOURCE_PATHS.depositClient, + SOURCE_PATHS.depositModel, + SOURCE_PATHS.depositClientTest, + SOURCE_PATHS.depositModelTest, + SOURCE_PATHS.productRouteShell, + ], + claimIds: [ + 'assetpack-is-commodity', + 'deposit-option-is-potential-supply', + 'operator-evidence-is-source-safe-readback', + 'compensation-follows-source-to-shares', + 'repair-fails-closed', + 'telemetry-is-observability-only', + ], + claimCategoryIds: ['protocol-law', 'product-guidance', 'operator-evidence', 'compensation-claim', 'repair-claim', 'telemetry-observability'], + authorityIds: ['canonical-specification', 'generated-proof', 'database-projection', 'object-storage-root', 'interface-guidance-only'], + capabilityIds: [ + 'low-detail-default', + 'route-owned-state', + 'five-step-depositing', + 'source-safe-preview', + 'expandable-proof-readback', + 'keyboard-navigation', + 'proof-root-readback', + 'compensation-readback', + 'terminal-debug-compatibility', + ], + requiredCopyTokens: [ + 'Source -> Options -> Review -> Admission -> Depository.', + 'DepositAssetPackOptionSynthesis', + 'Reviewable AssetPack supply options.', + 'Withheld: raw source', + 'deposit-route-step-connect-source', + 'deposit-expandable-proof-detail', + 'Expected compensation', + ], + readbackRoots: ['depositRouteSession.proofRoot', 'synthesis.roots.synthesisRoot', 'policy.roots.policyReportRoot', 'admission.roots.admissionReportRoot', 'earningSupplyIntelligence.roots.intelligenceRoot'], + operatorReading: + '/deposit is the source-safe supply route; it forms reviewable options and admission readback without exposing protected source or claiming final Need-relative BTD at option time.', + }), +]); + +function buildSourceRoots(repoRoot) { + return Object.fromEntries(Object.entries(SOURCE_PATHS).map(([key, sourcePath]) => [key, sourceRoot(repoRoot, sourcePath)])); +} + +function buildSourcePredicates(repoRoot) { + const sources = Object.fromEntries(Object.entries(SOURCE_PATHS).map(([key, sourcePath]) => [key, readSource(repoRoot, sourcePath)])); + return [ + predicateResult('active-pointer-remains-v45', SOURCE_PATHS.activePointer, sources.activePointer.trim() === 'V45'), + predicateResult('spec-records-route-readback-law', SOURCE_PATHS.spec, sources.spec.includes('V46 product route comprehension readback law')), + predicateResult('delta-records-gate4', SOURCE_PATHS.delta, sources.delta.includes('Gate 4: `/packs`, `/read`, And `/deposit` Comprehension UX Readback')), + predicateResult('notes-record-gate4', SOURCE_PATHS.notes, sources.notes.includes('Gate 4 records the product-route comprehension atom')), + predicateResult('parity-records-gate4', SOURCE_PATHS.parity, sources.parity.includes('Product route comprehension readback artifact')), + predicateResult('roadmap-records-current-gate4', SOURCE_PATHS.roadmap, sources.roadmap.includes('Current working gate: V46 Gate 4')), + predicateResult('package-source-exists', SOURCE_PATHS.packageSource, sourceExists(repoRoot, SOURCE_PATHS.packageSource)), + predicateResult('package-test-exists', SOURCE_PATHS.packageTest, sourceExists(repoRoot, SOURCE_PATHS.packageTest)), + predicateResult('generator-exists', SOURCE_PATHS.generator, sourceExists(repoRoot, SOURCE_PATHS.generator)), + predicateResult('checker-exists', SOURCE_PATHS.checker, sourceExists(repoRoot, SOURCE_PATHS.checker)), + predicateResult('package-json-exposes-gate4', SOURCE_PATHS.packageJson, sources.packageJson.includes('"check:v46-gate4"')), + predicateResult('package-exports-gate4', SOURCE_PATHS.packageIndex, sources.packageIndex.includes('buildV46ProductRouteComprehensionReadback')), + predicateResult('package-types-export-gate4', SOURCE_PATHS.packageTypes, sources.packageTypes.includes('buildV46ProductRouteComprehensionReadback')), + predicateResult('gate-and-canon-workflows-run-gate4', SOURCE_PATHS.gateWorkflow, sources.gateWorkflow.includes('check-v46-gate4-product-route-comprehension-readback.mjs') && sources.canonWorkflow.includes('check-v46-gate4-product-route-comprehension-readback.mjs')), + predicateResult('packs-route-uses-shared-shell', SOURCE_PATHS.packsClient, sources.packsClient.includes('route-shell-packs') && sources.packsClient.includes('ProductRouteEnterpriseSummary') && sources.packsClient.includes('ProductRouteProofDetail')), + predicateResult( + 'read-route-uses-five-step-shell', + SOURCE_PATHS.readClient, + sources.readClient.includes('route-shell-read') && + sources.readClient.includes('ProductRouteStepGrid') && + sources.readModel.includes('ReadFitsFindingSynthesis'), + ), + predicateResult('deposit-route-uses-five-step-shell', SOURCE_PATHS.depositClient, sources.depositClient.includes('route-shell-deposit') && sources.depositClient.includes('ProductRouteStepGrid') && sources.depositClient.includes('DepositAssetPackOptionSynthesis')), + ]; +} + +function sourceSafetyCoverage(repoRoot, rows) { + const allSourcePaths = [...new Set(rows.flatMap((row) => row.sourcePaths))]; + const forbiddenPhraseHits = scanSourcesForMarkers(repoRoot, allSourcePaths, FORBIDDEN_PRODUCT_ROUTE_PHRASES); + const secretMarkerHits = scanSourcesForMarkers(repoRoot, allSourcePaths, SECRET_MARKERS); + const rowsMissingRequiredCopy = rows.filter((row) => !requiredTokensPresent(repoRoot, row)).map((row) => row.routeId); + return { + sourceSafeMetadataOnly: rows.every((row) => row.sourceSafeMetadataOnly === true), + protectedSourceVisible: rows.some((row) => row.protectedSourceVisible === true), + unpaidAssetPackSourceVisible: rows.some((row) => row.unpaidAssetPackSourceVisible === true), + rawPromptVisible: rows.some((row) => row.rawPromptVisible === true), + interpolatedPromptVisible: rows.some((row) => row.interpolatedPromptVisible === true), + rawProviderResponseVisible: rows.some((row) => row.rawProviderResponseVisible === true), + credentialsSerialized: rows.some((row) => row.credentialsSerialized === true), + walletPrivateMaterialVisible: rows.some((row) => row.walletPrivateMaterialVisible === true), + settlementPrivatePayloadVisible: rows.some((row) => row.settlementPrivatePayloadVisible === true), + valueBearingMainnetAdmitted: rows.some((row) => row.valueBearingMainnetAdmitted === true), + forbiddenPhraseHits, + secretMarkerHits, + rowsMissingRequiredCopy, + }; +} + +export function buildV46ProductRouteComprehensionReadback(input = {}) { + const repoRoot = typeof input.repoRoot === 'string' ? input.repoRoot : DEFAULT_REPO_ROOT; + const routeRows = [...V46_PRODUCT_ROUTE_READBACK_ROWS]; + const sourcePredicates = buildSourcePredicates(repoRoot); + const failedPredicateIds = sourcePredicates.filter((predicate) => !predicate.passed).map((predicate) => predicate.id); + const claimIdsUsed = [...new Set(routeRows.flatMap((row) => row.claimIds))]; + const categoryIdsUsed = [...new Set(routeRows.flatMap((row) => row.claimCategoryIds))]; + const authorityIdsUsed = [...new Set(routeRows.flatMap((row) => row.authorityIds))]; + const capabilityIdsUsed = [...new Set(routeRows.flatMap((row) => row.capabilityIds))]; + const coverage = { + routeCount: routeRows.length, + routeIds: [...V46_PRODUCT_ROUTE_IDS], + routePaths: [...V46_PRODUCT_ROUTE_PATHS], + capabilityIds: [...V46_PRODUCT_ROUTE_CAPABILITY_IDS], + capabilityIdsUsed, + claimIdsUsed, + categoryIdsUsed, + authorityIdsUsed, + privatePayloadIds: [...V46_PROTOCOL_PRIVATE_PAYLOAD_IDS], + allRoutesCovered: V46_PRODUCT_ROUTE_IDS.every((routeId) => routeRows.some((row) => row.routeId === routeId)), + allRoutePathsCovered: V46_PRODUCT_ROUTE_PATHS.every((routePath) => routeRows.some((row) => row.routePath === routePath)), + lowDetailDefaultsCovered: routeRows.every((row) => row.lowDetailDefault === true), + expandableProofReadbackCovered: routeRows.every((row) => row.expandableSourceSafeDetail === true && row.proofReadbackVisible === true), + routeOwnedStateCovered: routeRows.every((row) => row.routeOwnedState === true), + requiredCapabilitiesCovered: V46_PRODUCT_ROUTE_CAPABILITY_IDS.filter((capabilityId) => capabilityId !== 'terminal-debug-compatibility').every( + (capabilityId) => capabilityIdsUsed.includes(capabilityId), + ), + routeSpecificCapabilitiesCovered: + capabilityIdsUsed.includes('search-filter-sort') && + capabilityIdsUsed.includes('five-step-reading') && + capabilityIdsUsed.includes('five-step-depositing'), + allClaimIdsKnown: claimIdsUsed.every(claimExists), + allCategoryIdsKnown: categoryIdsUsed.every(categoryExists), + allAuthorityIdsKnown: authorityIdsUsed.every(authorityExists), + sourcePredicates, + failedPredicateIds, + ...sourceSafetyCoverage(repoRoot, routeRows), + }; + + return { + artifactId: 'v46-product-route-comprehension-readback', + artifactPath: V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH, + artifactRoot: `v46-product-route-comprehension-readback:${digest(JSON.stringify({ routeRows, coverage }))}`, + schemaId: V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SCHEMA_ID, + version: V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_VERSION, + currentTarget: V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_CURRENT_TARGET, + sourceSafetyVerdict: V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_SAFETY_VERDICT, + sourceRoots: buildSourceRoots(repoRoot), + routeIds: [...V46_PRODUCT_ROUTE_IDS], + routePaths: [...V46_PRODUCT_ROUTE_PATHS], + capabilityIds: [...V46_PRODUCT_ROUTE_CAPABILITY_IDS], + privatePayloadIdsNeverSerialized: [...V46_PROTOCOL_PRIVATE_PAYLOAD_IDS], + routeRows, + coverage, + passed: + failedPredicateIds.length === 0 && + coverage.allRoutesCovered === true && + coverage.allRoutePathsCovered === true && + coverage.lowDetailDefaultsCovered === true && + coverage.expandableProofReadbackCovered === true && + coverage.routeOwnedStateCovered === true && + coverage.requiredCapabilitiesCovered === true && + coverage.routeSpecificCapabilitiesCovered === true && + coverage.allClaimIdsKnown === true && + coverage.allCategoryIdsKnown === true && + coverage.allAuthorityIdsKnown === true && + coverage.sourceSafeMetadataOnly === true && + coverage.protectedSourceVisible === false && + coverage.unpaidAssetPackSourceVisible === false && + coverage.rawPromptVisible === false && + coverage.interpolatedPromptVisible === false && + coverage.rawProviderResponseVisible === false && + coverage.credentialsSerialized === false && + coverage.walletPrivateMaterialVisible === false && + coverage.settlementPrivatePayloadVisible === false && + coverage.valueBearingMainnetAdmitted === false && + coverage.forbiddenPhraseHits.length === 0 && + coverage.secretMarkerHits.length === 0 && + coverage.rowsMissingRequiredCopy.length === 0, + closureReading: + 'V46 Gate 4 closes source-safe route comprehension readback for /packs, /read, and /deposit without changing active V45 canon or admitting value-bearing mainnet operation.', + }; +} + +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_ROOTS = Object.freeze( + buildSourceRoots(DEFAULT_REPO_ROOT), +); diff --git a/packages/protocol/src/canonical/v46-public-operator-claim-boundaries.js b/packages/protocol/src/canonical/v46-public-operator-claim-boundaries.js index 7a8037151..68beaad1d 100644 --- a/packages/protocol/src/canonical/v46-public-operator-claim-boundaries.js +++ b/packages/protocol/src/canonical/v46-public-operator-claim-boundaries.js @@ -388,7 +388,7 @@ export const V46_PUBLIC_OPERATOR_SURFACE_ROWS = Object.freeze([ 'V46 public/operator claim boundary law', 'Gate 3: Public Docs, Landing, And Operator Claim Boundaries', V46_PUBLIC_OPERATOR_CLAIM_BOUNDARIES_ARTIFACT_PATH, - 'Current working gate: V46 Gate 3 Public Docs, Landing, And Operator Claim Boundaries.', + 'V46 Gate 3 closure anchor', ], allowedDataClasses: ['claim-categories', 'claim-authority-ids', 'proof-root-ids', 'state-labels'], blockedDataClasses: [...V46_PROTOCOL_PRIVATE_PAYLOAD_IDS], @@ -433,7 +433,7 @@ function buildSourcePredicates(repoRoot) { predicateResult( 'roadmap-records-gate3', SOURCE_PATHS.roadmap, - sources.roadmap.includes('Current working gate: V46 Gate 3 Public Docs, Landing, And Operator Claim Boundaries.') && + sources.roadmap.includes('Latest closed gate: V46 Gate 3 Public Docs, Landing, And Operator Claim Boundaries') && sources.roadmap.includes('V46 Gate 3 closure anchor') && sources.roadmap.includes(V46_PUBLIC_OPERATOR_CLAIM_BOUNDARIES_ARTIFACT_PATH), ), diff --git a/packages/protocol/src/index.d.ts b/packages/protocol/src/index.d.ts index fe0c65d6f..e8d9618b6 100644 --- a/packages/protocol/src/index.d.ts +++ b/packages/protocol/src/index.d.ts @@ -860,6 +860,17 @@ export const V46_PUBLIC_OPERATOR_SURFACE_KIND_IDS: readonly string[]; export const V46_PUBLIC_OPERATOR_ALLOWED_DATA_CLASSES: readonly string[]; export const V46_PUBLIC_OPERATOR_SURFACE_ROWS: readonly Record[]; export function buildV46PublicOperatorClaimBoundaries(input?: Record): BitcodeProtocolReport; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH: string; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_CURRENT_TARGET: string; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SCHEMA_ID: string; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_VERSION: string; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_SAFETY_VERDICT: string; +export const V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_ROOTS: Readonly>; +export const V46_PRODUCT_ROUTE_IDS: readonly string[]; +export const V46_PRODUCT_ROUTE_PATHS: readonly string[]; +export const V46_PRODUCT_ROUTE_CAPABILITY_IDS: readonly string[]; +export const V46_PRODUCT_ROUTE_READBACK_ROWS: readonly Record[]; +export function buildV46ProductRouteComprehensionReadback(input?: Record): BitcodeProtocolReport; export const EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH: string; export const EXCHANGE_INTENT_ORDER_CONTRACTS_CURRENT_TARGET: string; export const EXCHANGE_INTENT_ORDER_CONTRACTS_SCHEMA_ID: string; diff --git a/packages/protocol/src/index.js b/packages/protocol/src/index.js index d0c9557a4..8ddc014b3 100644 --- a/packages/protocol/src/index.js +++ b/packages/protocol/src/index.js @@ -978,6 +978,19 @@ export { V46_PUBLIC_OPERATOR_SURFACE_ROWS, buildV46PublicOperatorClaimBoundaries } from './canonical/v46-public-operator-claim-boundaries.js'; +export { + V46_PRODUCT_ROUTE_CAPABILITY_IDS, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_CURRENT_TARGET, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SCHEMA_ID, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_ROOTS, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_SAFETY_VERDICT, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_VERSION, + V46_PRODUCT_ROUTE_IDS, + V46_PRODUCT_ROUTE_PATHS, + V46_PRODUCT_ROUTE_READBACK_ROWS, + buildV46ProductRouteComprehensionReadback +} from './canonical/v46-product-route-comprehension-readback.js'; export { EXCHANGE_INTENT_ACTION_KINDS, EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH, diff --git a/packages/protocol/test/v46-product-route-comprehension-readback.test.js b/packages/protocol/test/v46-product-route-comprehension-readback.test.js new file mode 100644 index 000000000..0b0426e6a --- /dev/null +++ b/packages/protocol/test/v46-product-route-comprehension-readback.test.js @@ -0,0 +1,92 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; +import { + V46_PRODUCT_ROUTE_CAPABILITY_IDS, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SCHEMA_ID, + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_SAFETY_VERDICT, + V46_PRODUCT_ROUTE_IDS, + V46_PRODUCT_ROUTE_PATHS, + V46_PRODUCT_ROUTE_READBACK_ROWS, + buildV46ProductRouteComprehensionReadback, +} from '../src/canonical/v46-product-route-comprehension-readback.js'; + +test('V46 product route comprehension readback binds packs, read, and deposit routes', () => { + const report = buildV46ProductRouteComprehensionReadback(); + + assert.equal(V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH, '.bitcode/v46-product-route-comprehension-readback.json'); + assert.equal(report.artifactId, 'v46-product-route-comprehension-readback'); + assert.equal(report.schemaId, V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SCHEMA_ID); + assert.equal(report.version, 'V46'); + assert.equal(report.currentTarget, 'V45'); + assert.equal(report.sourceSafetyVerdict, V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_SOURCE_SAFETY_VERDICT); + assert.ok(report.artifactRoot.startsWith('v46-product-route-comprehension-readback:')); + assert.deepEqual(report.routeIds, [...V46_PRODUCT_ROUTE_IDS]); + assert.deepEqual(report.routePaths, [...V46_PRODUCT_ROUTE_PATHS]); + assert.deepEqual(report.capabilityIds, [...V46_PRODUCT_ROUTE_CAPABILITY_IDS]); + assert.equal(report.routeRows.length, V46_PRODUCT_ROUTE_READBACK_ROWS.length); + assert.equal(report.coverage.allRoutesCovered, true); + assert.equal(report.coverage.allRoutePathsCovered, true); + assert.equal(report.coverage.lowDetailDefaultsCovered, true); + assert.equal(report.coverage.expandableProofReadbackCovered, true); + assert.equal(report.coverage.routeOwnedStateCovered, true); + assert.equal(report.coverage.requiredCapabilitiesCovered, true); + assert.equal(report.coverage.routeSpecificCapabilitiesCovered, true); + assert.equal(report.coverage.allClaimIdsKnown, true); + assert.equal(report.coverage.allCategoryIdsKnown, true); + assert.equal(report.coverage.allAuthorityIdsKnown, true); + assert.equal(report.coverage.rowsMissingRequiredCopy.length, 0); + assert.equal(report.passed, true); +}); + +test('V46 product route readback rows preserve source-safe disclosure boundaries', () => { + const report = buildV46ProductRouteComprehensionReadback(); + + assert.equal(report.coverage.sourceSafeMetadataOnly, true); + assert.equal(report.coverage.protectedSourceVisible, false); + assert.equal(report.coverage.unpaidAssetPackSourceVisible, false); + assert.equal(report.coverage.rawPromptVisible, false); + assert.equal(report.coverage.interpolatedPromptVisible, false); + assert.equal(report.coverage.rawProviderResponseVisible, false); + assert.equal(report.coverage.credentialsSerialized, false); + assert.equal(report.coverage.walletPrivateMaterialVisible, false); + assert.equal(report.coverage.settlementPrivatePayloadVisible, false); + assert.equal(report.coverage.valueBearingMainnetAdmitted, false); + assert.deepEqual(report.coverage.forbiddenPhraseHits, []); + assert.deepEqual(report.coverage.secretMarkerHits, []); + + for (const row of report.routeRows) { + assert.equal(row.lowDetailDefault, true); + assert.equal(row.expandableSourceSafeDetail, true); + assert.equal(row.routeOwnedState, true); + assert.equal(row.proofReadbackVisible, true); + assert.equal(row.sourceSafeMetadataOnly, true); + assert.equal(row.protectedSourceVisible, false); + assert.equal(row.unpaidAssetPackSourceVisible, false); + assert.equal(row.rawPromptVisible, false); + assert.equal(row.interpolatedPromptVisible, false); + assert.equal(row.rawProviderResponseVisible, false); + assert.equal(row.credentialsSerialized, false); + assert.equal(row.walletPrivateMaterialVisible, false); + assert.equal(row.settlementPrivatePayloadVisible, false); + assert.equal(row.valueBearingMainnetAdmitted, false); + assert.ok(row.rowRoot.includes(':')); + } +}); + +test('V46 product route readback rows keep route-specific product meaning distinct', () => { + const report = buildV46ProductRouteComprehensionReadback(); + const rowById = new Map(report.routeRows.map((row) => [row.routeId, row])); + + assert.deepEqual(rowById.get('packs')?.requiredCopyTokens.slice(0, 3), [ + 'Pack activity', + 'Portfolio positions, market signals, proof roots, settlement, compensation, delivery, repair.', + 'Search titles, measurements, values, proof roots', + ]); + assert.equal(rowById.get('packs')?.capabilityIds.includes('search-filter-sort'), true); + assert.equal(rowById.get('read')?.capabilityIds.includes('five-step-reading'), true); + assert.equal(rowById.get('read')?.claimIds.includes('quote-is-source-safe-offer'), true); + assert.equal(rowById.get('deposit')?.capabilityIds.includes('five-step-depositing'), true); + assert.equal(rowById.get('deposit')?.claimIds.includes('deposit-option-is-potential-supply'), true); + assert.equal(rowById.get('deposit')?.operatorReading.includes('source-safe supply route'), true); +}); diff --git a/scripts/check-v46-gate4-product-route-comprehension-readback.mjs b/scripts/check-v46-gate4-product-route-comprehension-readback.mjs new file mode 100644 index 000000000..d59735b8f --- /dev/null +++ b/scripts/check-v46-gate4-product-route-comprehension-readback.mjs @@ -0,0 +1,188 @@ +#!/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 { + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH, + buildV46ProductRouteComprehensionReadback, +} from '../packages/protocol/src/canonical/v46-product-route-comprehension-readback.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 }; + 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 === '--help' || arg === '-h') args.help = true; + else throw new Error(`Unknown argument ${arg}`); + } + return args; +} + +function printHelp() { + process.stdout.write( + [ + 'Usage: node scripts/check-v46-gate4-product-route-comprehension-readback.mjs [--skip-branch-check] [--skip-package-tests] [--repo-root ]', + '', + 'V46 Gate 4 check: validates source-safe /packs, /read, and /deposit route comprehension readback, generated artifact freshness, package exports, docs, workflow wiring, and focused protocol tests.', + ].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 === 'V45', `BITCODE_SPEC.txt must remain V45 during V46 gate work. Observed ${pointer || 'empty'}.`); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v46' || /^v46\/gate-\d+-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V46 work must occur on version/v46 or v46/gate-N-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH, + 'packages/protocol/src/canonical/v46-product-route-comprehension-readback.js', + 'packages/protocol/test/v46-product-route-comprehension-readback.test.js', + 'scripts/generate-v46-product-route-comprehension-readback.mjs', + 'scripts/check-v46-gate4-product-route-comprehension-readback.mjs', + 'BITCODE_SPEC_V46.md', + 'BITCODE_SPEC_V46_DELTA.md', + 'BITCODE_SPEC_V46_NOTES.md', + 'BITCODE_SPEC_V46_PARITY_MATRIX.md', + 'SPECIFICATIONS_ROADMAP.md', + 'uapi/app/packs/PacksPageClient.tsx', + 'uapi/app/read/ReadPageClient.tsx', + 'uapi/app/deposit/DepositPageClient.tsx', + 'uapi/components/base/bitcode/routes/product-route-shell.tsx', + 'uapi/tests/packsPageClient.test.tsx', + 'uapi/tests/readPageClient.test.tsx', + 'uapi/tests/depositPageClient.test.tsx', + '.github/workflows/bitcode-gate-quality.yml', + '.github/workflows/bitcode-canon-quality.yml', + 'package.json', + ]) { + assertCheck(failures, exists(root, relativePath), `Missing required V46 Gate 4 file: ${relativePath}`); + } + + const artifact = buildV46ProductRouteComprehensionReadback({ repoRoot: root }); + assertCheck(failures, artifact.passed, `V46 product route comprehension predicates failed: ${artifact.coverage.failedPredicateIds.join(', ')}`); + assertCheck(failures, artifact.coverage.allRoutesCovered === true, 'All product route ids must be covered.'); + assertCheck(failures, artifact.coverage.allRoutePathsCovered === true, 'All product route paths must be covered.'); + assertCheck(failures, artifact.coverage.lowDetailDefaultsCovered === true, 'Routes must default to low-detail guided readback.'); + assertCheck(failures, artifact.coverage.expandableProofReadbackCovered === true, 'Routes must expose expandable source-safe proof readback.'); + assertCheck(failures, artifact.coverage.routeOwnedStateCovered === true, 'Routes must own their source-safe route state.'); + assertCheck(failures, artifact.coverage.requiredCapabilitiesCovered === true, 'Required shared capabilities must be covered.'); + assertCheck(failures, artifact.coverage.routeSpecificCapabilitiesCovered === true, 'Packs search, Reading five-step, and Depositing five-step capabilities must be covered.'); + assertCheck(failures, artifact.coverage.allClaimIdsKnown === true, 'All referenced claim ids must be known to Gate 2.'); + assertCheck(failures, artifact.coverage.allCategoryIdsKnown === true, 'All referenced claim category ids must be known to Gate 2.'); + assertCheck(failures, artifact.coverage.allAuthorityIdsKnown === true, 'All referenced claim authority ids must be known to Gate 2.'); + 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.rawPromptVisible === false, 'Artifact must not expose raw prompts.'); + assertCheck(failures, artifact.coverage.interpolatedPromptVisible === false, 'Artifact must not expose interpolated prompts.'); + assertCheck(failures, artifact.coverage.rawProviderResponseVisible === false, 'Artifact must not expose raw provider responses.'); + assertCheck(failures, artifact.coverage.credentialsSerialized === false, 'Artifact must not serialize credentials.'); + assertCheck(failures, artifact.coverage.walletPrivateMaterialVisible === false, 'Artifact must not expose wallet private material.'); + assertCheck(failures, artifact.coverage.settlementPrivatePayloadVisible === false, 'Artifact must not expose private settlement payloads.'); + assertCheck(failures, artifact.coverage.valueBearingMainnetAdmitted === false, 'Gate 4 must not admit value-bearing mainnet operation.'); + assertCheck(failures, artifact.coverage.forbiddenPhraseHits.length === 0, `Forbidden product route phrases found: ${artifact.coverage.forbiddenPhraseHits.join(', ')}`); + assertCheck(failures, artifact.coverage.secretMarkerHits.length === 0, `Secret markers found in product route sources: ${artifact.coverage.secretMarkerHits.join(', ')}`); + assertCheck(failures, artifact.coverage.rowsMissingRequiredCopy.length === 0, `Missing required route copy tokens for rows: ${artifact.coverage.rowsMissingRequiredCopy.join(', ')}`); + + const serialized = `${JSON.stringify(artifact, null, 2)}\n`; + assertCheck( + failures, + exists(root, V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH) && + read(root, V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH) === serialized, + `${V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_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:v46-product-route-comprehension-readback"'), 'package.json must expose generate:v46-product-route-comprehension-readback.'); + assertCheck(failures, packageJson.includes('"check:v46-product-route-comprehension-readback"'), 'package.json must expose check:v46-product-route-comprehension-readback.'); + assertCheck(failures, packageJson.includes('"check:v46-gate4"'), 'package.json must expose check:v46-gate4.'); + assertCheck(failures, gateWorkflow.includes('check-v46-gate4-product-route-comprehension-readback.mjs'), 'Gate workflow must run V46 Gate 4 checker.'); + assertCheck(failures, canonWorkflow.includes('check-v46-gate4-product-route-comprehension-readback.mjs'), 'Canon workflow must run V46 Gate 4 checker.'); + + try { + run(root, 'node', ['scripts/generate-v46-product-route-comprehension-readback.mjs', '--check']); + } catch { + failures.push('V46 product route comprehension readback artifact must be fresh.'); + } + + if (!args.skipPackageTests) { + try { + run(root, 'pnpm', [ + '--dir', + 'packages/protocol', + 'exec', + 'node', + '--test', + '--test-force-exit', + 'test/v46-product-route-comprehension-readback.test.js', + ]); + } catch { + failures.push('packages/protocol/test/v46-product-route-comprehension-readback.test.js must pass.'); + } + } + + if (failures.length > 0) { + process.stderr.write('V46 Gate 4 product route comprehension readback check failed:\n'); + for (const failure of failures.filter(Boolean)) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write('V46 Gate 4 product route comprehension readback 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-v46-product-route-comprehension-readback.mjs b/scripts/generate-v46-product-route-comprehension-readback.mjs new file mode 100644 index 000000000..f35daae07 --- /dev/null +++ b/scripts/generate-v46-product-route-comprehension-readback.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 { + V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH, + buildV46ProductRouteComprehensionReadback, +} from '../packages/protocol/src/canonical/v46-product-route-comprehension-readback.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 = buildV46ProductRouteComprehensionReadback({ repoRoot }); +const serialized = `${JSON.stringify(artifact, null, 2)}\n`; +const artifactPath = path.join(repoRoot, V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH); + +if (checkOnly) { + if (!existsSync(artifactPath) || readFileSync(artifactPath, 'utf8') !== serialized) { + process.stderr.write( + `${V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH} is stale. Run pnpm run generate:v46-product-route-comprehension-readback.\n`, + ); + process.exitCode = 1; + } +} else { + mkdirSync(path.dirname(artifactPath), { recursive: true }); + writeFileSync(artifactPath, serialized); + process.stdout.write(`wrote ${V46_PRODUCT_ROUTE_COMPREHENSION_READBACK_ARTIFACT_PATH}\n`); +}