From 8cf1bdf229354c42469dc5cba386760c5a059338 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Fri, 29 May 2026 11:23:03 -0300 Subject: [PATCH] V43 Gate 6: Add deposit policy and compensation scoring Implement source-safe DepositAssetPackOptionPolicyReport scoring for criticality, likely demand, ROI, estimate-only BTD potential, and BTC source-to-shares compensation preview. Wire the policy through /deposit session state and UI readback, add package and route tests, bind protocol exports/checkers/artifacts, refresh V43 docs/workflows, and keep Gate 7 admission/indexing deferred. Validation: pnpm run check:v43-gate1; pnpm run check:v43-gate2; pnpm run check:v43-gate3 --skip-uapi-tests; pnpm run check:v43-gate4 --skip-uapi-tests; pnpm run check:v43-gate5 --skip-uapi-tests --skip-package-tests; pnpm run check:v43-gate6; pnpm --filter @bitcode/protocol test -- v43-deposit-policy-compensation.test.js; pnpm --filter @bitcode/protocol typecheck; pnpm --filter @bitcode/pipeline-asset-pack typecheck; pnpm --filter @bitcode/pipeline-asset-pack exec jest deposit-asset-pack-option-policy.test.ts deposit-asset-pack-options.test.ts --runInBand; pnpm --dir uapi exec jest --runTestsByPath tests/depositRouteModel.test.ts tests/depositPageClient.test.tsx --runInBand; pnpm --dir uapi exec tsc --noEmit --pretty false; pnpm --dir uapi run lint; pnpm --dir uapi run build; Playwright /deposit smoke. --- .bitcode/v43-deposit-policy-compensation.json | 307 +++++++++ .bitcode/v43-deposit-route-options.json | 38 +- .../v43-packs-activity-master-detail.json | 26 +- .bitcode/v43-read-route-five-step-ux.json | 26 +- .bitcode/v43-route-vocabulary-inventory.json | 125 +++- .github/workflows/bitcode-canon-quality.yml | 3 + .github/workflows/bitcode-gate-quality.yml | 6 + BITCODE_SPEC_V43.md | 26 +- BITCODE_SPEC_V43_DELTA.md | 15 + BITCODE_SPEC_V43_NOTES.md | 10 + BITCODE_SPEC_V43_PARITY_MATRIX.md | 13 +- README.md | 11 + SPECIFICATIONS_ROADMAP.md | 5 +- package.json | 3 + packages/pipelines/asset-pack/package.json | 1 + .../deposit-asset-pack-option-policy.test.ts | 103 +++ .../src/deposit-asset-pack-option-policy.ts | 628 ++++++++++++++++++ packages/pipelines/asset-pack/src/index.ts | 1 + packages/protocol/README.md | 12 + .../v43-deposit-policy-compensation.js | 234 +++++++ packages/protocol/src/index.d.ts | 11 + packages/protocol/src/index.js | 13 + .../v43-deposit-policy-compensation.test.js | 44 ++ ...-v43-gate6-deposit-policy-compensation.mjs | 173 +++++ ...nerate-v43-deposit-policy-compensation.mjs | 30 + uapi/app/deposit/DepositPageClient.tsx | 73 +- uapi/app/deposit/deposit-route-model.ts | 29 + uapi/jest.config.cjs | 1 + uapi/tests/depositPageClient.test.tsx | 2 + uapi/tests/depositRouteModel.test.ts | 33 + uapi/tsconfig.json | 3 + 31 files changed, 1911 insertions(+), 94 deletions(-) create mode 100644 .bitcode/v43-deposit-policy-compensation.json create mode 100644 packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts create mode 100644 packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts create mode 100644 packages/protocol/src/canonical/v43-deposit-policy-compensation.js create mode 100644 packages/protocol/test/v43-deposit-policy-compensation.test.js create mode 100644 scripts/check-v43-gate6-deposit-policy-compensation.mjs create mode 100644 scripts/generate-v43-deposit-policy-compensation.mjs diff --git a/.bitcode/v43-deposit-policy-compensation.json b/.bitcode/v43-deposit-policy-compensation.json new file mode 100644 index 00000000..70ee7cb6 --- /dev/null +++ b/.bitcode/v43-deposit-policy-compensation.json @@ -0,0 +1,307 @@ +{ + "artifactId": "v43-deposit-policy-compensation", + "schemaId": "bitcode.v43.depositPolicyCompensation.v1", + "version": "V43", + "currentTarget": "V42", + "sourceSafetyVerdict": "source-safe-deposit-policy-compensation-metadata", + "generatedAt": "deterministic", + "artifactRoot": "v43-deposit-policy-compensation:06077693236133dff819908a", + "passed": true, + "objectIds": [ + "DepositAssetPackOptionPolicy", + "DepositAssetPackOptionPolicyReport", + "DepositAssetPackOptionPolicyEvaluation", + "source criticality posture", + "likely demand posture", + "ROI posture", + "BTD potential estimate", + "BTC source-to-shares compensation route", + "future Gate 7 admission boundary" + ], + "fieldIds": [ + "sourceCriticality", + "demand", + "roi", + "btdPotential", + "compensation", + "policyDecision", + "admissionBoundary", + "policy roots" + ], + "forbiddenPayloadIds": [ + "protected_source_payload", + "raw_source_text", + "unpaid_assetpack_source", + "raw_protected_prompt", + "interpolated_prompt", + "raw_provider_response", + "wallet_private_material", + "settlement_private_payload" + ], + "contractRows": [ + { + "rowId": "criticality-policy", + "owner": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "contract": "DepositAssetPackOptionPolicy evaluates source criticality from source-safe criticality signals and blocks critical IP before Gate 7 admission.", + "requiredFields": [ + "sourceCriticality", + "blocked-critical-source", + "critical_source_policy_block" + ], + "rowRoot": "v43-deposit-policy-contract:e5411b4187a92443f8ac974f", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + }, + { + "rowId": "demand-roi-policy", + "owner": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "contract": "Policy evaluates likely demand and ROI deterministically from source-safe option measurements, demand confidence, estimated settlement, and development cost.", + "requiredFields": [ + "demand", + "roi", + "positive-expected-value", + "negative-expected-value" + ], + "rowRoot": "v43-deposit-policy-contract:b686a0c2af187d224c61c5f7", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + }, + { + "rowId": "btd-compensation-policy", + "owner": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "contract": "Policy exposes BTD potential as estimate-only and previews future-reader BTC source-to-shares compensation without minting BTD or transferring rights.", + "requiredFields": [ + "btdPotential", + "compensation", + "source-to-shares-largest-remainder", + "BTC" + ], + "rowRoot": "v43-deposit-policy-contract:00577909a54242c3c4cf17e3", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + }, + { + "rowId": "route-policy-readback", + "owner": "uapi/app/deposit/DepositPageClient.tsx", + "contract": "/deposit renders policy readback for criticality, demand, ROI, BTD potential, and compensation while admission/indexing remain owned by Gate 7.", + "requiredFields": [ + "DepositAssetPackOptionPolicy", + "BTC source-to-shares preview", + "future-gate7-deposit-option-review" + ], + "rowRoot": "v43-deposit-policy-contract:d04bd16cdda75bf1c0539c52", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + } + ], + "sourceRoots": { + "activePointer": "BITCODE_SPEC.txt:75f3f6d81f999da998f40cb6", + "spec": "BITCODE_SPEC_V43.md:801a9fc58bfeddd4c71140ac", + "delta": "BITCODE_SPEC_V43_DELTA.md:3f942fe82b77655231ddb8ed", + "notes": "BITCODE_SPEC_V43_NOTES.md:540a19ddbba065526ebe0819", + "parity": "BITCODE_SPEC_V43_PARITY_MATRIX.md:0555bc917046cbad7995966e", + "roadmap": "SPECIFICATIONS_ROADMAP.md:aa1ee2ac496931752e11cd7e", + "readme": "README.md:89be1d13f8d516dc263bd9cf", + "protocolReadme": "packages/protocol/README.md:ecd8d9539e4cacdc7d1a32e6", + "packageJson": "package.json:d5e4b589e6a81ff3ba867017", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:715ca61f2961eae12ae64bb8", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:c9d194dbe48ea4eafd75f225", + "optionModel": "packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts:df560ea2544282645f57a6b5", + "policyModel": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts:12816b23b2d8e304ab4a1638", + "optionModelTest": "packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-options.test.ts:66cfc8c728f134087476a3a3", + "policyModelTest": "packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts:1af7adccac488298ccd7f048", + "routeModel": "uapi/app/deposit/deposit-route-model.ts:65e22b7bd3a9dcd6db0b7a47", + "client": "uapi/app/deposit/DepositPageClient.tsx:13f13e38dff99f46eb557179", + "routeModelTest": "uapi/tests/depositRouteModel.test.ts:c755b89c1e977e101aee25c1", + "pageTest": "uapi/tests/depositPageClient.test.tsx:f1526e498bfa332b3eb2cc42", + "packageIndex": "packages/pipelines/asset-pack/src/index.ts:7eddc6519cf67b4044fcd40e", + "packageManifest": "packages/pipelines/asset-pack/package.json:09e67662168fc921a53c696e", + "protocolIndex": "packages/protocol/src/index.js:533d73eb0b2cf01b4ac5c8b5", + "protocolTypes": "packages/protocol/src/index.d.ts:307e3a474c62fcce0b015be6", + "protocolTest": "packages/protocol/test/v43-deposit-policy-compensation.test.js:f84b0c016065b10f796eb775", + "generator": "scripts/generate-v43-deposit-policy-compensation.mjs:0117b1222d0f4a4640324b47", + "checker": "scripts/check-v43-gate6-deposit-policy-compensation.mjs:03412b725c36f24991a6325e" + }, + "predicateResults": [ + { + "id": "active-canon-pointer-remains-v42", + "sourcePath": "BITCODE_SPEC.txt", + "passed": true + }, + { + "id": "spec-defines-gate6", + "sourcePath": "BITCODE_SPEC_V43.md", + "passed": true + }, + { + "id": "spec-names-policy-objects", + "sourcePath": "BITCODE_SPEC_V43.md", + "passed": true + }, + { + "id": "delta-records-gate6", + "sourcePath": "BITCODE_SPEC_V43_DELTA.md", + "passed": true + }, + { + "id": "notes-records-gate6", + "sourcePath": "BITCODE_SPEC_V43_NOTES.md", + "passed": true + }, + { + "id": "parity-records-gate6", + "sourcePath": "BITCODE_SPEC_V43_PARITY_MATRIX.md", + "passed": true + }, + { + "id": "roadmap-records-gate6", + "sourcePath": "SPECIFICATIONS_ROADMAP.md", + "passed": true + }, + { + "id": "readme-records-gate6", + "sourcePath": "README.md", + "passed": true + }, + { + "id": "protocol-readme-records-gate6", + "sourcePath": "packages/protocol/README.md", + "passed": true + }, + { + "id": "policy-model-defines-report", + "sourcePath": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "passed": true + }, + { + "id": "policy-model-defines-criticality", + "sourcePath": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "passed": true + }, + { + "id": "policy-model-defines-demand-roi", + "sourcePath": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "passed": true + }, + { + "id": "policy-model-defines-btd-compensation", + "sourcePath": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "passed": true + }, + { + "id": "policy-model-defers-gate7-admission", + "sourcePath": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "passed": true + }, + { + "id": "policy-model-forbids-source-leakage", + "sourcePath": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "passed": true + }, + { + "id": "route-model-owns-policy", + "sourcePath": "uapi/app/deposit/deposit-route-model.ts", + "passed": true + }, + { + "id": "deposit-client-renders-policy", + "sourcePath": "uapi/app/deposit/DepositPageClient.tsx", + "passed": true + }, + { + "id": "asset-pack-package-exports-policy", + "sourcePath": "packages/pipelines/asset-pack/src/index.ts", + "passed": true + }, + { + "id": "asset-pack-manifest-exports-policy", + "sourcePath": "packages/pipelines/asset-pack/package.json", + "passed": true + }, + { + "id": "policy-test-covers-report", + "sourcePath": "packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts", + "passed": true + }, + { + "id": "route-test-covers-policy", + "sourcePath": "uapi/tests/depositRouteModel.test.ts", + "passed": true + }, + { + "id": "page-test-covers-policy", + "sourcePath": "uapi/tests/depositPageClient.test.tsx", + "passed": true + }, + { + "id": "protocol-test-covers-artifact", + "sourcePath": "packages/protocol/test/v43-deposit-policy-compensation.test.js", + "passed": true + }, + { + "id": "protocol-package-exports-gate6", + "sourcePath": "packages/protocol/src/index.js", + "passed": true + }, + { + "id": "protocol-types-export-gate6", + "sourcePath": "packages/protocol/src/index.d.ts", + "passed": true + }, + { + "id": "package-json-exposes-gate6", + "sourcePath": "package.json", + "passed": true + }, + { + "id": "gate-workflow-runs-gate6", + "sourcePath": ".github/workflows/bitcode-gate-quality.yml", + "passed": true + }, + { + "id": "canon-workflow-runs-gate6", + "sourcePath": ".github/workflows/bitcode-canon-quality.yml", + "passed": true + }, + { + "id": "generator-exists", + "sourcePath": "scripts/generate-v43-deposit-policy-compensation.mjs", + "passed": true + }, + { + "id": "checker-exists", + "sourcePath": "scripts/check-v43-gate6-deposit-policy-compensation.mjs", + "passed": true + } + ], + "coverage": { + "depositPolicyImplemented": true, + "criticalityPolicyImplemented": true, + "criticalSourceBlockedBeforeAdmission": true, + "demandPolicyImplemented": true, + "roiPolicyImplemented": true, + "btdPotentialEstimateOnly": true, + "compensationPolicyImplemented": true, + "compensationPriceAsset": "BTC", + "compensationAllocationMethod": "source-to-shares-largest-remainder", + "btdMintRequiresFutureNeedFitSettlement": true, + "admissionAndIndexingDeferredToGate7": true, + "routePolicyReadbackImplemented": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawSourceTextVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "requiredPredicateCount": 30, + "passedPredicateCount": 30, + "failedPredicateIds": [] + } +} diff --git a/.bitcode/v43-deposit-route-options.json b/.bitcode/v43-deposit-route-options.json index 611f67c9..d47c1272 100644 --- a/.bitcode/v43-deposit-route-options.json +++ b/.bitcode/v43-deposit-route-options.json @@ -5,7 +5,7 @@ "currentTarget": "V42", "sourceSafetyVerdict": "source-safe-deposit-route-option-metadata", "generatedAt": "deterministic", - "artifactRoot": "v43-deposit-route-options:1526fdf3f411384b07dd5db3", + "artifactRoot": "v43-deposit-route-options:cad9aab28407bb9a43dd27aa", "passed": true, "stepIds": [ "connect-source", @@ -111,33 +111,33 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:75f3f6d81f999da998f40cb6", - "spec": "BITCODE_SPEC_V43.md:33b2ffd69e638cda5924ff84", - "delta": "BITCODE_SPEC_V43_DELTA.md:eda402621bd2f265573cfae3", - "notes": "BITCODE_SPEC_V43_NOTES.md:276187a00ac011add5b867ab", - "parity": "BITCODE_SPEC_V43_PARITY_MATRIX.md:3b29425561456f9bc81745a5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:58c7f7db3966ba19c82db7e5", - "readme": "README.md:e090d2bf24246cb842600900", - "protocolReadme": "packages/protocol/README.md:cee8de9b189f70c155029df7", - "packageJson": "package.json:bb1ffd9a93103ef8519c1920", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:2fd6aec9c8291402cdfca043", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:b0479c7d71076f41e34011e7", + "spec": "BITCODE_SPEC_V43.md:801a9fc58bfeddd4c71140ac", + "delta": "BITCODE_SPEC_V43_DELTA.md:3f942fe82b77655231ddb8ed", + "notes": "BITCODE_SPEC_V43_NOTES.md:540a19ddbba065526ebe0819", + "parity": "BITCODE_SPEC_V43_PARITY_MATRIX.md:0555bc917046cbad7995966e", + "roadmap": "SPECIFICATIONS_ROADMAP.md:aa1ee2ac496931752e11cd7e", + "readme": "README.md:89be1d13f8d516dc263bd9cf", + "protocolReadme": "packages/protocol/README.md:ecd8d9539e4cacdc7d1a32e6", + "packageJson": "package.json:d5e4b589e6a81ff3ba867017", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:715ca61f2961eae12ae64bb8", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:c9d194dbe48ea4eafd75f225", "terminalRoutes": "uapi/app/terminal/terminal-routes.ts:80f478da2673f1a64ada9bfb", - "routeModel": "uapi/app/deposit/deposit-route-model.ts:f8a9c553c9ef418538981f76", + "routeModel": "uapi/app/deposit/deposit-route-model.ts:65e22b7bd3a9dcd6db0b7a47", "page": "uapi/app/deposit/page.tsx:6bab6a9debab3f4350d0ddca", - "client": "uapi/app/deposit/DepositPageClient.tsx:aacb1c4ba2bc494f62e5eee8", + "client": "uapi/app/deposit/DepositPageClient.tsx:13f13e38dff99f46eb557179", "optionModel": "packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts:df560ea2544282645f57a6b5", "optionModelTest": "packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-options.test.ts:66cfc8c728f134087476a3a3", - "packageIndex": "packages/pipelines/asset-pack/src/index.ts:056519274720276b37d3432d", - "packageManifest": "packages/pipelines/asset-pack/package.json:ae609a986babb6d97ddce16f", + "packageIndex": "packages/pipelines/asset-pack/src/index.ts:7eddc6519cf67b4044fcd40e", + "packageManifest": "packages/pipelines/asset-pack/package.json:09e67662168fc921a53c696e", "publicCopy": "uapi/components/base/bitcode/layout/bitcode-public-copy.ts:3a45184ba8d2a4e71858c597", "publicExplainers": "uapi/components/base/bitcode/layout/bitcode-public-explainers.ts:282d915eac3c9f22ba8c07f1", "workspaceSurface": "uapi/components/base/bitcode/layout/workspace-surface.ts:12418d5db9c3ddad6d10c841", "nav": "uapi/components/base/bitcode/layout/nav.tsx:d7d1a8104e780bb7c25f1880", "footer": "uapi/components/base/bitcode/layout/footer.tsx:44749b98e5f63e7ac8f9f574", - "routeModelTest": "uapi/tests/depositRouteModel.test.ts:c4b37d9400817a86af56306a", - "pageTest": "uapi/tests/depositPageClient.test.tsx:f2931dcddd80be378ce40aaf", - "protocolIndex": "packages/protocol/src/index.js:d6fea9aa2abae4a717a3373a", - "protocolTypes": "packages/protocol/src/index.d.ts:32caa412e41598f3c0c9bad8", + "routeModelTest": "uapi/tests/depositRouteModel.test.ts:c755b89c1e977e101aee25c1", + "pageTest": "uapi/tests/depositPageClient.test.tsx:f1526e498bfa332b3eb2cc42", + "protocolIndex": "packages/protocol/src/index.js:533d73eb0b2cf01b4ac5c8b5", + "protocolTypes": "packages/protocol/src/index.d.ts:307e3a474c62fcce0b015be6", "protocolTest": "packages/protocol/test/v43-deposit-route-options.test.js:6576a3d4947b9bc23f7a786d", "generator": "scripts/generate-v43-deposit-route-options.mjs:2d92d5e9c25e2e66712953f9", "checker": "scripts/check-v43-gate5-deposit-route-options.mjs:10c6ad1594ea8bd06f97d7d5" diff --git a/.bitcode/v43-packs-activity-master-detail.json b/.bitcode/v43-packs-activity-master-detail.json index d726378c..fff95e25 100644 --- a/.bitcode/v43-packs-activity-master-detail.json +++ b/.bitcode/v43-packs-activity-master-detail.json @@ -5,7 +5,7 @@ "currentTarget": "V42", "sourceSafetyVerdict": "source-safe-packs-activity-master-detail-metadata", "generatedAt": "deterministic", - "artifactRoot": "v43-packs-activity-master-detail:75879f49ee5102393f0d4f00", + "artifactRoot": "v43-packs-activity-master-detail:14c2af511e4f0c40641606a3", "passed": true, "typeIds": [ "deposit-option", @@ -138,16 +138,16 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:75f3f6d81f999da998f40cb6", - "spec": "BITCODE_SPEC_V43.md:33b2ffd69e638cda5924ff84", - "delta": "BITCODE_SPEC_V43_DELTA.md:eda402621bd2f265573cfae3", - "notes": "BITCODE_SPEC_V43_NOTES.md:276187a00ac011add5b867ab", - "parity": "BITCODE_SPEC_V43_PARITY_MATRIX.md:3b29425561456f9bc81745a5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:58c7f7db3966ba19c82db7e5", - "readme": "README.md:e090d2bf24246cb842600900", - "protocolReadme": "packages/protocol/README.md:cee8de9b189f70c155029df7", - "packageJson": "package.json:bb1ffd9a93103ef8519c1920", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:2fd6aec9c8291402cdfca043", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:b0479c7d71076f41e34011e7", + "spec": "BITCODE_SPEC_V43.md:801a9fc58bfeddd4c71140ac", + "delta": "BITCODE_SPEC_V43_DELTA.md:3f942fe82b77655231ddb8ed", + "notes": "BITCODE_SPEC_V43_NOTES.md:540a19ddbba065526ebe0819", + "parity": "BITCODE_SPEC_V43_PARITY_MATRIX.md:0555bc917046cbad7995966e", + "roadmap": "SPECIFICATIONS_ROADMAP.md:aa1ee2ac496931752e11cd7e", + "readme": "README.md:89be1d13f8d516dc263bd9cf", + "protocolReadme": "packages/protocol/README.md:ecd8d9539e4cacdc7d1a32e6", + "packageJson": "package.json:d5e4b589e6a81ff3ba867017", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:715ca61f2961eae12ae64bb8", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:c9d194dbe48ea4eafd75f225", "model": "uapi/components/base/bitcode/activity/pack-activity-model.ts:6c610ebddc2949f3716b6bf8", "route": "uapi/app/api/packs/activity/route.ts:8a524f1dd16889733ce418a7", "page": "uapi/app/packs/page.tsx:1b3d7a1cc00500a13042e8dd", @@ -157,8 +157,8 @@ "workspaceSurface": "uapi/components/base/bitcode/layout/workspace-surface.ts:12418d5db9c3ddad6d10c841", "publicCopy": "uapi/components/base/bitcode/layout/bitcode-public-copy.ts:3a45184ba8d2a4e71858c597", "publicExplainers": "uapi/components/base/bitcode/layout/bitcode-public-explainers.ts:282d915eac3c9f22ba8c07f1", - "packageIndex": "packages/protocol/src/index.js:d6fea9aa2abae4a717a3373a", - "packageTypes": "packages/protocol/src/index.d.ts:32caa412e41598f3c0c9bad8", + "packageIndex": "packages/protocol/src/index.js:533d73eb0b2cf01b4ac5c8b5", + "packageTypes": "packages/protocol/src/index.d.ts:307e3a474c62fcce0b015be6", "packageTest": "packages/protocol/test/v43-packs-activity-master-detail.test.js:baf3e44b2fbe4e62590c1824", "uapiTest": "uapi/tests/packActivityModel.test.ts:a4c3deea857830cf57772a4d", "generator": "scripts/generate-v43-packs-activity-master-detail.mjs:f342bc9b3ebb8de4e7aa2882", diff --git a/.bitcode/v43-read-route-five-step-ux.json b/.bitcode/v43-read-route-five-step-ux.json index 7131e458..8db8d460 100644 --- a/.bitcode/v43-read-route-five-step-ux.json +++ b/.bitcode/v43-read-route-five-step-ux.json @@ -5,7 +5,7 @@ "currentTarget": "V42", "sourceSafetyVerdict": "source-safe-read-route-five-step-metadata", "generatedAt": "deterministic", - "artifactRoot": "v43-read-route-five-step-ux:4009298776576d65b9257c9a", + "artifactRoot": "v43-read-route-five-step-ux:e1bca988fc966aa1184f23c7", "passed": true, "stepIds": [ "request-read", @@ -117,16 +117,16 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:75f3f6d81f999da998f40cb6", - "spec": "BITCODE_SPEC_V43.md:33b2ffd69e638cda5924ff84", - "delta": "BITCODE_SPEC_V43_DELTA.md:eda402621bd2f265573cfae3", - "notes": "BITCODE_SPEC_V43_NOTES.md:276187a00ac011add5b867ab", - "parity": "BITCODE_SPEC_V43_PARITY_MATRIX.md:3b29425561456f9bc81745a5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:58c7f7db3966ba19c82db7e5", - "readme": "README.md:e090d2bf24246cb842600900", - "protocolReadme": "packages/protocol/README.md:cee8de9b189f70c155029df7", - "packageJson": "package.json:bb1ffd9a93103ef8519c1920", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:2fd6aec9c8291402cdfca043", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:b0479c7d71076f41e34011e7", + "spec": "BITCODE_SPEC_V43.md:801a9fc58bfeddd4c71140ac", + "delta": "BITCODE_SPEC_V43_DELTA.md:3f942fe82b77655231ddb8ed", + "notes": "BITCODE_SPEC_V43_NOTES.md:540a19ddbba065526ebe0819", + "parity": "BITCODE_SPEC_V43_PARITY_MATRIX.md:0555bc917046cbad7995966e", + "roadmap": "SPECIFICATIONS_ROADMAP.md:aa1ee2ac496931752e11cd7e", + "readme": "README.md:89be1d13f8d516dc263bd9cf", + "protocolReadme": "packages/protocol/README.md:ecd8d9539e4cacdc7d1a32e6", + "packageJson": "package.json:d5e4b589e6a81ff3ba867017", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:715ca61f2961eae12ae64bb8", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:c9d194dbe48ea4eafd75f225", "routeModel": "uapi/app/read/read-route-model.ts:a9324b0d92cd6c5176fa7940", "page": "uapi/app/read/page.tsx:37a723ed87feac05c0504249", "client": "uapi/app/read/ReadPageClient.tsx:d14f0fbb65af0edfa68d774f", @@ -138,8 +138,8 @@ "publicCopy": "uapi/components/base/bitcode/layout/bitcode-public-copy.ts:3a45184ba8d2a4e71858c597", "publicExplainers": "uapi/components/base/bitcode/layout/bitcode-public-explainers.ts:282d915eac3c9f22ba8c07f1", "footer": "uapi/components/base/bitcode/layout/footer.tsx:44749b98e5f63e7ac8f9f574", - "packageIndex": "packages/protocol/src/index.js:d6fea9aa2abae4a717a3373a", - "packageTypes": "packages/protocol/src/index.d.ts:32caa412e41598f3c0c9bad8", + "packageIndex": "packages/protocol/src/index.js:533d73eb0b2cf01b4ac5c8b5", + "packageTypes": "packages/protocol/src/index.d.ts:307e3a474c62fcce0b015be6", "packageTest": "packages/protocol/test/v43-read-route-five-step-ux.test.js:fedf825a49244098367f6388", "routeModelTest": "uapi/tests/readRouteModel.test.ts:47d613cef4ab6dce86846c8f", "pageTest": "uapi/tests/readPageClient.test.tsx:9bd621c200f02082d0159cc5", diff --git a/.bitcode/v43-route-vocabulary-inventory.json b/.bitcode/v43-route-vocabulary-inventory.json index 75eabfa2..a685c692 100644 --- a/.bitcode/v43-route-vocabulary-inventory.json +++ b/.bitcode/v43-route-vocabulary-inventory.json @@ -5,7 +5,7 @@ "currentTarget": "V42", "sourceSafetyVerdict": "source-safe-route-vocabulary-inventory-metadata", "generatedAt": "deterministic", - "artifactRoot": "v43-route-vocabulary-inventory:76618af5465e2b1ebfe54d8f", + "artifactRoot": "v43-route-vocabulary-inventory:70e81bcca62f07362dfcb38c", "passed": true, "tokenIds": [ "route:/exchange", @@ -2081,7 +2081,7 @@ }, { "path": "BITCODE_SPEC_V43.md", - "pathRoot": "v43-route-vocabulary-file:69d0686a09cba4e2837e6c81", + "pathRoot": "v43-route-vocabulary-file:460d8c8dbf26f869e8308f65", "categories": [ "doc", "spec", @@ -2090,7 +2090,7 @@ "tokenCounts": { "route:/exchange": 5, "route:/terminal": 5, - "route:/packs": 17, + "route:/packs": 18, "route:/read": 18, "route:/deposit": 15, "symbol:Exchange": 4, @@ -2104,14 +2104,14 @@ "word:terminal": 5, "word:self-referential": 4 }, - "totalMatches": 124, + "totalMatches": 125, "sourceSafeMetadataOnly": true, "rawSourceTextSerialized": false, "sourceSnippetSerialized": false }, { "path": "BITCODE_SPEC_V43_DELTA.md", - "pathRoot": "v43-route-vocabulary-file:e1f2e7f6e037a3d62fef4671", + "pathRoot": "v43-route-vocabulary-file:d0228ac3d68cb6d5681900dd", "categories": [ "doc", "spec", @@ -2120,9 +2120,9 @@ "tokenCounts": { "route:/exchange": 4, "route:/terminal": 2, - "route:/packs": 11, + "route:/packs": 12, "route:/read": 8, - "route:/deposit": 8, + "route:/deposit": 9, "symbol:Exchange": 2, "symbol:Terminal": 4, "symbol:Reading": 6, @@ -2133,14 +2133,14 @@ "word:terminal": 2, "word:self-referential": 3 }, - "totalMatches": 60, + "totalMatches": 62, "sourceSafeMetadataOnly": true, "rawSourceTextSerialized": false, "sourceSnippetSerialized": false }, { "path": "BITCODE_SPEC_V43_NOTES.md", - "pathRoot": "v43-route-vocabulary-file:dd302d5840c0d8020e6181c1", + "pathRoot": "v43-route-vocabulary-file:233ba30dfc52405c5c397acb", "categories": [ "doc", "spec", @@ -2149,7 +2149,7 @@ "tokenCounts": { "route:/exchange": 2, "route:/terminal": 1, - "route:/packs": 7, + "route:/packs": 8, "route:/read": 5, "route:/deposit": 4, "symbol:Exchange": 1, @@ -2163,14 +2163,14 @@ "word:terminal": 1, "word:self-referential": 2 }, - "totalMatches": 37, + "totalMatches": 38, "sourceSafeMetadataOnly": true, "rawSourceTextSerialized": false, "sourceSnippetSerialized": false }, { "path": "BITCODE_SPEC_V43_PARITY_MATRIX.md", - "pathRoot": "v43-route-vocabulary-file:2ac1fc5494f30b6fdbe53d19", + "pathRoot": "v43-route-vocabulary-file:08f0c7cb30e04720cbe51840", "categories": [ "doc", "spec" @@ -2178,9 +2178,9 @@ "tokenCounts": { "route:/exchange": 3, "route:/terminal": 1, - "route:/packs": 6, + "route:/packs": 7, "route:/read": 6, - "route:/deposit": 7, + "route:/deposit": 8, "symbol:Packs": 1, "symbol:Reading": 1, "symbol:PackActivity": 4, @@ -2189,7 +2189,7 @@ "word:terminal": 1, "word:self-referential": 2 }, - "totalMatches": 36, + "totalMatches": 38, "sourceSafeMetadataOnly": true, "rawSourceTextSerialized": false, "sourceSnippetSerialized": false @@ -2314,7 +2314,7 @@ }, { "path": "README.md", - "pathRoot": "v43-route-vocabulary-file:b25272f972595511a2e5f1bc", + "pathRoot": "v43-route-vocabulary-file:ff44a442f13c63b599e9d939", "categories": [ "doc", "telemetry" @@ -2322,7 +2322,7 @@ "tokenCounts": { "route:/exchange": 5, "route:/terminal": 5, - "route:/packs": 9, + "route:/packs": 10, "route:/read": 8, "route:/deposit": 7, "symbol:Exchange": 16, @@ -2336,14 +2336,14 @@ "word:terminal": 7, "word:self-referential": 2 }, - "totalMatches": 147, + "totalMatches": 148, "sourceSafeMetadataOnly": true, "rawSourceTextSerialized": false, "sourceSnippetSerialized": false }, { "path": "SPECIFICATIONS_ROADMAP.md", - "pathRoot": "v43-route-vocabulary-file:6983f144935cd91791f4bab9", + "pathRoot": "v43-route-vocabulary-file:57b411ed167476617c185746", "categories": [ "doc", "spec", @@ -2352,9 +2352,9 @@ "tokenCounts": { "route:/exchange": 4, "route:/terminal": 3, - "route:/packs": 9, + "route:/packs": 10, "route:/read": 10, - "route:/deposit": 7, + "route:/deposit": 8, "symbol:Exchange": 25, "symbol:Terminal": 42, "symbol:Reading": 59, @@ -2365,7 +2365,7 @@ "word:terminal": 6, "word:self-referential": 3 }, - "totalMatches": 201, + "totalMatches": 203, "sourceSafeMetadataOnly": true, "rawSourceTextSerialized": false, "sourceSnippetSerialized": false @@ -4795,6 +4795,22 @@ "rawSourceTextSerialized": false, "sourceSnippetSerialized": false }, + { + "path": "packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts", + "pathRoot": "v43-route-vocabulary-file:afe8e3fb4d29f1b988768184", + "categories": [ + "package", + "test" + ], + "tokenCounts": { + "route:/deposit": 2, + "symbol:Reading": 1 + }, + "totalMatches": 3, + "sourceSafeMetadataOnly": true, + "rawSourceTextSerialized": false, + "sourceSnippetSerialized": false + }, { "path": "packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-options.test.ts", "pathRoot": "v43-route-vocabulary-file:96749aa8ed22eaa357174623", @@ -5156,6 +5172,21 @@ "rawSourceTextSerialized": false, "sourceSnippetSerialized": false }, + { + "path": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "pathRoot": "v43-route-vocabulary-file:c16791dbd3acae9a9143790b", + "categories": [ + "package" + ], + "tokenCounts": { + "route:/deposit": 3, + "symbol:DepositAssetPackOption": 8 + }, + "totalMatches": 11, + "sourceSafeMetadataOnly": true, + "rawSourceTextSerialized": false, + "sourceSnippetSerialized": false + }, { "path": "packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts", "pathRoot": "v43-route-vocabulary-file:f3d165e7891d499973f55f24", @@ -5889,7 +5920,7 @@ }, { "path": "packages/protocol/README.md", - "pathRoot": "v43-route-vocabulary-file:6ef7463895b607b04eede3f4", + "pathRoot": "v43-route-vocabulary-file:92166b0423e4bbda7dc2f0ab", "categories": [ "doc", "package", @@ -5898,7 +5929,7 @@ "tokenCounts": { "route:/exchange": 4, "route:/terminal": 2, - "route:/packs": 6, + "route:/packs": 7, "route:/read": 5, "route:/deposit": 3, "symbol:Exchange": 17, @@ -5911,7 +5942,7 @@ "word:terminal": 6, "word:self-referential": 1 }, - "totalMatches": 131, + "totalMatches": 132, "sourceSafeMetadataOnly": true, "rawSourceTextSerialized": false, "sourceSnippetSerialized": false @@ -7107,6 +7138,20 @@ "rawSourceTextSerialized": false, "sourceSnippetSerialized": false }, + { + "path": "packages/protocol/src/canonical/v43-deposit-policy-compensation.js", + "pathRoot": "v43-route-vocabulary-file:cd9271147b9b9528c7da1b1e", + "categories": [ + "package" + ], + "tokenCounts": { + "route:/deposit": 3 + }, + "totalMatches": 3, + "sourceSafeMetadataOnly": true, + "rawSourceTextSerialized": false, + "sourceSnippetSerialized": false + }, { "path": "packages/protocol/src/canonical/v43-deposit-route-options.js", "pathRoot": "v43-route-vocabulary-file:fd99b475c329e18fdeacc290", @@ -9943,6 +9988,20 @@ "rawSourceTextSerialized": false, "sourceSnippetSerialized": false }, + { + "path": "scripts/check-v43-gate6-deposit-policy-compensation.mjs", + "pathRoot": "v43-route-vocabulary-file:e502f4561c7b1e9768555bc1", + "categories": [ + "script" + ], + "tokenCounts": { + "route:/deposit": 2 + }, + "totalMatches": 2, + "sourceSafeMetadataOnly": true, + "rawSourceTextSerialized": false, + "sourceSnippetSerialized": false + }, { "path": "scripts/code-review/README.md", "pathRoot": "v43-route-vocabulary-file:fef2886ffeed000a3327379c", @@ -15555,20 +15614,20 @@ } ], "coverage": { - "sourceFileCount": 914, + "sourceFileCount": 918, "tokenTotals": { "route:/exchange": 147, "route:/terminal": 1475, - "route:/packs": 153, + "route:/packs": 160, "route:/read": 294, - "route:/deposit": 140, + "route:/deposit": 153, "symbol:Exchange": 1964, "symbol:Terminal": 3091, "symbol:Packs": 50, - "symbol:Reading": 1333, + "symbol:Reading": 1334, "symbol:Depositing": 243, "symbol:PackActivity": 28, - "symbol:DepositAssetPackOption": 21, + "symbol:DepositAssetPackOption": 29, "word:exchange": 1708, "word:terminal": 3735, "word:self-referential": 30 @@ -15576,13 +15635,13 @@ "categoryTotals": { "route": 14, "component": 150, - "test": 221, + "test": 222, "doc": 169, "api": 43, "telemetry": 655, "workflow": 12, - "script": 119, - "package": 314, + "script": 120, + "package": 317, "spec": 76 }, "routeVocabularyInventoryComplete": true, diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index ee497868..20897797 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -340,6 +340,9 @@ jobs: if [ -f scripts/check-v43-gate5-deposit-route-options.mjs ]; then node scripts/check-v43-gate5-deposit-route-options.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ -f scripts/check-v43-gate6-deposit-policy-compensation.mjs ]; then + node scripts/check-v43-gate6-deposit-policy-compensation.mjs --skip-branch-check --skip-uapi-tests --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 3e31fdcb..1a3a268f 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -469,6 +469,9 @@ jobs: if [ -f scripts/check-v43-gate5-deposit-route-options.mjs ]; then node scripts/check-v43-gate5-deposit-route-options.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ -f scripts/check-v43-gate6-deposit-policy-compensation.mjs ]; then + node scripts/check-v43-gate6-deposit-policy-compensation.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 @@ -514,6 +517,9 @@ jobs: if [ -f scripts/check-v43-gate5-deposit-route-options.mjs ]; then node scripts/check-v43-gate5-deposit-route-options.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ -f scripts/check-v43-gate6-deposit-policy-compensation.mjs ]; then + node scripts/check-v43-gate6-deposit-policy-compensation.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests + fi pnpm --filter @bitcode/protocol test pnpm --filter @bitcode/btd exec jest --config jest.config.cjs --runInBand --forceExit pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --passWithNoTests --forceExit diff --git a/BITCODE_SPEC_V43.md b/BITCODE_SPEC_V43.md index 72a49774..9883a127 100644 --- a/BITCODE_SPEC_V43.md +++ b/BITCODE_SPEC_V43.md @@ -183,7 +183,19 @@ be serialized into route state or generated proof artifacts. ## V43 Gate 6 Source Criticality, Demand, ROI, And Compensation Policy -Gate 6 must formalize how Bitcode estimates sub-critical source posture, likely demand, positive ROI, BTD potential, compensation route, and admission blockers. The system must help depositors sell non-critical positive-ROI IP while refusing or warning on critical IP and negative expected value. +Gate 6 formalizes how Bitcode estimates sub-critical source posture, likely demand, positive ROI, BTD potential, compensation route, and admission blockers. The system helps depositors sell non-critical positive-ROI IP while refusing or warning on critical IP and negative expected value. + +Gate 6 closes with `DepositAssetPackOptionPolicy`, +`DepositAssetPackOptionPolicyReport`, and the generated +`.bitcode/v43-deposit-policy-compensation.json` proof. The policy consumes the +source-safe `DepositAssetPackOptionSynthesis` output plus source-safe +criticality signals, estimated development cost, expected future settlement, +and depositor wallet posture. It emits per-option policy evaluations for source +criticality, demand, ROI, BTD potential, and BTC source-to-shares compensation +route. BTD potential remains estimate-only: no BTD mint, paid rights transfer, +or source-bearing disclosure occurs until a future accepted Need-Fit settlement. +Deposit option approval, Depository admission, indexing, storage projection, +and `/packs` synchronization remain Gate 7 responsibilities. ## V43 Gate 7 Deposit Option Review, Approval, And Admission @@ -205,12 +217,12 @@ Gate 10 must bind every V43 artifact, workflow, generated proof, docs update, ro ### Depositing and asset supply -- Current canonical objects and emitted artifacts: DepositRouteSession, DepositAssetPackOption, DepositOptionSynthesisRequest, DepositAssetPackOptionSynthesis, Depository record, source admission proof, compensation preview, `.bitcode/v43-deposit-route-options.json`. -- Current algorithms and derivation rules: connected-source selection, depositor instruction rooting, source path rooting, Depository demand signal roots, Reading demand signal roots, existing supply signal roots, option grouping, measurement projection, and source-safe review posture. -- Current invariants and fail-closed conditions: invalid repository binding, missing source hints, policy deferred to Gate 6, admission/indexing deferred to Gate 7, and protected-source leak. -- Current proof obligations: source-safe option synthesis, option review boundary, future admission boundary, compensation preview deferral, and activity synchronization. -- Current source-bearing implementation basis: `/deposit` route, `DepositRouteSession`, asset-pack pipeline package option synthesis, existing deposit composer, source-safe route tests, and generated protocol artifact. -- Current validating commands and parity basis: `pnpm run check:v43-gate5`, package tests, API tests, and generated artifacts. +- Current canonical objects and emitted artifacts: DepositRouteSession, DepositAssetPackOption, DepositOptionSynthesisRequest, DepositAssetPackOptionSynthesis, DepositAssetPackOptionPolicy, DepositAssetPackOptionPolicyReport, Depository record, source admission proof, compensation preview, `.bitcode/v43-deposit-route-options.json`, and `.bitcode/v43-deposit-policy-compensation.json`. +- Current algorithms and derivation rules: connected-source selection, depositor instruction rooting, source path rooting, Depository demand signal roots, Reading demand signal roots, existing supply signal roots, option grouping, measurement projection, source-safe review posture, source criticality scoring, weighted demand scoring, deterministic gross-minus-cost ROI scoring, estimate-only BTD potential, and future-reader BTC source-to-shares compensation route preview. +- Current invariants and fail-closed conditions: invalid repository binding, missing source hints, critical-source block, negative expected value warning/block, missing wallet compensation repair posture, admission/indexing deferred to Gate 7, and protected-source leak. +- Current proof obligations: source-safe option synthesis, option policy report, option review boundary, future admission boundary, compensation route preview, BTD mint boundary, and activity synchronization. +- Current source-bearing implementation basis: `/deposit` route, `DepositRouteSession`, asset-pack pipeline package option synthesis, asset-pack package policy report, existing deposit composer, source-safe route tests, package tests, and generated protocol artifacts. +- Current validating commands and parity basis: `pnpm run check:v43-gate5`, `pnpm run check:v43-gate6`, package tests, API tests, and generated artifacts. - Current accepted boundaries: options are not BTD mints and do not expose source to readers before settlement. ### Reading and prompt/inference ownership diff --git a/BITCODE_SPEC_V43_DELTA.md b/BITCODE_SPEC_V43_DELTA.md index 6b46852f..4146d1c4 100644 --- a/BITCODE_SPEC_V43_DELTA.md +++ b/BITCODE_SPEC_V43_DELTA.md @@ -93,6 +93,21 @@ state. Source criticality, demand/ROI, compensation policy, deposit admission, and indexing remain explicit Gate 6/Gate 7 boundaries. The route and artifact remain source-safe metadata only. +## Gate 6 delta closure + +Gate 6 adds `DepositAssetPackOptionPolicy`, +`DepositAssetPackOptionPolicyReport`, the generated +`.bitcode/v43-deposit-policy-compensation.json` artifact, package exports, +protocol tests, workflow checks, `/deposit` policy readback, and focused +route/package tests. The policy scores each source-safe deposit option for +criticality, likely demand, estimated gross BTC value, development-cost ROI, +estimate-only BTD potential, and future-reader BTC source-to-shares +compensation route. Critical IP is blocked before admission, negative expected +value is not reviewable as positive-ROI supply, and missing wallet posture +requires compensation repair. Admission, Depository indexing, storage +projection, `/packs` synchronization, and final approve/reject/resynthesize +decisions remain Gate 7 boundaries. + ## Commit-Body Direction V43 gate commits should state the route/product surface changed, the protocol objects preserved, the proof/test commands run, and the source-safety boundaries maintained. Gate PR titles must begin with `V43 Gate N:`. diff --git a/BITCODE_SPEC_V43_NOTES.md b/BITCODE_SPEC_V43_NOTES.md index 7a3c2b2e..b0a74cc2 100644 --- a/BITCODE_SPEC_V43_NOTES.md +++ b/BITCODE_SPEC_V43_NOTES.md @@ -53,6 +53,16 @@ review posture, and proof roots; it may not serialize raw source, unpaid AssetPack source, prompts, provider responses, credentials, or wallet private material. +Gate 6 closes the criticality, demand, ROI, BTD-potential, and compensation +policy layer without admitting source into the Depository. `DepositAssetPackOptionPolicyReport` +is source-safe metadata: it records signal roots, policy decisions, expected net +sats, estimate-only BTD posture, and future BTC source-to-shares compensation +route. It must not serialize raw source, unpaid AssetPack source, prompts, +provider responses, wallet private material, or private settlement payloads. +Gate 7 remains responsible for depositor approval, reject/resynthesize +decisions, Depository admission receipts, indexing, storage projection, +telemetry, and `/packs` activity synchronization. + ## V43 copy boundary Outside public docs, avoid self-referential copy such as text explaining that a component is powerful or that Bitcode is doing a thing. Use clear route names, labels, status rows, measurement summaries, empty states, and expandable proof metadata. Public docs may explain the protocol; product UI should operate it. diff --git a/BITCODE_SPEC_V43_PARITY_MATRIX.md b/BITCODE_SPEC_V43_PARITY_MATRIX.md index 70ba2474..fa471553 100644 --- a/BITCODE_SPEC_V43_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V43_PARITY_MATRIX.md @@ -8,7 +8,7 @@ - Prior canonical anchor: `BITCODE_SPEC_V42.md` - Prior generated proof appendix: `BITCODE_SPEC_V42_PROVEN.md` - Generated structured artifact inventory: `.bitcode/v43-spec-family-report.json`, `.bitcode/v43-canonical-input-report.json`, and future V43 gate artifacts -- Source parity state: V43 Gate 1 parity is documentation/workflow posture; V43 Gate 2 parity is source-safe inventory and migration planning; V43 Gate 3 parity is PackActivity source-safe master-detail implementation; V43 Gate 4 parity is `/read`; V43 Gate 5 parity is `/deposit` and source-safe DepositAssetPackOption synthesis +- Source parity state: V43 Gate 1 parity is documentation/workflow posture; V43 Gate 2 parity is source-safe inventory and migration planning; V43 Gate 3 parity is PackActivity source-safe master-detail implementation; V43 Gate 4 parity is `/read`; V43 Gate 5 parity is `/deposit` and source-safe DepositAssetPackOption synthesis; V43 Gate 6 parity is source-safe deposit policy and compensation scoring ## Purpose @@ -27,7 +27,7 @@ Audit V43 against `BITCODE_SPEC_V43.md`, V42 active canon, route source, package | Packs master-detail | Searchable, sortable, filterable pack activity table, source-safe detail route, proof-root display, settlement/compensation/delivery/repair readback, and `/exchange` compatibility redirect | `packages/protocol/src/canonical/v43-packs-activity-master-detail.js`, `.bitcode/v43-packs-activity-master-detail.json`, `uapi/app/packs`, `uapi/app/api/packs/activity/route.ts`, `uapi/components/base/bitcode/activity/pack-activity-model.ts` | implemented | | Read route | `ReadRouteSession` and five-step Reading UX own Read Request, synthesized Need review, accepted-Need-gated Finding Fits, source-safe AssetPack preview, BTC settlement, and delivery posture | `packages/protocol/src/canonical/v43-read-route-five-step-ux.js`, `.bitcode/v43-read-route-five-step-ux.json`, `uapi/app/read`, `uapi/app/read/read-route-model.ts` | implemented | | Deposit route | `DepositRouteSession`, `/deposit`, source-safe connected-source option synthesis, source-safe option cards, route tests, package tests, generated proof, and retained deposit composer reuse | `packages/protocol/src/canonical/v43-deposit-route-options.js`, `.bitcode/v43-deposit-route-options.json`, `uapi/app/deposit`, `packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts` | implemented | -| Criticality/ROI policy | Source criticality, demand, ROI, BTD potential, and compensation posture | future Gate 6 artifact | draft-required | +| Criticality/ROI policy | Source criticality, demand, ROI, BTD potential, and BTC source-to-shares compensation posture | `packages/protocol/src/canonical/v43-deposit-policy-compensation.js`, `.bitcode/v43-deposit-policy-compensation.json`, `packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts`, `/deposit` policy readback | implemented | | Admission sync | Approved deposit options enter Depository and `/packs` activity | future Gate 7 artifact | draft-required | | UX excellence | Self-explanatory, polished, progressive-detail UI without self-referential product copy | future Gate 8 artifact | draft-required | | Rehearsal | Local/staging-testnet cross-route path verifies deposit, read, packs, settlement, compensation, delivery | future Gate 9 artifact | draft-required | @@ -45,7 +45,8 @@ Audit V43 against `BITCODE_SPEC_V43.md`, V42 active canon, route source, package | Gate 3 PackActivity proof | `V43PacksActivityMasterDetail` exports, generated artifact, source-safe model/API/UI tests, workflow checks, and `check:v43-gate3` exist | implemented | | Gate 4 Read route proof | `V43ReadRouteFiveStepUx` exports, generated artifact, source-safe route model/UI tests, workflow checks, and `check:v43-gate4` exist | implemented | | Gate 5 Deposit route proof | `V43DepositRouteOptions` exports, generated artifact, source-safe route model/UI tests, asset-pack option synthesis tests, workflow checks, and `check:v43-gate5` exist | implemented | -| Implementation | Route and pipeline source changes are not part of Gates 1 or 2; Gate 3 implements only `/packs` and PackActivity; Gate 4 implements `/read`; Gate 5 implements `/deposit` option synthesis while leaving policy/admission to Gates 6 and 7 | accepted boundary | +| Gate 6 Deposit policy proof | `DepositAssetPackOptionPolicyReport`, generated artifact, source-safe route model/UI tests, asset-pack policy tests, workflow checks, and `check:v43-gate6` exist | implemented | +| Implementation | Route and pipeline source changes are not part of Gates 1 or 2; Gate 3 implements only `/packs` and PackActivity; Gate 4 implements `/read`; Gate 5 implements `/deposit` option synthesis; Gate 6 implements policy scoring while leaving approval/admission/indexing to Gate 7 | accepted boundary | ## V43 accepted boundaries @@ -54,8 +55,10 @@ to inventory and plan migration only. Gate 3 may implement `/packs`, PackActivity, and `/exchange` compatibility redirect only. It must not extract `/read`, extract `/deposit`, or add deposit option synthesis behavior before their owning implementation gates. Gate 5 may implement `/deposit` and -source-safe option synthesis, but it must not decide Gate 6 criticality/ROI -policy or Gate 7 admission/indexing. +source-safe option synthesis. Gate 6 may decide source-safe criticality, demand, +ROI, BTD potential, and compensation posture, but it must not approve, admit, +index, store, or synchronize deposit AssetPacks into `/packs`; those remain Gate +7 responsibilities. ## V43 completion condition diff --git a/README.md b/README.md index b2422b39..488c049b 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,17 @@ reuse, navigation/footer route ownership, and focused UAPI/package/protocol tests. `/deposit` does not decide source criticality, ROI, compensation policy, admission, or indexing; those stay deferred to V43 Gates 6 and 7. +V43 Gate 6 adds `DepositAssetPackOptionPolicyReport`, +`.bitcode/v43-deposit-policy-compensation.json`, +`generate:v43-deposit-policy-compensation`, +`check:v43-deposit-policy-compensation`, and `check:v43-gate6`. It implements +source-safe policy scoring for source criticality, likely demand, estimated +ROI, estimate-only BTD potential, and future-reader BTC source-to-shares +compensation route. Critical source is blocked before admission, negative +expected value is not treated as positive-ROI supply, and Gate 7 still owns +approval, admission, indexing, storage projection, telemetry, and `/packs` +activity synchronization. + Exchange is inherited V36 canon: market-wide activity master-detail, buy/sell/ bid/ask/cancel/accept/settle/history flows, AssetPack range trading, rights-transfer review, pricing/liquidity/wrapper analysis, settlement diff --git a/SPECIFICATIONS_ROADMAP.md b/SPECIFICATIONS_ROADMAP.md index 134ae49c..366d3724 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -5,8 +5,8 @@ - Current active canonical pointer: `BITCODE_SPEC.txt` -> `V42` - Current active canon: `BITCODE_SPEC_V42.md` - Current draft target: `BITCODE_SPEC_V43.md`. -- Current working gate: V43 Gate 5 Deposit Route And Agentic AssetPack Option Synthesis. -- Next queued work after V43 Gate 5: source criticality, demand, ROI, and compensation policy for deposit AssetPack options. +- Current working gate: V43 Gate 6 Source Criticality, Demand, ROI, And Compensation Policy. +- Next queued work after V43 Gate 6: deposit option review, approval, admission receipts, Depository indexing, storage projection, telemetry, and `/packs` activity synchronization. - Latest closed version: V42 Reliable MVP Experience, which promoted shortest-path Depositing, five-step Reading, ReadNeed review/resynthesis, ReadFitsFinding source-safe preview and quote, settlement rights transfer, repository delivery, AI-reading demonstration, local/staging MVP rehearsal, and V42 promotion readiness. - Recent V42 canonical promotion anchor: V42 canonical promotion updated `BITCODE_SPEC.txt` to `V42`, generated `BITCODE_SPEC_V42_PROVEN.md`, preserved active V42 / draft V43 runtime posture, and closed reliable MVP experience canon. - Recent V42 opening anchor: reliable MVP experience opens over promoted V41 with V42 SPEC, DELTA, NOTES, and PARITY files, `check:v42-gate1`, active V41 / draft V42 posture, and a nine-gate plan for shortest-path Depositing, five-step Reading, ReadNeed product closure, ReadFitsFinding preview and quote closure, settlement and repository delivery, AI-reading demonstration, local/staging rehearsal, and promotion readiness. @@ -22,6 +22,7 @@ - V43 Gate 3 closure anchor: route-product cleanup now owns package-backed `V43PacksActivityMasterDetail`, deterministic `.bitcode/v43-packs-activity-master-detail.json`, `PackActivityRecord`, `PacksActivityDetail`, `/api/packs/activity`, `/packs` master-detail UI, `/exchange` compatibility redirect, search, type/state filtering, column sorting, proof-root display, settlement/compensation/delivery/repair readback, no-source leak tests, package exports, protocol tests, workflow wiring, and `check:v43-gate3`. - V43 Gate 4 closure anchor: route-product cleanup now owns package-backed `V43ReadRouteFiveStepUx`, deterministic `.bitcode/v43-read-route-five-step-ux.json`, `ReadRouteSession`, `/read`, five-step Reading UX, Read Request, synthesized Need review, accepted-Need-gated Finding Fits, source-safe AssetPack preview, BTC settlement/delivery posture, retained execution stream readback, route/nav/footer ownership, focused UAPI/protocol tests, workflow wiring, and `check:v43-gate4`. - V43 Gate 5 closure anchor: route-product cleanup now owns package-backed `V43DepositRouteOptions`, deterministic `.bitcode/v43-deposit-route-options.json`, `DepositRouteSession`, `/deposit`, five-step Depositing UX, connected-source option synthesis, `DepositAssetPackOptionSynthesis`, source-safe AssetPack option cards, option measurement roots, demand signal roots, retained deposit composer reuse, route/nav/footer ownership, focused UAPI/package/protocol tests, workflow wiring, and `check:v43-gate5`. +- V43 Gate 6 closure anchor: route-product cleanup now owns package-backed `DepositAssetPackOptionPolicyReport`, deterministic `.bitcode/v43-deposit-policy-compensation.json`, source criticality scoring, likely demand scoring, deterministic estimated-gross-minus-development-cost ROI, estimate-only BTD potential, future-reader BTC source-to-shares compensation route preview, critical-source pre-admission blocking, `/deposit` policy readback, source-safe route/package/protocol tests, workflow wiring, and `check:v43-gate6`. - Recent V41 closure anchor: V41 canonical promotion updated `BITCODE_SPEC.txt` to `V41`, generated `BITCODE_SPEC_V41_PROVEN.md`, preserved active V41 / draft V42 runtime posture, and closed prompt-program excellence canon. - Recent V40 closure anchor: V40 canonical promotion updated `BITCODE_SPEC.txt` to `V40`, generated `BITCODE_SPEC_V40_PROVEN.md`, preserved active V40 / draft V41 runtime posture, and closed exhaustive commercial application testing canon. - Recent V39 closure anchor: V39 canonical promotion updated `BITCODE_SPEC.txt` to `V39`, generated `BITCODE_SPEC_V39_PROVEN.md`, preserved active V39 / draft V40 runtime posture, and closed commercial Reading readiness canon. diff --git a/package.json b/package.json index 233b1cb7..acff48d9 100644 --- a/package.json +++ b/package.json @@ -342,6 +342,9 @@ "generate:v43-deposit-route-options": "node scripts/generate-v43-deposit-route-options.mjs", "check:v43-deposit-route-options": "node scripts/generate-v43-deposit-route-options.mjs --check", "check:v43-gate5": "node scripts/check-v43-gate5-deposit-route-options.mjs", + "generate:v43-deposit-policy-compensation": "node scripts/generate-v43-deposit-policy-compensation.mjs", + "check:v43-deposit-policy-compensation": "node scripts/generate-v43-deposit-policy-compensation.mjs --check", + "check:v43-gate6": "node scripts/check-v43-gate6-deposit-policy-compensation.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/pipelines/asset-pack/package.json b/packages/pipelines/asset-pack/package.json index 50e814f7..c597bbb4 100644 --- a/packages/pipelines/asset-pack/package.json +++ b/packages/pipelines/asset-pack/package.json @@ -13,6 +13,7 @@ "./reading-interface-product-parity": "./src/reading-interface-product-parity.ts", "./reading-local-staging-rehearsal": "./src/reading-local-staging-rehearsal.ts", "./deposit-asset-pack-options": "./src/deposit-asset-pack-options.ts", + "./deposit-asset-pack-option-policy": "./src/deposit-asset-pack-option-policy.ts", "./read-need": "./src/read-need.ts", "./read-need-review-resynthesis": "./src/read-need-review-resynthesis.ts", "./read-fits-finding-runtime": "./src/read-fits-finding-runtime.ts", diff --git a/packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts b/packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts new file mode 100644 index 00000000..690873fb --- /dev/null +++ b/packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts @@ -0,0 +1,103 @@ +import { + buildDepositAssetPackOptionPolicyReport, + assertDepositAssetPackOptionPolicyReportSourceSafe, +} from '../deposit-asset-pack-option-policy'; +import { buildDepositAssetPackOptionSynthesis } from '../deposit-asset-pack-options'; + +function reviewableSynthesis() { + return buildDepositAssetPackOptionSynthesis({ + repositoryFullName: 'engineeredsoftware/ENGI', + sourceBranch: 'main', + sourceCommit: '31bbc0c5227b6b3aed5d107fd8507d35ec22970a', + depositorInstructions: 'Prepare source-safe deposit AssetPack options for non-critical reusable proof infrastructure.', + sourcePathHints: [ + 'uapi/app/deposit/DepositPageClient.tsx', + 'packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts', + ], + depositoryDemandSignals: [{ id: 'depository-gap', label: 'Depository needs reviewable source supply', weight: 0.8 }], + readingDemandSignals: [{ id: 'reading-fit-demand', label: 'Reading demand needs proof-bearing source fits', weight: 0.84 }], + existingDepositorySignals: [{ id: 'supply-route', label: 'Existing supply uses compensation preview roots', weight: 0.62 }], + }); +} + +describe('Deposit AssetPack option policy', () => { + it('scores reviewable options for criticality, demand, ROI, BTD potential, and BTC compensation route', () => { + const report = buildDepositAssetPackOptionPolicyReport({ + synthesis: reviewableSynthesis(), + sourceCriticalitySignals: [ + { + id: 'sub-critical-proof-surface', + label: 'Reusable proof surface is sub-critical to expose after settlement.', + severity: 'sub-critical', + weight: 0.82, + }, + ], + depositorWalletId: 'wallet-depositor-1', + developmentCostSats: 1500, + expectedSettlementSats: 5200, + }); + + expect(report.schema).toBe('bitcode.deposit.asset-pack-option-policy-report'); + expect(report.policy).toBe('DepositAssetPackOptionPolicy'); + expect(report.route).toBe('/deposit'); + expect(report.optionCount).toBe(3); + expect(report.reviewablePositiveRoiCount).toBeGreaterThan(0); + expect(report.aggregatePolicy).toMatchObject({ + criticalityPolicy: 'source-safe-criticality-signals-with-depositor-review', + demandPolicy: 'weighted-depository-reading-and-existing-supply-signals', + roiPolicy: 'deterministic-estimated-gross-minus-development-cost', + compensationPolicy: 'future-reader-btc-source-to-shares-route-preview', + admissionAndIndexingOwnedBy: 'future-gate7-deposit-option-review', + }); + for (const evaluation of report.evaluations) { + expect(evaluation.sourceCriticality.state).not.toBe('blocked-critical-source'); + expect(evaluation.demand.weightedDemand).toBeGreaterThan(0.5); + expect(evaluation.roi.estimatedGrossSats).toBeGreaterThan(0); + expect(evaluation.btdPotential.estimateOnly).toBe(true); + expect(evaluation.btdPotential.btdMintBoundary).toBe('not-minted-until-future-need-fit-settlement'); + expect(evaluation.compensation).toMatchObject({ + payer: 'future-reader-after-settlement', + payee: 'depositing-wallet', + priceAsset: 'BTC', + allocationMethod: 'source-to-shares-largest-remainder', + sourceToSharesProofState: 'not-created-until-accepted-need-fit-and-settlement', + }); + expect(evaluation.admissionBoundary).toMatchObject({ + depositApprovalRequired: true, + admissionAndIndexingOwnedBy: 'future-gate7-deposit-option-review', + sourceBearingDisclosureBeforeSettlementVisible: false, + }); + expect(evaluation.visibility.rawSourceTextVisible).toBe(false); + expect(evaluation.roots.policyEvaluationRoot).toMatch(/^deposit-policy-evaluation:/); + } + expect(assertDepositAssetPackOptionPolicyReportSourceSafe(report)).toEqual({ + admitted: true, + reason: 'source_safe_deposit_asset_pack_option_policy', + }); + expect(JSON.stringify(report)).not.toContain('PRIVATE_SOURCE_DO_NOT_SERIALIZE'); + }); + + it('blocks critical or negative-value options before Gate 7 admission without leaking source', () => { + const report = buildDepositAssetPackOptionPolicyReport({ + synthesis: reviewableSynthesis(), + sourceCriticalitySignals: [ + { + id: 'critical-core-warning', + label: 'Core IP would be critical to expose.', + severity: 'critical', + weight: 0.95, + }, + ], + developmentCostSats: 9000, + expectedSettlementSats: 1800, + depositorWalletId: null, + }); + + expect(report.blockedCount).toBe(3); + expect(report.evaluations.every((evaluation) => evaluation.policyDecision === 'blocked-before-admission')).toBe(true); + expect(report.evaluations.every((evaluation) => evaluation.sourceCriticality.state === 'blocked-critical-source')).toBe(true); + expect(report.evaluations.every((evaluation) => evaluation.compensation.state === 'blocked-before-compensation')).toBe(true); + expect(assertDepositAssetPackOptionPolicyReportSourceSafe(report).admitted).toBe(true); + expect(JSON.stringify(report)).not.toContain('Core IP'); + }); +}); diff --git a/packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts b/packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts new file mode 100644 index 00000000..b95b1b9d --- /dev/null +++ b/packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts @@ -0,0 +1,628 @@ +import type { + DepositAssetPackOption, + DepositAssetPackOptionSynthesis, + DepositOptionDemandSignal, +} from './deposit-asset-pack-options'; + +export type DepositOptionCriticalityState = + | 'sub-critical' + | 'review-warning' + | 'blocked-critical-source'; + +export type DepositOptionDemandState = + | 'strong-likely-demand' + | 'moderate-likely-demand' + | 'weak-likely-demand'; + +export type DepositOptionRoiState = + | 'positive-expected-value' + | 'marginal-expected-value' + | 'negative-expected-value' + | 'blocked-criticality'; + +export type DepositOptionBtdPotentialState = + | 'high-potential' + | 'moderate-potential' + | 'low-potential' + | 'blocked-until-policy-repair'; + +export type DepositOptionCompensationState = + | 'eligible-if-approved-and-selected' + | 'repair-required-before-compensation' + | 'blocked-before-compensation'; + +export interface DepositOptionCriticalitySignal { + id?: string | null; + label?: string | null; + severity?: 'sub-critical' | 'warning' | 'critical' | null; + weight?: number | null; +} + +export interface DepositAssetPackOptionPolicyInput { + synthesis: DepositAssetPackOptionSynthesis; + sourceCriticalitySignals?: DepositOptionCriticalitySignal[] | null; + developmentCostSats?: number | null; + expectedSettlementSats?: number | null; + depositorWalletId?: string | null; + createdAt?: string | null; +} + +export interface DepositAssetPackOptionPolicyEvaluation { + schema: 'bitcode.deposit.asset-pack-option-policy-evaluation'; + optionId: string; + optionKind: DepositAssetPackOption['kind']; + title: string; + policyDecision: + | 'reviewable-positive-roi' + | 'review-warning-before-admission' + | 'blocked-before-admission'; + sourceCriticality: { + state: DepositOptionCriticalityState; + score: number; + signalRoots: string[]; + blockers: string[]; + warnings: string[]; + }; + demand: { + state: DepositOptionDemandState; + confidence: number; + weightedDemand: number; + demandRoot: string; + }; + roi: { + state: DepositOptionRoiState; + estimatedGrossSats: number; + estimatedDevelopmentCostSats: number; + expectedNetSats: number; + roiMultiple: number; + roiRoot: string; + }; + btdPotential: { + state: DepositOptionBtdPotentialState; + estimatedKnowledgeVolume: number; + estimatedBtdCells: number; + estimateOnly: true; + btdMintBoundary: 'not-minted-until-future-need-fit-settlement'; + rightsBoundary: 'depositor-retains-rights-until-paid-reader-settlement-transfer'; + btdPotentialRoot: string; + }; + compensation: { + state: DepositOptionCompensationState; + payer: 'future-reader-after-settlement'; + payee: 'depositing-wallet'; + priceAsset: 'BTC'; + allocationMethod: 'source-to-shares-largest-remainder'; + depositorShareBasisPoints: number; + protocolTreasuryBasisPoints: number; + sourceToSharesProofState: 'not-created-until-accepted-need-fit-and-settlement'; + eligibleIfApprovedAndSelected: boolean; + blockers: string[]; + warnings: string[]; + compensationRouteRoot: string; + }; + admissionBoundary: { + depositApprovalRequired: true; + admissionAndIndexingOwnedBy: 'future-gate7-deposit-option-review'; + sourceBearingDisclosureBeforeSettlementVisible: false; + }; + visibility: { + sourceSafeMetadataOnly: true; + protectedSourceVisible: false; + rawSourceTextVisible: false; + unpaidAssetPackSourceVisible: false; + rawPromptVisible: false; + interpolatedPromptVisible: false; + rawProviderResponseVisible: false; + walletPrivateMaterialVisible: false; + settlementPrivatePayloadVisible: false; + }; + roots: { + policyEvaluationRoot: string; + sourceCriticalityRoot: string; + demandRoot: string; + roiRoot: string; + btdPotentialRoot: string; + compensationRouteRoot: string; + }; +} + +export interface DepositAssetPackOptionPolicyReport { + schema: 'bitcode.deposit.asset-pack-option-policy-report'; + policy: 'DepositAssetPackOptionPolicy'; + reportId: string; + createdAt: string; + route: '/deposit'; + synthesisRequestId: string; + optionCount: number; + reviewablePositiveRoiCount: number; + warningCount: number; + blockedCount: number; + evaluations: DepositAssetPackOptionPolicyEvaluation[]; + aggregatePolicy: { + criticalityPolicy: 'source-safe-criticality-signals-with-depositor-review'; + demandPolicy: 'weighted-depository-reading-and-existing-supply-signals'; + roiPolicy: 'deterministic-estimated-gross-minus-development-cost'; + compensationPolicy: 'future-reader-btc-source-to-shares-route-preview'; + admissionAndIndexingOwnedBy: 'future-gate7-deposit-option-review'; + }; + sourceSafety: { + sourceSafeMetadataOnly: true; + protectedSourceVisible: false; + rawSourceTextVisible: false; + unpaidAssetPackSourceVisible: false; + rawPromptVisible: false; + interpolatedPromptVisible: false; + rawProviderResponseVisible: false; + walletPrivateMaterialVisible: false; + settlementPrivatePayloadVisible: false; + }; + roots: { + policyReportRoot: string; + synthesisRoot: string; + evaluationRoots: string[]; + aggregatePolicyRoot: string; + }; +} + +const FORBIDDEN_SOURCE_MARKERS = [ + 'PRIVATE_SOURCE_DO_NOT_SERIALIZE', + `BEGIN_${'PRIVATE'}_KEY`, + 'wallet_private_material', + 'raw_provider_response', + 'unpaid_assetpack_source', +]; + +function stableStringify(value: unknown): string { + if (value === null || typeof value !== 'object') return JSON.stringify(value); + if (Array.isArray(value)) return `[${value.map((entry) => stableStringify(entry)).join(',')}]`; + return `{${Object.keys(value as Record) + .sort() + .map((key) => `${JSON.stringify(key)}:${stableStringify((value as Record)[key])}`) + .join(',')}}`; +} + +function stableHash(value: unknown) { + const text = typeof value === 'string' ? value : stableStringify(value); + let hash = 2166136261; + for (let index = 0; index < text.length; index += 1) { + hash ^= text.charCodeAt(index); + hash = Math.imul(hash, 16777619); + } + return (hash >>> 0).toString(16).padStart(8, '0'); +} + +function root(prefix: string, value: unknown) { + return `${prefix}:${stableHash(value)}`; +} + +function normalizedText(value: string | null | undefined) { + const normalized = value?.trim(); + return normalized ? normalized : null; +} + +function boundedUnit(value: number | null | undefined, fallback: number) { + const numeric = Number(value ?? fallback); + if (!Number.isFinite(numeric)) return fallback; + return Math.max(0, Math.min(1, numeric)); +} + +function positiveInteger(value: number | null | undefined, fallback: number) { + const numeric = Number(value ?? fallback); + if (!Number.isFinite(numeric)) return fallback; + return Math.max(0, Math.round(numeric)); +} + +function normalizedCriticalitySignals(value: DepositOptionCriticalitySignal[] | null | undefined) { + return (value || []) + .map((signal, index) => ({ + id: normalizedText(signal.id) || `criticality-signal-${index + 1}`, + label: normalizedText(signal.label) || `Criticality signal ${index + 1}`, + severity: signal.severity || 'warning', + weight: boundedUnit(signal.weight, 0.5), + })) + .sort((left, right) => left.id.localeCompare(right.id)); +} + +function sumSignalWeights(signals: DepositOptionDemandSignal[] | undefined) { + return (signals || []).reduce((sum, signal) => sum + boundedUnit(signal.weight, 0.5), 0); +} + +function optionMeasurementVolume(option: DepositAssetPackOption) { + if (!option.measurements.length) return 0; + const weighted = option.measurements.reduce( + (sum, measurement) => sum + boundedUnit(measurement.volume, 0) * boundedUnit(measurement.weight, 0), + 0, + ); + const weights = option.measurements.reduce((sum, measurement) => sum + boundedUnit(measurement.weight, 0), 0); + return Number((weights ? weighted / weights : 0).toFixed(4)); +} + +function sourceCriticalityFor(input: { + option: DepositAssetPackOption; + signals: ReturnType; +}) { + const signalRoots = input.signals.map((signal) => root('deposit-policy-criticality-signal', signal)); + const criticalWeight = input.signals + .filter((signal) => signal.severity === 'critical') + .reduce((sum, signal) => sum + signal.weight, 0); + const warningWeight = input.signals + .filter((signal) => signal.severity === 'warning') + .reduce((sum, signal) => sum + signal.weight, 0); + const subCriticalWeight = input.signals + .filter((signal) => signal.severity === 'sub-critical') + .reduce((sum, signal) => sum + signal.weight, 0); + const sourceBreadthRisk = Math.min(0.2, input.option.sourceBinding.sourcePathCount * 0.025); + const score = Number(Math.max(0, Math.min(1, 0.22 + criticalWeight * 0.55 + warningWeight * 0.22 - subCriticalWeight * 0.18 + sourceBreadthRisk)).toFixed(2)); + const state: DepositOptionCriticalityState = criticalWeight >= 0.75 || score >= 0.78 + ? 'blocked-critical-source' + : score >= 0.48 || warningWeight > subCriticalWeight + ? 'review-warning' + : 'sub-critical'; + const blockers = state === 'blocked-critical-source' ? ['critical_source_policy_block'] : []; + const warnings = [ + ...(state === 'review-warning' ? ['depositor_review_required_for_source_criticality'] : []), + ...(!input.signals.length ? ['source_criticality_signals_missing'] : []), + ]; + + return { + state, + score, + signalRoots, + blockers, + warnings, + }; +} + +function demandFor(option: DepositAssetPackOption) { + const weightedDemand = Number(Math.max(0, Math.min(1, option.demandAlignment.confidence)).toFixed(2)); + const state: DepositOptionDemandState = weightedDemand >= 0.76 + ? 'strong-likely-demand' + : weightedDemand >= 0.56 + ? 'moderate-likely-demand' + : 'weak-likely-demand'; + + return { + state, + confidence: option.demandAlignment.confidence, + weightedDemand, + demandRoot: root('deposit-policy-demand', { + optionId: option.optionId, + confidence: option.demandAlignment.confidence, + depositorySignalRoots: option.demandAlignment.depositorySignalRoots, + readingSignalRoots: option.demandAlignment.readingSignalRoots, + existingDepositorySignalRoots: option.demandAlignment.existingDepositorySignalRoots, + }), + }; +} + +function roiFor(input: { + option: DepositAssetPackOption; + demand: ReturnType; + criticality: ReturnType; + developmentCostSats: number; + expectedSettlementSats: number; +}) { + const measurementVolume = optionMeasurementVolume(input.option); + const kindMultiplier = + input.option.kind === 'capability-slice' + ? 1 + : input.option.kind === 'implementation-pattern' + ? 0.92 + : 0.84; + const criticalityDiscount = input.criticality.state === 'sub-critical' + ? 1 + : input.criticality.state === 'review-warning' + ? 0.76 + : 0; + const estimatedGrossSats = Math.round( + input.expectedSettlementSats * input.demand.weightedDemand * (0.62 + measurementVolume * 0.38) * kindMultiplier * criticalityDiscount, + ); + const expectedNetSats = estimatedGrossSats - input.developmentCostSats; + const roiMultiple = Number((input.developmentCostSats > 0 ? estimatedGrossSats / input.developmentCostSats : 0).toFixed(2)); + const state: DepositOptionRoiState = input.criticality.state === 'blocked-critical-source' + ? 'blocked-criticality' + : expectedNetSats < 0 + ? 'negative-expected-value' + : roiMultiple < 1.25 + ? 'marginal-expected-value' + : 'positive-expected-value'; + const roiRoot = root('deposit-policy-roi', { + optionId: input.option.optionId, + state, + estimatedGrossSats, + estimatedDevelopmentCostSats: input.developmentCostSats, + expectedNetSats, + roiMultiple, + }); + + return { + state, + estimatedGrossSats, + estimatedDevelopmentCostSats: input.developmentCostSats, + expectedNetSats, + roiMultiple, + roiRoot, + }; +} + +function btdPotentialFor(input: { + option: DepositAssetPackOption; + demand: ReturnType; + roi: ReturnType; + criticality: ReturnType; +}) { + const estimatedKnowledgeVolume = Number((optionMeasurementVolume(input.option) * input.demand.weightedDemand).toFixed(4)); + const estimatedBtdCells = Math.max(0, Math.round(estimatedKnowledgeVolume * 1000)); + const state: DepositOptionBtdPotentialState = input.criticality.state === 'blocked-critical-source' || input.roi.state === 'negative-expected-value' + ? 'blocked-until-policy-repair' + : estimatedKnowledgeVolume >= 0.64 + ? 'high-potential' + : estimatedKnowledgeVolume >= 0.42 + ? 'moderate-potential' + : 'low-potential'; + const btdPotentialRoot = root('deposit-policy-btd-potential', { + optionId: input.option.optionId, + state, + estimatedKnowledgeVolume, + estimatedBtdCells, + }); + + return { + state, + estimatedKnowledgeVolume, + estimatedBtdCells, + estimateOnly: true as const, + btdMintBoundary: 'not-minted-until-future-need-fit-settlement' as const, + rightsBoundary: 'depositor-retains-rights-until-paid-reader-settlement-transfer' as const, + btdPotentialRoot, + }; +} + +function compensationFor(input: { + option: DepositAssetPackOption; + criticality: ReturnType; + roi: ReturnType; + depositorWalletId: string | null; +}) { + const blockers = [ + ...input.criticality.blockers, + ...(input.roi.state === 'negative-expected-value' ? ['negative_expected_value'] : []), + ...(input.roi.state === 'blocked-criticality' ? ['criticality_blocks_compensation'] : []), + ...(!input.depositorWalletId ? ['depositor_wallet_missing'] : []), + ...(input.option.reviewBoundary.state !== 'reviewable-source-safe-option' ? ['option_not_reviewable'] : []), + ]; + const warnings = [ + ...input.criticality.warnings, + ...(input.roi.state === 'marginal-expected-value' ? ['marginal_expected_value'] : []), + ]; + const eligibleIfApprovedAndSelected = blockers.length === 0; + const state: DepositOptionCompensationState = eligibleIfApprovedAndSelected + ? 'eligible-if-approved-and-selected' + : input.criticality.state === 'blocked-critical-source' || input.roi.state === 'negative-expected-value' + ? 'blocked-before-compensation' + : 'repair-required-before-compensation'; + const compensationRoute = { + optionId: input.option.optionId, + state, + payer: 'future-reader-after-settlement', + payee: 'depositing-wallet', + priceAsset: 'BTC', + allocationMethod: 'source-to-shares-largest-remainder', + depositorShareBasisPoints: 8000, + protocolTreasuryBasisPoints: 2000, + sourceToSharesProofState: 'not-created-until-accepted-need-fit-and-settlement', + depositorWalletRoot: input.depositorWalletId ? root('deposit-policy-wallet', input.depositorWalletId) : null, + blockers, + warnings, + }; + + return { + state, + payer: 'future-reader-after-settlement' as const, + payee: 'depositing-wallet' as const, + priceAsset: 'BTC' as const, + allocationMethod: 'source-to-shares-largest-remainder' as const, + depositorShareBasisPoints: 8000, + protocolTreasuryBasisPoints: 2000, + sourceToSharesProofState: 'not-created-until-accepted-need-fit-and-settlement' as const, + eligibleIfApprovedAndSelected, + blockers: [...new Set(blockers)].sort(), + warnings: [...new Set(warnings)].sort(), + compensationRouteRoot: root('deposit-policy-compensation-route', compensationRoute), + }; +} + +function policyDecisionFor(input: { + criticality: ReturnType; + roi: ReturnType; + compensation: ReturnType; +}): DepositAssetPackOptionPolicyEvaluation['policyDecision'] { + if ( + input.criticality.state === 'blocked-critical-source' || + input.roi.state === 'negative-expected-value' || + input.roi.state === 'blocked-criticality' || + input.compensation.state === 'blocked-before-compensation' + ) { + return 'blocked-before-admission'; + } + if (input.criticality.state === 'review-warning' || input.roi.state === 'marginal-expected-value' || input.compensation.warnings.length) { + return 'review-warning-before-admission'; + } + return 'reviewable-positive-roi'; +} + +export function buildDepositAssetPackOptionPolicyReport( + input: DepositAssetPackOptionPolicyInput, +): DepositAssetPackOptionPolicyReport { + const createdAt = normalizedText(input.createdAt) || 'deterministic'; + const sourceCriticalitySignals = normalizedCriticalitySignals(input.sourceCriticalitySignals); + const demandSignalWeight = + input.synthesis.options.reduce((sum, option) => sum + option.demandAlignment.confidence, 0) + + sumSignalWeights(input.synthesis.options.flatMap((option) => option.measurements.map((measurement) => ({ + id: measurement.id, + label: measurement.label, + weight: measurement.volume * measurement.weight, + })))); + const developmentCostSats = positiveInteger( + input.developmentCostSats, + Math.max(1200, Math.round(850 + input.synthesis.optionCount * 275 + input.synthesis.request.sourcePathRoots.length * 180)), + ); + const expectedSettlementSats = positiveInteger( + input.expectedSettlementSats, + Math.max(2500, Math.round(2800 + demandSignalWeight * 450 + input.synthesis.request.sourcePathRoots.length * 220)), + ); + const depositorWalletId = normalizedText(input.depositorWalletId); + + const evaluations = input.synthesis.options.map((option): DepositAssetPackOptionPolicyEvaluation => { + const sourceCriticality = sourceCriticalityFor({ option, signals: sourceCriticalitySignals }); + const demand = demandFor(option); + const roi = roiFor({ + option, + demand, + criticality: sourceCriticality, + developmentCostSats, + expectedSettlementSats, + }); + const btdPotential = btdPotentialFor({ option, demand, roi, criticality: sourceCriticality }); + const compensation = compensationFor({ option, criticality: sourceCriticality, roi, depositorWalletId }); + const policyDecision = policyDecisionFor({ criticality: sourceCriticality, roi, compensation }); + const admissionBoundary = { + depositApprovalRequired: true as const, + admissionAndIndexingOwnedBy: 'future-gate7-deposit-option-review' as const, + sourceBearingDisclosureBeforeSettlementVisible: false as const, + }; + const visibility = { + sourceSafeMetadataOnly: true as const, + protectedSourceVisible: false as const, + rawSourceTextVisible: false as const, + unpaidAssetPackSourceVisible: false as const, + rawPromptVisible: false as const, + interpolatedPromptVisible: false as const, + rawProviderResponseVisible: false as const, + walletPrivateMaterialVisible: false as const, + settlementPrivatePayloadVisible: false as const, + }; + const policyEvaluationRoot = root('deposit-policy-evaluation', { + optionId: option.optionId, + policyDecision, + sourceCriticality, + demand, + roi, + btdPotential, + compensation, + admissionBoundary, + visibility, + }); + + return { + schema: 'bitcode.deposit.asset-pack-option-policy-evaluation', + optionId: option.optionId, + optionKind: option.kind, + title: option.title, + policyDecision, + sourceCriticality, + demand, + roi, + btdPotential, + compensation, + admissionBoundary, + visibility, + roots: { + policyEvaluationRoot, + sourceCriticalityRoot: root('deposit-policy-criticality', sourceCriticality), + demandRoot: demand.demandRoot, + roiRoot: roi.roiRoot, + btdPotentialRoot: btdPotential.btdPotentialRoot, + compensationRouteRoot: compensation.compensationRouteRoot, + }, + }; + }); + const aggregatePolicy = { + criticalityPolicy: 'source-safe-criticality-signals-with-depositor-review' as const, + demandPolicy: 'weighted-depository-reading-and-existing-supply-signals' as const, + roiPolicy: 'deterministic-estimated-gross-minus-development-cost' as const, + compensationPolicy: 'future-reader-btc-source-to-shares-route-preview' as const, + admissionAndIndexingOwnedBy: 'future-gate7-deposit-option-review' as const, + }; + const evaluationRoots = evaluations.map((evaluation) => evaluation.roots.policyEvaluationRoot); + const aggregatePolicyRoot = root('deposit-policy-aggregate', aggregatePolicy); + const policyReportRoot = root('deposit-policy-report', { + synthesisRequestId: input.synthesis.requestId, + evaluationRoots, + aggregatePolicyRoot, + createdAt, + }); + + return { + schema: 'bitcode.deposit.asset-pack-option-policy-report', + policy: 'DepositAssetPackOptionPolicy', + reportId: policyReportRoot, + createdAt, + route: '/deposit', + synthesisRequestId: input.synthesis.requestId, + optionCount: evaluations.length, + reviewablePositiveRoiCount: evaluations.filter((evaluation) => evaluation.policyDecision === 'reviewable-positive-roi').length, + warningCount: evaluations.filter((evaluation) => evaluation.policyDecision === 'review-warning-before-admission').length, + blockedCount: evaluations.filter((evaluation) => evaluation.policyDecision === 'blocked-before-admission').length, + evaluations, + aggregatePolicy, + sourceSafety: { + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawSourceTextVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + }, + roots: { + policyReportRoot, + synthesisRoot: input.synthesis.roots.synthesisRoot, + evaluationRoots, + aggregatePolicyRoot, + }, + }; +} + +export function assertDepositAssetPackOptionPolicyReportSourceSafe( + report: DepositAssetPackOptionPolicyReport, +) { + const serialized = stableStringify(report); + const noForbiddenMarkers = FORBIDDEN_SOURCE_MARKERS.every((marker) => !serialized.includes(marker)); + const sourceSafe = + report.schema === 'bitcode.deposit.asset-pack-option-policy-report' && + report.policy === 'DepositAssetPackOptionPolicy' && + report.route === '/deposit' && + report.aggregatePolicy.admissionAndIndexingOwnedBy === 'future-gate7-deposit-option-review' && + report.sourceSafety.sourceSafeMetadataOnly === true && + report.sourceSafety.protectedSourceVisible === false && + report.sourceSafety.rawSourceTextVisible === false && + report.sourceSafety.unpaidAssetPackSourceVisible === false && + report.sourceSafety.rawPromptVisible === false && + report.sourceSafety.interpolatedPromptVisible === false && + report.sourceSafety.rawProviderResponseVisible === false && + report.sourceSafety.walletPrivateMaterialVisible === false && + report.sourceSafety.settlementPrivatePayloadVisible === false && + report.evaluations.every( + (evaluation) => + evaluation.admissionBoundary.admissionAndIndexingOwnedBy === 'future-gate7-deposit-option-review' && + evaluation.admissionBoundary.sourceBearingDisclosureBeforeSettlementVisible === false && + evaluation.btdPotential.estimateOnly === true && + evaluation.btdPotential.btdMintBoundary === 'not-minted-until-future-need-fit-settlement' && + evaluation.compensation.priceAsset === 'BTC' && + evaluation.compensation.sourceToSharesProofState === 'not-created-until-accepted-need-fit-and-settlement' && + evaluation.visibility.sourceSafeMetadataOnly === true && + evaluation.visibility.protectedSourceVisible === false && + evaluation.visibility.rawSourceTextVisible === false && + evaluation.visibility.unpaidAssetPackSourceVisible === false && + evaluation.visibility.walletPrivateMaterialVisible === false, + ) && + noForbiddenMarkers; + + return { + admitted: sourceSafe, + reason: sourceSafe ? 'source_safe_deposit_asset_pack_option_policy' : 'deposit_option_policy_source_safety_boundary_violation', + }; +} diff --git a/packages/pipelines/asset-pack/src/index.ts b/packages/pipelines/asset-pack/src/index.ts index 643ec4f0..810603c6 100644 --- a/packages/pipelines/asset-pack/src/index.ts +++ b/packages/pipelines/asset-pack/src/index.ts @@ -438,6 +438,7 @@ export * from './reading-operational-telemetry-repair-readback'; export * from './reading-interface-product-parity'; export * from './reading-local-staging-rehearsal'; export * from './deposit-asset-pack-options'; +export * from './deposit-asset-pack-option-policy'; export * from './embedding-config'; export * from './asset-pack-disclosure'; export * from './read-need-review-resynthesis'; diff --git a/packages/protocol/README.md b/packages/protocol/README.md index 1b08333f..f8d7e79f 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -119,6 +119,18 @@ demand signal roots, option measurement roots, retained deposit composer reuse, route navigation, and no-source leak tests while leaving Gate 6 policy and Gate 7 admission/indexing deferred. +V43 Gate 6 adds `DepositAssetPackOptionPolicyReport` through +`packages/protocol/src/canonical/v43-deposit-policy-compensation.js`, +`packages/protocol/test/v43-deposit-policy-compensation.test.js`, +`.bitcode/v43-deposit-policy-compensation.json`, +`generate:v43-deposit-policy-compensation`, +`check:v43-deposit-policy-compensation`, and `check:v43-gate6`. It binds +source criticality, likely demand, deterministic ROI, estimate-only BTD +potential, critical-source pre-admission blocking, and BTC source-to-shares +compensation route preview while keeping Gate 7 responsible for depositor +approval, admission, indexing, storage projection, telemetry, and `/packs` +activity synchronization. + 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/v43-deposit-policy-compensation.js b/packages/protocol/src/canonical/v43-deposit-policy-compensation.js new file mode 100644 index 00000000..c7cca5f2 --- /dev/null +++ b/packages/protocol/src/canonical/v43-deposit-policy-compensation.js @@ -0,0 +1,234 @@ +// @ts-check + +import crypto from 'node:crypto'; +import { existsSync, readFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const DEFAULT_REPO_ROOT = path.resolve(__dirname, '..', '..', '..', '..'); + +export const V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH = '.bitcode/v43-deposit-policy-compensation.json'; +export const V43_DEPOSIT_POLICY_COMPENSATION_SCHEMA_ID = 'bitcode.v43.depositPolicyCompensation.v1'; +export const V43_DEPOSIT_POLICY_COMPENSATION_VERSION = 'V43'; +export const V43_DEPOSIT_POLICY_COMPENSATION_CURRENT_TARGET = 'V42'; +export const V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_SAFETY_VERDICT = + 'source-safe-deposit-policy-compensation-metadata'; + +export const V43_DEPOSIT_POLICY_OBJECT_IDS = Object.freeze([ + 'DepositAssetPackOptionPolicy', + 'DepositAssetPackOptionPolicyReport', + 'DepositAssetPackOptionPolicyEvaluation', + 'source criticality posture', + 'likely demand posture', + 'ROI posture', + 'BTD potential estimate', + 'BTC source-to-shares compensation route', + 'future Gate 7 admission boundary', +]); + +export const V43_DEPOSIT_POLICY_FIELD_IDS = Object.freeze([ + 'sourceCriticality', + 'demand', + 'roi', + 'btdPotential', + 'compensation', + 'policyDecision', + 'admissionBoundary', + 'policy roots', +]); + +export const V43_DEPOSIT_POLICY_FORBIDDEN_PAYLOAD_IDS = Object.freeze([ + 'protected_source_payload', + 'raw_source_text', + 'unpaid_assetpack_source', + 'raw_protected_prompt', + 'interpolated_prompt', + 'raw_provider_response', + 'wallet_private_material', + 'settlement_private_payload', +]); + +const SOURCE_ROOTS = Object.freeze({ + activePointer: 'BITCODE_SPEC.txt', + spec: 'BITCODE_SPEC_V43.md', + delta: 'BITCODE_SPEC_V43_DELTA.md', + notes: 'BITCODE_SPEC_V43_NOTES.md', + parity: 'BITCODE_SPEC_V43_PARITY_MATRIX.md', + roadmap: 'SPECIFICATIONS_ROADMAP.md', + readme: 'README.md', + protocolReadme: 'packages/protocol/README.md', + packageJson: 'package.json', + gateWorkflow: '.github/workflows/bitcode-gate-quality.yml', + canonWorkflow: '.github/workflows/bitcode-canon-quality.yml', + optionModel: 'packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts', + policyModel: 'packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts', + optionModelTest: 'packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-options.test.ts', + policyModelTest: 'packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts', + routeModel: 'uapi/app/deposit/deposit-route-model.ts', + client: 'uapi/app/deposit/DepositPageClient.tsx', + routeModelTest: 'uapi/tests/depositRouteModel.test.ts', + pageTest: 'uapi/tests/depositPageClient.test.tsx', + packageIndex: 'packages/pipelines/asset-pack/src/index.ts', + packageManifest: 'packages/pipelines/asset-pack/package.json', + protocolIndex: 'packages/protocol/src/index.js', + protocolTypes: 'packages/protocol/src/index.d.ts', + protocolTest: 'packages/protocol/test/v43-deposit-policy-compensation.test.js', + generator: 'scripts/generate-v43-deposit-policy-compensation.mjs', + checker: 'scripts/check-v43-gate6-deposit-policy-compensation.mjs', +}); + +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 predicateResult(id, sourcePath, passed) { + return { id, sourcePath, passed: Boolean(passed) }; +} + +export const V43_DEPOSIT_POLICY_COMPENSATION_CONTRACT_ROWS = Object.freeze([ + { + rowId: 'criticality-policy', + owner: SOURCE_ROOTS.policyModel, + contract: + 'DepositAssetPackOptionPolicy evaluates source criticality from source-safe criticality signals and blocks critical IP before Gate 7 admission.', + requiredFields: ['sourceCriticality', 'blocked-critical-source', 'critical_source_policy_block'], + }, + { + rowId: 'demand-roi-policy', + owner: SOURCE_ROOTS.policyModel, + contract: + 'Policy evaluates likely demand and ROI deterministically from source-safe option measurements, demand confidence, estimated settlement, and development cost.', + requiredFields: ['demand', 'roi', 'positive-expected-value', 'negative-expected-value'], + }, + { + rowId: 'btd-compensation-policy', + owner: SOURCE_ROOTS.policyModel, + contract: + 'Policy exposes BTD potential as estimate-only and previews future-reader BTC source-to-shares compensation without minting BTD or transferring rights.', + requiredFields: ['btdPotential', 'compensation', 'source-to-shares-largest-remainder', 'BTC'], + }, + { + rowId: 'route-policy-readback', + owner: SOURCE_ROOTS.client, + contract: + '/deposit renders policy readback for criticality, demand, ROI, BTD potential, and compensation while admission/indexing remain owned by Gate 7.', + requiredFields: ['DepositAssetPackOptionPolicy', 'BTC source-to-shares preview', 'future-gate7-deposit-option-review'], + }, +]); + +function buildPredicateResults(repoRoot) { + const sources = Object.fromEntries( + Object.entries(SOURCE_ROOTS).map(([key, sourcePath]) => [key, readSource(repoRoot, sourcePath)]), + ); + + return [ + predicateResult('active-canon-pointer-remains-v42', SOURCE_ROOTS.activePointer, sources.activePointer.trim() === 'V42'), + predicateResult('spec-defines-gate6', SOURCE_ROOTS.spec, sources.spec.includes('V43 Gate 6 Source Criticality, Demand, ROI, And Compensation Policy')), + predicateResult('spec-names-policy-objects', SOURCE_ROOTS.spec, sources.spec.includes('DepositAssetPackOptionPolicy') && sources.spec.includes('BTD potential')), + predicateResult('delta-records-gate6', SOURCE_ROOTS.delta, sources.delta.includes('Gate 6') && sources.delta.includes('v43-deposit-policy-compensation')), + predicateResult('notes-records-gate6', SOURCE_ROOTS.notes, sources.notes.includes('Gate 6') && sources.notes.includes('criticality, demand, ROI')), + predicateResult('parity-records-gate6', SOURCE_ROOTS.parity, sources.parity.includes('Criticality/ROI policy') && sources.parity.includes('v43-deposit-policy-compensation')), + predicateResult('roadmap-records-gate6', SOURCE_ROOTS.roadmap, sources.roadmap.includes('V43 Gate 6 closure anchor')), + predicateResult('readme-records-gate6', SOURCE_ROOTS.readme, sources.readme.includes('V43 Gate 6')), + predicateResult('protocol-readme-records-gate6', SOURCE_ROOTS.protocolReadme, sources.protocolReadme.includes('V43 Gate 6')), + predicateResult('policy-model-defines-report', SOURCE_ROOTS.policyModel, sources.policyModel.includes('DepositAssetPackOptionPolicyReport') && sources.policyModel.includes('buildDepositAssetPackOptionPolicyReport')), + predicateResult('policy-model-defines-criticality', SOURCE_ROOTS.policyModel, sources.policyModel.includes('blocked-critical-source') && sources.policyModel.includes('sourceCriticality')), + predicateResult('policy-model-defines-demand-roi', SOURCE_ROOTS.policyModel, sources.policyModel.includes('weighted-depository-reading-and-existing-supply-signals') && sources.policyModel.includes('deterministic-estimated-gross-minus-development-cost')), + predicateResult('policy-model-defines-btd-compensation', SOURCE_ROOTS.policyModel, sources.policyModel.includes('not-minted-until-future-need-fit-settlement') && sources.policyModel.includes('source-to-shares-largest-remainder')), + predicateResult('policy-model-defers-gate7-admission', SOURCE_ROOTS.policyModel, sources.policyModel.includes('future-gate7-deposit-option-review') && sources.policyModel.includes('admissionAndIndexingOwnedBy')), + predicateResult('policy-model-forbids-source-leakage', SOURCE_ROOTS.policyModel, sources.policyModel.includes('rawSourceTextVisible: false') && sources.policyModel.includes('settlementPrivatePayloadVisible: false') && sources.policyModel.includes('walletPrivateMaterialVisible: false')), + predicateResult('route-model-owns-policy', SOURCE_ROOTS.routeModel, sources.routeModel.includes('DepositAssetPackOptionPolicyReport') && sources.routeModel.includes('sourceCriticalityDemandRoiPolicyOwnedByGate6')), + predicateResult('deposit-client-renders-policy', SOURCE_ROOTS.client, sources.client.includes('DepositAssetPackOptionPolicy') && sources.client.includes('BTC source-to-shares preview')), + predicateResult('asset-pack-package-exports-policy', SOURCE_ROOTS.packageIndex, sources.packageIndex.includes("export * from './deposit-asset-pack-option-policy'")), + predicateResult('asset-pack-manifest-exports-policy', SOURCE_ROOTS.packageManifest, sources.packageManifest.includes('"./deposit-asset-pack-option-policy"')), + predicateResult('policy-test-covers-report', SOURCE_ROOTS.policyModelTest, sources.policyModelTest.includes('buildDepositAssetPackOptionPolicyReport') && sources.policyModelTest.includes('blocked-before-admission')), + predicateResult('route-test-covers-policy', SOURCE_ROOTS.routeModelTest, sources.routeModelTest.includes('DepositAssetPackOptionPolicy') && sources.routeModelTest.includes('blockedCount')), + predicateResult('page-test-covers-policy', SOURCE_ROOTS.pageTest, sources.pageTest.includes('DepositAssetPackOptionPolicy') && sources.pageTest.includes('BTC source-to-shares preview')), + predicateResult('protocol-test-covers-artifact', SOURCE_ROOTS.protocolTest, sources.protocolTest.includes('buildV43DepositPolicyCompensation')), + predicateResult('protocol-package-exports-gate6', SOURCE_ROOTS.protocolIndex, sources.protocolIndex.includes('buildV43DepositPolicyCompensation')), + predicateResult('protocol-types-export-gate6', SOURCE_ROOTS.protocolTypes, sources.protocolTypes.includes('buildV43DepositPolicyCompensation')), + predicateResult('package-json-exposes-gate6', SOURCE_ROOTS.packageJson, sources.packageJson.includes('"generate:v43-deposit-policy-compensation"') && sources.packageJson.includes('"check:v43-gate6"')), + predicateResult('gate-workflow-runs-gate6', SOURCE_ROOTS.gateWorkflow, sources.gateWorkflow.includes('check-v43-gate6-deposit-policy-compensation.mjs')), + predicateResult('canon-workflow-runs-gate6', SOURCE_ROOTS.canonWorkflow, sources.canonWorkflow.includes('check-v43-gate6-deposit-policy-compensation.mjs')), + predicateResult('generator-exists', SOURCE_ROOTS.generator, sources.generator.includes('buildV43DepositPolicyCompensation')), + predicateResult('checker-exists', SOURCE_ROOTS.checker, sources.checker.includes('V43 Gate 6 deposit policy compensation check')), + ]; +} + +export function buildV43DepositPolicyCompensation({ repoRoot = DEFAULT_REPO_ROOT } = {}) { + const predicateResults = buildPredicateResults(repoRoot); + const failedPredicateIds = predicateResults + .filter((predicate) => !predicate.passed) + .map((predicate) => predicate.id); + const sourceRoots = Object.fromEntries( + Object.entries(SOURCE_ROOTS).map(([key, sourcePath]) => [key, `${sourcePath}:${digest(readSource(repoRoot, sourcePath))}`]), + ); + const artifactRoot = `v43-deposit-policy-compensation:${digest(JSON.stringify({ + objectIds: V43_DEPOSIT_POLICY_OBJECT_IDS, + fieldIds: V43_DEPOSIT_POLICY_FIELD_IDS, + forbiddenPayloadIds: V43_DEPOSIT_POLICY_FORBIDDEN_PAYLOAD_IDS, + contractRows: V43_DEPOSIT_POLICY_COMPENSATION_CONTRACT_ROWS.map((row) => row.rowId), + sourceRoots, + failedPredicateIds, + }))}`; + + return { + artifactId: 'v43-deposit-policy-compensation', + schemaId: V43_DEPOSIT_POLICY_COMPENSATION_SCHEMA_ID, + version: V43_DEPOSIT_POLICY_COMPENSATION_VERSION, + currentTarget: V43_DEPOSIT_POLICY_COMPENSATION_CURRENT_TARGET, + sourceSafetyVerdict: V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_SAFETY_VERDICT, + generatedAt: 'deterministic', + artifactRoot, + passed: failedPredicateIds.length === 0, + objectIds: [...V43_DEPOSIT_POLICY_OBJECT_IDS], + fieldIds: [...V43_DEPOSIT_POLICY_FIELD_IDS], + forbiddenPayloadIds: [...V43_DEPOSIT_POLICY_FORBIDDEN_PAYLOAD_IDS], + contractRows: V43_DEPOSIT_POLICY_COMPENSATION_CONTRACT_ROWS.map((row) => ({ + ...row, + rowRoot: `v43-deposit-policy-contract:${digest(row.rowId)}`, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + unpaidAssetPackSourceVisible: false, + })), + sourceRoots, + predicateResults, + coverage: { + depositPolicyImplemented: true, + criticalityPolicyImplemented: true, + criticalSourceBlockedBeforeAdmission: true, + demandPolicyImplemented: true, + roiPolicyImplemented: true, + btdPotentialEstimateOnly: true, + compensationPolicyImplemented: true, + compensationPriceAsset: 'BTC', + compensationAllocationMethod: 'source-to-shares-largest-remainder', + btdMintRequiresFutureNeedFitSettlement: true, + admissionAndIndexingDeferredToGate7: true, + routePolicyReadbackImplemented: true, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawSourceTextVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + requiredPredicateCount: predicateResults.length, + passedPredicateCount: predicateResults.length - failedPredicateIds.length, + failedPredicateIds, + }, + }; +} + +export const V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_ROOTS = Object.freeze( + Object.fromEntries(Object.entries(SOURCE_ROOTS).map(([key, sourcePath]) => [key, sourcePath])), +); diff --git a/packages/protocol/src/index.d.ts b/packages/protocol/src/index.d.ts index 7f23d9e2..0d40f110 100644 --- a/packages/protocol/src/index.d.ts +++ b/packages/protocol/src/index.d.ts @@ -630,6 +630,17 @@ export const V43_DEPOSIT_OPTION_SOURCE_SAFE_FIELD_IDS: readonly string[]; export const V43_DEPOSIT_OPTION_FORBIDDEN_PAYLOAD_IDS: readonly string[]; export const V43_DEPOSIT_ROUTE_OPTIONS_CONTRACT_ROWS: readonly Record[]; export function buildV43DepositRouteOptions(input?: Record): BitcodeProtocolReport; +export const V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH: string; +export const V43_DEPOSIT_POLICY_COMPENSATION_CURRENT_TARGET: string; +export const V43_DEPOSIT_POLICY_COMPENSATION_SCHEMA_ID: string; +export const V43_DEPOSIT_POLICY_COMPENSATION_VERSION: string; +export const V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_SAFETY_VERDICT: string; +export const V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_ROOTS: Readonly>; +export const V43_DEPOSIT_POLICY_OBJECT_IDS: readonly string[]; +export const V43_DEPOSIT_POLICY_FIELD_IDS: readonly string[]; +export const V43_DEPOSIT_POLICY_FORBIDDEN_PAYLOAD_IDS: readonly string[]; +export const V43_DEPOSIT_POLICY_COMPENSATION_CONTRACT_ROWS: readonly Record[]; +export function buildV43DepositPolicyCompensation(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 58cd2b9a..e52ab3a2 100644 --- a/packages/protocol/src/index.js +++ b/packages/protocol/src/index.js @@ -712,6 +712,19 @@ export { V43_DEPOSIT_ROUTE_STEP_IDS, buildV43DepositRouteOptions } from './canonical/v43-deposit-route-options.js'; +export { + V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH, + V43_DEPOSIT_POLICY_COMPENSATION_CONTRACT_ROWS, + V43_DEPOSIT_POLICY_COMPENSATION_CURRENT_TARGET, + V43_DEPOSIT_POLICY_COMPENSATION_SCHEMA_ID, + V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_ROOTS, + V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_SAFETY_VERDICT, + V43_DEPOSIT_POLICY_COMPENSATION_VERSION, + V43_DEPOSIT_POLICY_FIELD_IDS, + V43_DEPOSIT_POLICY_FORBIDDEN_PAYLOAD_IDS, + V43_DEPOSIT_POLICY_OBJECT_IDS, + buildV43DepositPolicyCompensation +} from './canonical/v43-deposit-policy-compensation.js'; export { EXCHANGE_INTENT_ACTION_KINDS, EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH, diff --git a/packages/protocol/test/v43-deposit-policy-compensation.test.js b/packages/protocol/test/v43-deposit-policy-compensation.test.js new file mode 100644 index 00000000..2ff5506c --- /dev/null +++ b/packages/protocol/test/v43-deposit-policy-compensation.test.js @@ -0,0 +1,44 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; +import { + V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH, + V43_DEPOSIT_POLICY_COMPENSATION_SCHEMA_ID, + V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_SAFETY_VERDICT, + V43_DEPOSIT_POLICY_FIELD_IDS, + V43_DEPOSIT_POLICY_FORBIDDEN_PAYLOAD_IDS, + V43_DEPOSIT_POLICY_OBJECT_IDS, + buildV43DepositPolicyCompensation, +} from '../src/canonical/v43-deposit-policy-compensation.js'; + +test('V43 deposit policy compensation artifact binds source-safe policy contracts', () => { + const report = buildV43DepositPolicyCompensation(); + + assert.equal(V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH, '.bitcode/v43-deposit-policy-compensation.json'); + assert.equal(report.artifactId, 'v43-deposit-policy-compensation'); + assert.equal(report.schemaId, V43_DEPOSIT_POLICY_COMPENSATION_SCHEMA_ID); + assert.equal(report.version, 'V43'); + assert.equal(report.currentTarget, 'V42'); + assert.equal(report.sourceSafetyVerdict, V43_DEPOSIT_POLICY_COMPENSATION_SOURCE_SAFETY_VERDICT); + assert.ok(report.artifactRoot.startsWith('v43-deposit-policy-compensation:')); + assert.deepEqual(report.objectIds, [...V43_DEPOSIT_POLICY_OBJECT_IDS]); + assert.deepEqual(report.fieldIds, [...V43_DEPOSIT_POLICY_FIELD_IDS]); + assert.deepEqual(report.forbiddenPayloadIds, [...V43_DEPOSIT_POLICY_FORBIDDEN_PAYLOAD_IDS]); + assert.equal(report.contractRows.length, 4); + assert.equal(report.coverage.depositPolicyImplemented, true); + assert.equal(report.coverage.criticalityPolicyImplemented, true); + assert.equal(report.coverage.criticalSourceBlockedBeforeAdmission, true); + assert.equal(report.coverage.demandPolicyImplemented, true); + assert.equal(report.coverage.roiPolicyImplemented, true); + assert.equal(report.coverage.btdPotentialEstimateOnly, true); + assert.equal(report.coverage.compensationPolicyImplemented, true); + assert.equal(report.coverage.compensationPriceAsset, 'BTC'); + assert.equal(report.coverage.compensationAllocationMethod, 'source-to-shares-largest-remainder'); + assert.equal(report.coverage.btdMintRequiresFutureNeedFitSettlement, true); + assert.equal(report.coverage.admissionAndIndexingDeferredToGate7, true); + assert.equal(report.coverage.routePolicyReadbackImplemented, true); + assert.equal(report.coverage.sourceSafeMetadataOnly, true); + assert.equal(report.coverage.protectedSourceVisible, false); + assert.equal(report.coverage.unpaidAssetPackSourceVisible, false); + assert.equal(report.coverage.walletPrivateMaterialVisible, false); + assert.equal(report.coverage.settlementPrivatePayloadVisible, false); +}); diff --git a/scripts/check-v43-gate6-deposit-policy-compensation.mjs b/scripts/check-v43-gate6-deposit-policy-compensation.mjs new file mode 100644 index 00000000..840fa518 --- /dev/null +++ b/scripts/check-v43-gate6-deposit-policy-compensation.mjs @@ -0,0 +1,173 @@ +#!/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 { + V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH, + buildV43DepositPolicyCompensation, +} from '../packages/protocol/src/canonical/v43-deposit-policy-compensation.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 assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { repoRoot: defaultRepoRoot, skipBranchCheck: false, skipUapiTests: 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-uapi-tests') args.skipUapiTests = 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-v43-gate6-deposit-policy-compensation.mjs [--skip-branch-check] [--skip-uapi-tests] [--skip-package-tests] [--repo-root ]', + '', + 'Checks V43 Gate 6 deposit source criticality, demand, ROI, BTD potential, compensation policy, generated artifact, docs, workflows, and tests.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function run(root, command, args) { + execFileSync(command, args, { cwd: root, stdio: 'pipe', encoding: 'utf8' }); +} + +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 === 'V42', `BITCODE_SPEC.txt must remain V42 during V43 gate work. Observed ${pointer || 'empty'}.`); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v43' || /^v43\/gate-\d+-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V43 work must occur on version/v43 or v43/gate-N-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH, + 'packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts', + 'packages/pipelines/asset-pack/src/__tests__/deposit-asset-pack-option-policy.test.ts', + 'uapi/app/deposit/deposit-route-model.ts', + 'uapi/app/deposit/DepositPageClient.tsx', + 'uapi/tests/depositRouteModel.test.ts', + 'uapi/tests/depositPageClient.test.tsx', + 'packages/protocol/src/canonical/v43-deposit-policy-compensation.js', + 'packages/protocol/test/v43-deposit-policy-compensation.test.js', + 'scripts/generate-v43-deposit-policy-compensation.mjs', + 'scripts/check-v43-gate6-deposit-policy-compensation.mjs', + 'BITCODE_SPEC_V43.md', + 'BITCODE_SPEC_V43_DELTA.md', + 'BITCODE_SPEC_V43_NOTES.md', + 'BITCODE_SPEC_V43_PARITY_MATRIX.md', + 'SPECIFICATIONS_ROADMAP.md', + 'README.md', + 'packages/protocol/README.md', + '.github/workflows/bitcode-gate-quality.yml', + '.github/workflows/bitcode-canon-quality.yml', + 'package.json', + ]) { + assertCheck(failures, exists(root, relativePath), `Missing required V43 Gate 6 file: ${relativePath}`); + } + + const artifact = buildV43DepositPolicyCompensation({ repoRoot: root }); + assertCheck(failures, artifact.passed, `V43 deposit policy predicates failed: ${artifact.coverage.failedPredicateIds.join(', ')}`); + assertCheck(failures, artifact.coverage.depositPolicyImplemented === true, 'Deposit policy must be implemented.'); + assertCheck(failures, artifact.coverage.criticalSourceBlockedBeforeAdmission === true, 'Critical source must block before admission.'); + assertCheck(failures, artifact.coverage.roiPolicyImplemented === true, 'ROI policy must be implemented.'); + assertCheck(failures, artifact.coverage.btdPotentialEstimateOnly === true, 'BTD potential must remain estimate-only.'); + assertCheck(failures, artifact.coverage.compensationPolicyImplemented === true, 'Compensation policy must be implemented.'); + assertCheck(failures, artifact.coverage.compensationPriceAsset === 'BTC', 'Compensation price asset must be BTC.'); + assertCheck(failures, artifact.coverage.admissionAndIndexingDeferredToGate7 === true, 'Gate 7 admission/indexing must remain deferred.'); + 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.walletPrivateMaterialVisible === false, 'Artifact must not expose wallet private material.'); + assertCheck(failures, artifact.coverage.settlementPrivatePayloadVisible === false, 'Artifact must not expose settlement private payload.'); + + const serialized = `${JSON.stringify(artifact, null, 2)}\n`; + assertCheck( + failures, + exists(root, V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH) && + read(root, V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH) === serialized, + `${V43_DEPOSIT_POLICY_COMPENSATION_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:v43-deposit-policy-compensation"'), 'package.json must expose generate:v43-deposit-policy-compensation.'); + assertCheck(failures, packageJson.includes('"check:v43-deposit-policy-compensation"'), 'package.json must expose check:v43-deposit-policy-compensation.'); + assertCheck(failures, packageJson.includes('"check:v43-gate6"'), 'package.json must expose check:v43-gate6.'); + assertCheck(failures, gateWorkflow.includes('check-v43-gate6-deposit-policy-compensation.mjs'), 'Gate workflow must run V43 Gate 6 checker.'); + assertCheck(failures, canonWorkflow.includes('check-v43-gate6-deposit-policy-compensation.mjs'), 'Canon workflow must run V43 Gate 6 checker.'); + + if (!args.skipPackageTests) { + try { + run(root, 'pnpm', ['--filter', '@bitcode/pipeline-asset-pack', 'exec', 'jest', 'deposit-asset-pack-option-policy.test.ts', '--runInBand']); + } catch { + failures.push('asset-pack deposit-asset-pack-option-policy.test.ts must pass.'); + } + } + + if (!args.skipUapiTests) { + try { + run(root, 'pnpm', ['--dir', 'uapi', 'exec', 'jest', 'depositRouteModel.test.ts', 'depositPageClient.test.tsx', '--runInBand']); + } catch { + failures.push('uapi depositRouteModel.test.ts and depositPageClient.test.tsx must pass.'); + } + } + + if (failures.length > 0) { + process.stderr.write('V43 Gate 6 deposit policy compensation check failed:\n'); + for (const failure of failures.filter(Boolean)) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write('V43 Gate 6 deposit policy compensation 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-v43-deposit-policy-compensation.mjs b/scripts/generate-v43-deposit-policy-compensation.mjs new file mode 100644 index 00000000..3257c288 --- /dev/null +++ b/scripts/generate-v43-deposit-policy-compensation.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 { + V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH, + buildV43DepositPolicyCompensation, +} from '../packages/protocol/src/canonical/v43-deposit-policy-compensation.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); +const check = process.argv.includes('--check'); +const artifact = buildV43DepositPolicyCompensation({ repoRoot }); +const serialized = `${JSON.stringify(artifact, null, 2)}\n`; +const artifactPath = path.join(repoRoot, V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH); + +if (check) { + if (!existsSync(artifactPath) || readFileSync(artifactPath, 'utf8') !== serialized) { + process.stderr.write( + `${V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH} is stale. Run pnpm run generate:v43-deposit-policy-compensation.\n`, + ); + process.exitCode = 1; + } +} else { + mkdirSync(path.dirname(artifactPath), { recursive: true }); + writeFileSync(artifactPath, serialized); + process.stdout.write(`wrote ${V43_DEPOSIT_POLICY_COMPENSATION_ARTIFACT_PATH}\n`); +} diff --git a/uapi/app/deposit/DepositPageClient.tsx b/uapi/app/deposit/DepositPageClient.tsx index cfd0193c..c005832f 100644 --- a/uapi/app/deposit/DepositPageClient.tsx +++ b/uapi/app/deposit/DepositPageClient.tsx @@ -34,6 +34,7 @@ import { deriveTerminalTransactionReadiness } from '@/app/terminal/terminal-tran import { buildDepositRouteSession, readDepositRouteStage, writeDepositRouteStage } from './deposit-route-model'; const DEPOSIT_OPTION_PIPELINE_ID = 'DepositAssetPackOptionSynthesis'; +const DEPOSIT_OPTION_POLICY_ID = 'DepositAssetPackOptionPolicy'; function shortIdentifier(value: string | null | undefined) { if (!value) return 'pending'; @@ -205,6 +206,27 @@ export default function DepositPageClient() { () => sourcePathHintsText.split(/\r?\n|,/u).map((entry) => entry.trim()).filter(Boolean), [sourcePathHintsText], ); + const sourceCriticalitySignals = useMemo( + () => [ + { + id: 'depositor-sub-critical-intent', + label: 'Depositor intends this option set to avoid critical source exposure.', + severity: 'sub-critical' as const, + weight: 0.74, + }, + ...(sourcePathHints.some((path) => /secret|credential|wallet|auth|key|payment|settlement/iu.test(path)) + ? [ + { + id: 'source-path-sensitive-scope-warning', + label: 'Source path hints include sensitive operational terms requiring review.', + severity: 'warning' as const, + weight: 0.64, + }, + ] + : []), + ], + [sourcePathHints], + ); const hasSubmittedDeposit = useMemo(() => { const selectedRepository = repositoryContext?.selectedRepository || null; if (!selectedRepository) return false; @@ -257,6 +279,10 @@ export default function DepositPageClient() { weight: 0.58, }, ], + sourceCriticalitySignals, + developmentCostSats: Math.max(1600, 1200 + sourcePathHints.length * 240), + expectedSettlementSats: Math.max(4200, 3600 + sourcePathHints.length * 360 + liveRuns.length * 90), + depositorWalletId: preferredSignerAddress ? 'connected-depositor-wallet' : null, hasRepositorySource: Boolean(repositoryContext?.selectedRepository), optionsRequested, hasReviewedOption: Boolean(reviewedOptionId), @@ -273,7 +299,9 @@ export default function DepositPageClient() { routeDepositStage, selectedRun?.id, selectedTransactionId, + sourceCriticalitySignals, sourcePathHints, + preferredSignerAddress, ], ); @@ -283,7 +311,9 @@ export default function DepositPageClient() { { label: 'Commit', value: shortIdentifier(depositRouteSession.routeState.sourceCommit) }, { label: 'Transaction', value: shortIdentifier(depositRouteSession.routeState.transactionId) }, { label: 'Pipeline', value: DEPOSIT_OPTION_PIPELINE_ID }, + { label: 'Policy', value: DEPOSIT_OPTION_POLICY_ID }, { label: 'Option roots', value: String(depositRouteSession.synthesis.roots.optionRoots.length) }, + { label: 'Positive ROI options', value: String(depositRouteSession.policy.reviewablePositiveRoiCount) }, ]; const recentDepositRuns = useMemo( @@ -469,7 +499,7 @@ export default function DepositPageClient() {

Options

Source-safe AssetPack proposals

- Gate 5 proposes reviewable options only. Criticality, ROI, compensation policy, and admission are explicitly deferred to later gates. + Policy scores criticality, demand, ROI, BTD potential, and compensation route before admission.

@@ -479,6 +509,9 @@ export default function DepositPageClient() {
{depositRouteSession.synthesis.options.map((option) => { const reviewed = reviewedOptionId === option.optionId; + const policyEvaluation = depositRouteSession.policy.evaluations.find( + (evaluation) => evaluation.optionId === option.optionId, + ); return (
{option.summary}

+ {policyEvaluation ? ( + <> +
+
Policy
+
{policyEvaluation.policyDecision}
+
+
+
+
Criticality
+
{policyEvaluation.sourceCriticality.state}
+
+
+
Demand
+
{policyEvaluation.demand.state}
+
+
+
+
+
ROI
+
+ {policyEvaluation.roi.state} / {policyEvaluation.roi.expectedNetSats} sats net +
+
+
+
BTD potential
+
{policyEvaluation.btdPotential.state}
+
+
+
+
Compensation
+
+ {policyEvaluation.compensation.state} / BTC source-to-shares preview +
+
+ + ) : null} {option.measurements.map((measurement) => (
{measurement.label}
@@ -573,7 +642,7 @@ export default function DepositPageClient() { Disclosure boundary

- Deposit options expose measurements, demand signal roots, source path roots, and policy posture only. Raw source, unpaid AssetPack source, prompts, provider responses, and wallet private material are not serialized. + Deposit options expose measurements, demand signal roots, source path roots, policy roots, estimated ROI, BTD potential, and compensation route metadata only. Raw source, unpaid AssetPack source, prompts, provider responses, settlement private payloads, and wallet private material are not serialized.

diff --git a/uapi/app/deposit/deposit-route-model.ts b/uapi/app/deposit/deposit-route-model.ts index 3d449257..7a915d67 100644 --- a/uapi/app/deposit/deposit-route-model.ts +++ b/uapi/app/deposit/deposit-route-model.ts @@ -4,6 +4,12 @@ import { type DepositAssetPackOptionSynthesis, type DepositOptionSynthesisRequest, } from '@bitcode/pipeline-asset-pack/deposit-asset-pack-options'; +import { + assertDepositAssetPackOptionPolicyReportSourceSafe, + buildDepositAssetPackOptionPolicyReport, + type DepositAssetPackOptionPolicyReport, + type DepositOptionCriticalitySignal, +} from '@bitcode/pipeline-asset-pack/deposit-asset-pack-option-policy'; export type DepositRouteStepId = | 'connect-source' @@ -17,6 +23,10 @@ export type DepositRouteStepState = 'complete' | 'current' | 'blocked' | 'ready' export interface DepositRouteSessionInput extends DepositOptionSynthesisRequest { depositStage?: DepositRouteStepId | null; transactionId?: string | null; + sourceCriticalitySignals?: DepositOptionCriticalitySignal[] | null; + developmentCostSats?: number | null; + expectedSettlementSats?: number | null; + depositorWalletId?: string | null; hasRepositorySource?: boolean; optionsRequested?: boolean; hasReviewedOption?: boolean; @@ -47,12 +57,15 @@ export interface DepositRouteSession { }; pipelineOwnership: { depositOptionPipeline: 'DepositAssetPackOptionSynthesis'; + depositOptionPolicy: 'DepositAssetPackOptionPolicy'; reviewRequiredBeforeDepositAdmission: true; + sourceCriticalityDemandRoiPolicyOwnedByGate6: true; sourceCriticalityDemandRoiPolicyDeferredToGate6: true; admissionAndIndexingDeferredToGate7: true; retainedTerminalDebugCompatible: true; }; synthesis: DepositAssetPackOptionSynthesis; + policy: DepositAssetPackOptionPolicyReport; disclosure: { sourceSafetyClass: 'source_safe_deposit_option_route_metadata'; lowDetailDefault: true; @@ -175,6 +188,14 @@ export function buildDepositRouteSession(input: DepositRouteSessionInput = {}): existingDepositorySignals: input.existingDepositorySignals, createdAt: input.createdAt, }); + const policy = buildDepositAssetPackOptionPolicyReport({ + synthesis, + sourceCriticalitySignals: input.sourceCriticalitySignals, + developmentCostSats: input.developmentCostSats, + expectedSettlementSats: input.expectedSettlementSats, + depositorWalletId: input.depositorWalletId, + createdAt: input.createdAt, + }); const steps = DEPOSIT_ROUTE_STEPS.map((step) => ({ ...step, state: stepState(input, step.id, activeStepId), @@ -187,6 +208,7 @@ export function buildDepositRouteSession(input: DepositRouteSessionInput = {}): sourceBranch, sourceCommit, synthesisRoot: synthesis.roots.synthesisRoot, + policyReportRoot: policy.roots.policyReportRoot, steps: steps.map((step) => ({ id: step.id, state: step.state, blockers: step.blockers })), }); @@ -205,12 +227,15 @@ export function buildDepositRouteSession(input: DepositRouteSessionInput = {}): }, pipelineOwnership: { depositOptionPipeline: 'DepositAssetPackOptionSynthesis', + depositOptionPolicy: 'DepositAssetPackOptionPolicy', reviewRequiredBeforeDepositAdmission: true, + sourceCriticalityDemandRoiPolicyOwnedByGate6: true, sourceCriticalityDemandRoiPolicyDeferredToGate6: true, admissionAndIndexingDeferredToGate7: true, retainedTerminalDebugCompatible: true, }, synthesis, + policy, disclosure: { sourceSafetyClass: 'source_safe_deposit_option_route_metadata', lowDetailDefault: true, @@ -229,13 +254,17 @@ export function buildDepositRouteSession(input: DepositRouteSessionInput = {}): export function assertDepositRouteSessionSourceSafe(session: DepositRouteSession) { const synthesisSafety = assertDepositAssetPackOptionSynthesisSourceSafe(session.synthesis); + const policySafety = assertDepositAssetPackOptionPolicyReportSourceSafe(session.policy); const sourceSafe = synthesisSafety.admitted && + policySafety.admitted && session.schema === 'bitcode.deposit.route-session' && session.route === '/deposit' && session.stageCount === 5 && session.pipelineOwnership.depositOptionPipeline === 'DepositAssetPackOptionSynthesis' && + session.pipelineOwnership.depositOptionPolicy === 'DepositAssetPackOptionPolicy' && session.pipelineOwnership.reviewRequiredBeforeDepositAdmission === true && + session.pipelineOwnership.sourceCriticalityDemandRoiPolicyOwnedByGate6 === true && session.pipelineOwnership.sourceCriticalityDemandRoiPolicyDeferredToGate6 === true && session.pipelineOwnership.admissionAndIndexingDeferredToGate7 === true && session.disclosure.sourceSafetyClass === 'source_safe_deposit_option_route_metadata' && diff --git a/uapi/jest.config.cjs b/uapi/jest.config.cjs index 0316bc33..dd7f3eb0 100644 --- a/uapi/jest.config.cjs +++ b/uapi/jest.config.cjs @@ -53,6 +53,7 @@ module.exports = { '^@bitcode/pipeline-asset-pack/reading-interface-product-parity$': '/../packages/pipelines/asset-pack/src/reading-interface-product-parity.ts', '^@bitcode/pipeline-asset-pack/reading-pipeline-contract$': '/../packages/pipelines/asset-pack/src/reading-pipeline-contract.ts', '^@bitcode/pipeline-asset-pack/deposit-asset-pack-options$': '/../packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts', + '^@bitcode/pipeline-asset-pack/deposit-asset-pack-option-policy$': '/../packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts', '^@bitcode/pipeline-asset-pack/src/(.+)$': '/../packages/pipelines/asset-pack/src/$1', '^@bitcode/([^/]+)/src/(.+)$': '/../packages/$1/src/$2', '^@bitcode/supabase/ssr/server$': '/tests/mocks/supabaseServerClient.ts', diff --git a/uapi/tests/depositPageClient.test.tsx b/uapi/tests/depositPageClient.test.tsx index af346f5f..3f4091e6 100644 --- a/uapi/tests/depositPageClient.test.tsx +++ b/uapi/tests/depositPageClient.test.tsx @@ -150,6 +150,8 @@ describe('DepositPageClient', () => { expect(screen.getByTestId('deposit-route-step-review-options')).toHaveAttribute('data-deposit-step-state', 'current'); expect(screen.getByText('Source-safe deposit state')).toBeInTheDocument(); expect(screen.getAllByText('DepositAssetPackOptionSynthesis').length).toBeGreaterThan(0); + expect(screen.getAllByText('DepositAssetPackOptionPolicy').length).toBeGreaterThan(0); + expect(screen.getAllByText(/BTC source-to-shares preview/u).length).toBeGreaterThan(0); expect(screen.getByTestId('deposit-option-capability-slice')).toBeInTheDocument(); expect(screen.getByTestId('deposit-option-implementation-pattern')).toBeInTheDocument(); expect(screen.getByTestId('deposit-option-proof-operations-slice')).toBeInTheDocument(); diff --git a/uapi/tests/depositRouteModel.test.ts b/uapi/tests/depositRouteModel.test.ts index f7f3c3d2..e79a8bee 100644 --- a/uapi/tests/depositRouteModel.test.ts +++ b/uapi/tests/depositRouteModel.test.ts @@ -15,6 +15,15 @@ describe('deposit-route-model', () => { sourceCommit: '31bbc0c5227b6b3aed5d107fd8507d35ec22970a', depositorInstructions: 'Create bounded source-safe AssetPack options for review.', sourcePathHints: ['uapi/app/deposit/DepositPageClient.tsx'], + sourceCriticalitySignals: [ + { + id: 'sub-critical-route-test', + label: 'Route test source is sub-critical.', + severity: 'sub-critical', + weight: 0.75, + }, + ], + depositorWalletId: 'wallet-depositor-1', optionsRequested: true, }); @@ -31,13 +40,18 @@ describe('deposit-route-model', () => { expect(session.activeStepId).toBe('review-options'); expect(session.pipelineOwnership).toMatchObject({ depositOptionPipeline: 'DepositAssetPackOptionSynthesis', + depositOptionPolicy: 'DepositAssetPackOptionPolicy', reviewRequiredBeforeDepositAdmission: true, + sourceCriticalityDemandRoiPolicyOwnedByGate6: true, sourceCriticalityDemandRoiPolicyDeferredToGate6: true, admissionAndIndexingDeferredToGate7: true, retainedTerminalDebugCompatible: true, }); expect(session.synthesis.schema).toBe('bitcode.deposit.asset-pack-option-synthesis'); expect(session.synthesis.optionCount).toBe(3); + expect(session.policy.schema).toBe('bitcode.deposit.asset-pack-option-policy-report'); + expect(session.policy.reviewablePositiveRoiCount).toBeGreaterThan(0); + expect(session.policy.aggregatePolicy.compensationPolicy).toBe('future-reader-btc-source-to-shares-route-preview'); expect(session.synthesis.options[0].reviewBoundary.state).toBe('reviewable-source-safe-option'); expect(session.disclosure).toMatchObject({ sourceSafetyClass: 'source_safe_deposit_option_route_metadata', @@ -63,6 +77,7 @@ describe('deposit-route-model', () => { sourceBranch: 'main', sourceCommit: '31bbc0c5227b6b3aed5d107fd8507d35ec22970a', sourcePathHints: ['packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts'], + sourceCriticalitySignals: [{ id: 'warning', severity: 'warning', weight: 0.5 }], optionsRequested: true, hasReviewedOption: false, }); @@ -77,6 +92,24 @@ describe('deposit-route-model', () => { expect(assertDepositRouteSessionSourceSafe(session).admitted).toBe(true); }); + it('keeps critical or negative-value policy blocked before Gate 7 admission', () => { + const session = buildDepositRouteSession({ + repositoryFullName: 'engineeredsoftware/ENGI', + sourceBranch: 'main', + sourceCommit: '31bbc0c5227b6b3aed5d107fd8507d35ec22970a', + sourcePathHints: ['packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts'], + sourceCriticalitySignals: [{ id: 'critical', severity: 'critical', weight: 1 }], + developmentCostSats: 9000, + expectedSettlementSats: 1000, + optionsRequested: true, + }); + + expect(session.policy.blockedCount).toBe(3); + expect(session.policy.evaluations.every((evaluation) => evaluation.policyDecision === 'blocked-before-admission')).toBe(true); + expect(session.pipelineOwnership.admissionAndIndexingDeferredToGate7).toBe(true); + expect(assertDepositRouteSessionSourceSafe(session).admitted).toBe(true); + }); + it('reads and writes the route-owned depositStage query parameter', () => { const params = new URLSearchParams('transactionId=deposit-run-2'); const withStage = writeDepositRouteStage(params, 'submit-deposit'); diff --git a/uapi/tsconfig.json b/uapi/tsconfig.json index 828bb501..608beaaf 100644 --- a/uapi/tsconfig.json +++ b/uapi/tsconfig.json @@ -73,6 +73,9 @@ "@bitcode/pipeline-asset-pack/deposit-asset-pack-options": [ "../packages/pipelines/asset-pack/src/deposit-asset-pack-options.ts" ], + "@bitcode/pipeline-asset-pack/deposit-asset-pack-option-policy": [ + "../packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts" + ], "@bitcode/*": [ "../packages/*/src", "../packages/*"