From 71a0fa2842e1ea93857587483ba5d7ee96396692 Mon Sep 17 00:00:00 2001 From: Garrett Maring Date: Fri, 29 May 2026 17:27:55 -0300 Subject: [PATCH] V44 Gate 5: Add Depositor earning supply intelligence Add source-safe DepositorEarningSupplyIntelligence for /deposit likely demand, unfit Need opportunities, source criticality, ROI posture, estimate-only BTC compensation ranges, source-to-shares proof boundaries, earning statements, and supply recommendations. Bind the V44 Depositor earnings supply opportunities artifact, generator, checker, protocol exports, tests, workflow hooks, and draft specification documentation updates. Validated with V44 gate checks, focused package and UAPI tests, package/UAPI/protocol typechecks, protocol tests, workflow YAML parsing, diff whitespace, ASCII hygiene, and changed-file secret scanning. --- ...positor-earnings-supply-opportunities.json | 362 +++++++++++++ .bitcode/v44-economic-domain-model.json | 26 +- ...4-packs-portfolio-market-intelligence.json | 26 +- .bitcode/v44-reading-budget-quote-policy.json | 26 +- .github/workflows/bitcode-canon-quality.yml | 3 + .github/workflows/bitcode-gate-quality.yml | 6 + BITCODE_SPEC_V44.md | 28 +- BITCODE_SPEC_V44_DELTA.md | 15 +- BITCODE_SPEC_V44_NOTES.md | 16 +- BITCODE_SPEC_V44_PARITY_MATRIX.md | 8 +- README.md | 15 +- SPECIFICATIONS_ROADMAP.md | 5 +- package.json | 3 + packages/pipelines/asset-pack/package.json | 1 + ...ositor-earning-supply-intelligence.test.ts | 109 ++++ .../depositor-earning-supply-intelligence.ts | 478 ++++++++++++++++++ packages/pipelines/asset-pack/src/index.ts | 4 +- packages/protocol/README.md | 12 + ...depositor-earnings-supply-opportunities.js | 273 ++++++++++ packages/protocol/src/index.d.ts | 13 + packages/protocol/src/index.js | 15 + ...itor-earnings-supply-opportunities.test.js | 59 +++ ...epositor-earnings-supply-opportunities.mjs | 198 ++++++++ ...epositor-earnings-supply-opportunities.mjs | 27 + uapi/app/deposit/DepositPageClient.tsx | 174 +++++++ uapi/app/deposit/deposit-route-model.ts | 27 + uapi/jest.config.cjs | 3 +- uapi/tests/depositPageClient.test.tsx | 8 + uapi/tests/depositRouteModel.test.ts | 48 ++ 29 files changed, 1929 insertions(+), 59 deletions(-) create mode 100644 .bitcode/v44-depositor-earnings-supply-opportunities.json create mode 100644 packages/pipelines/asset-pack/src/__tests__/depositor-earning-supply-intelligence.test.ts create mode 100644 packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts create mode 100644 packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js create mode 100644 packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js create mode 100644 scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs create mode 100644 scripts/generate-v44-depositor-earnings-supply-opportunities.mjs diff --git a/.bitcode/v44-depositor-earnings-supply-opportunities.json b/.bitcode/v44-depositor-earnings-supply-opportunities.json new file mode 100644 index 00000000..713b80c5 --- /dev/null +++ b/.bitcode/v44-depositor-earnings-supply-opportunities.json @@ -0,0 +1,362 @@ +{ + "artifactId": "v44-depositor-earnings-supply-opportunities", + "schemaId": "bitcode.v44.depositorEarningsSupplyOpportunities.v1", + "version": "V44", + "currentTarget": "V43", + "sourceSafetyVerdict": "source-safe-depositor-earnings-supply-opportunity-metadata", + "generatedAt": "deterministic", + "artifactRoot": "v44-depositor-earnings-supply-opportunities:7d08756f3b7ca3d960bcdce1", + "passed": true, + "objectIds": [ + "DepositorEarningSupplyIntelligence", + "DepositorEarningStatement", + "DepositSupplyOpportunity", + "UnfitNeedOpportunity", + "SourceCriticalityPosture", + "ExpectedCompensationRange", + "SourceSafeSupplyRecommendation" + ], + "earningStateIds": [ + "compensation-range-estimated", + "repair-required-before-earning", + "blocked-critical-source" + ], + "recommendationIds": [ + "approve-for-depository-review", + "repair-policy-before-admission", + "resynthesize-for-demand", + "withhold-critical-source" + ], + "demandOpportunityStateIds": [ + "strong-demand-opportunity", + "moderate-demand-opportunity", + "weak-demand-opportunity" + ], + "forbiddenPayloadIds": [ + "protected-source-payloads", + "raw-source-text", + "unpaid-assetpack-source", + "raw-prompts", + "interpolated-prompts", + "raw-provider-responses", + "credentials", + "wallet-private-material", + "private-settlement-payloads", + "value-bearing-mainnet-admission" + ], + "rows": [ + { + "rowId": "likely-demand-intelligence", + "owner": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "contract": "DepositorEarningSupplyIntelligence aggregates likely Reading demand from source-safe option policy evaluations.", + "requiredFields": [ + "likelyDemand", + "averageConfidence", + "strongDemandOptionCount", + "demandRoot" + ], + "rowRoot": "v44-depositor-earning-supply-row:3f21ab5d35fe3fe66b040e54", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + }, + { + "rowId": "unfit-need-opportunities", + "owner": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "contract": "Unfit Need opportunities are represented as source-safe weighted demand signals that guide supply creation without exposing Read or source payloads.", + "requiredFields": [ + "unfitNeedOpportunities", + "opportunityCount", + "opportunityRoot" + ], + "rowRoot": "v44-depositor-earning-supply-row:1657685e3e08e02653f801db", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + }, + { + "rowId": "earning-statements", + "owner": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "contract": "Depositor earning statements label all values as estimates and expose BTC compensation ranges, ROI, criticality, blockers, warnings, and statement roots.", + "requiredFields": [ + "DepositorEarningStatement", + "valueLabel", + "expectedCompensationRangeSats", + "blocked-critical-source" + ], + "rowRoot": "v44-depositor-earning-supply-row:0835a42862b22864611d6f1a", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + }, + { + "rowId": "source-safe-supply-recommendations", + "owner": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "contract": "Supply recommendations choose approve, repair, resynthesize, or withhold actions from source-safe demand, criticality, ROI, and compensation posture.", + "requiredFields": [ + "approve-for-depository-review", + "repair-policy-before-admission", + "resynthesize-for-demand", + "withhold-critical-source" + ], + "rowRoot": "v44-depositor-earning-supply-row:95fc05f465a5dbc377888ddf", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + }, + { + "rowId": "deposit-route-earning-readback", + "owner": "uapi/app/deposit/DepositPageClient.tsx", + "contract": "/deposit renders earning estimates, unfit Need opportunities, source-safe recommendations, and opportunity roots beside the five-step Depositing path.", + "requiredFields": [ + "Supply opportunity", + "Earning estimate", + "Unfit Need opportunities", + "DepositorEarningSupplyIntelligence" + ], + "rowRoot": "v44-depositor-earning-supply-row:f701e70f93e3ece09d9e402c", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + }, + { + "rowId": "source-to-shares-compensation-basis", + "owner": "packages/btd/src/source-to-shares.ts", + "contract": "Depositor earning ranges remain estimate-only until future Need-Fit settlement produces source-to-shares allocation receipts.", + "requiredFields": [ + "source-to-shares-largest-remainder", + "settlementAllocations", + "settlementConservation" + ], + "rowRoot": "v44-depositor-earning-supply-row:874063553da1f69224274403", + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "unpaidAssetPackSourceVisible": false + } + ], + "sourceRoots": { + "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", + "spec": "BITCODE_SPEC_V44.md:f42417c87b28658f95bfc5e2", + "delta": "BITCODE_SPEC_V44_DELTA.md:67047539c440859038b21e0e", + "notes": "BITCODE_SPEC_V44_NOTES.md:65d2a226a68ddc14e10d4f1d", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:720f3406bcadd2098ba3a509", + "roadmap": "SPECIFICATIONS_ROADMAP.md:2ef8f1bf59c26479728c3153", + "readme": "README.md:a6409b31ee2230d6889bf26f", + "protocolReadme": "packages/protocol/README.md:e33e94fa5584a2a44cd49c1f", + "packageJson": "package.json:8d6cf25f9345ca24f1a6aa3b", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:11c68267a63ed03d95524e98", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:dfd0de96bd301ec722e4ea67", + "economicModel": "packages/protocol/src/canonical/v44-economic-domain-model.js:21b8f5c80ad8322dff2909ed", + "portfolioMarketIntelligence": "packages/protocol/src/canonical/v44-packs-portfolio-market-intelligence.js:f5d37e086c9bbbdb6202da53", + "optionPolicy": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts:12816b23b2d8e304ab4a1638", + "earningSupplyIntelligence": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts:e0ec2d83cfaf3bfaaa126387", + "earningSupplyIntelligenceTest": "packages/pipelines/asset-pack/src/__tests__/depositor-earning-supply-intelligence.test.ts:3b7a869e6262f6f5ebcc71fe", + "depositModel": "uapi/app/deposit/deposit-route-model.ts:b4a51a495a193eff88f1f103", + "depositClient": "uapi/app/deposit/DepositPageClient.tsx:3aee0372e480aa8212be7fe0", + "depositRouteTest": "uapi/tests/depositRouteModel.test.ts:f60d0f4541bb0dae5d455f13", + "depositPageTest": "uapi/tests/depositPageClient.test.tsx:44960f6c465c87194a689958", + "assetPackPackageIndex": "packages/pipelines/asset-pack/src/index.ts:4d900afeb3eb6ab1202403ee", + "assetPackPackageManifest": "packages/pipelines/asset-pack/package.json:7f4a82493f32385420e2082c", + "sourceToShares": "packages/btd/src/source-to-shares.ts:6e2e84251b29ba2477766708", + "packageIndex": "packages/protocol/src/index.js:806cfbf3ee86977fead7b928", + "packageTypes": "packages/protocol/src/index.d.ts:907bd1de313f4d5503462765", + "packageSource": "packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js:cf9cf5f99f00dbf3201c8c8e", + "packageTest": "packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js:1b025c1904f94a1069b64ddf", + "generator": "scripts/generate-v44-depositor-earnings-supply-opportunities.mjs:0844124207cbfe8264f12a2f", + "checker": "scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs:85467da9804f946a18c764ce" + }, + "predicateResults": [ + { + "id": "active-canon-pointer-remains-v43", + "sourcePath": "BITCODE_SPEC.txt", + "passed": true + }, + { + "id": "spec-defines-gate5", + "sourcePath": "BITCODE_SPEC_V44.md", + "passed": true + }, + { + "id": "spec-names-gate5-artifact", + "sourcePath": "BITCODE_SPEC_V44.md", + "passed": true + }, + { + "id": "delta-records-gate5", + "sourcePath": "BITCODE_SPEC_V44_DELTA.md", + "passed": true + }, + { + "id": "notes-records-gate5", + "sourcePath": "BITCODE_SPEC_V44_NOTES.md", + "passed": true + }, + { + "id": "parity-records-gate5", + "sourcePath": "BITCODE_SPEC_V44_PARITY_MATRIX.md", + "passed": true + }, + { + "id": "roadmap-records-gate5", + "sourcePath": "SPECIFICATIONS_ROADMAP.md", + "passed": true + }, + { + "id": "readme-records-gate5", + "sourcePath": "README.md", + "passed": true + }, + { + "id": "protocol-readme-records-gate5", + "sourcePath": "packages/protocol/README.md", + "passed": true + }, + { + "id": "economic-model-prerequisite-present", + "sourcePath": "packages/protocol/src/canonical/v44-economic-domain-model.js", + "passed": true + }, + { + "id": "portfolio-market-prerequisite-present", + "sourcePath": "packages/protocol/src/canonical/v44-packs-portfolio-market-intelligence.js", + "passed": true + }, + { + "id": "option-policy-prerequisite-present", + "sourcePath": "packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts", + "passed": true + }, + { + "id": "earning-intelligence-defines-builder", + "sourcePath": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "passed": true + }, + { + "id": "earning-intelligence-defines-demand", + "sourcePath": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "passed": true + }, + { + "id": "earning-intelligence-defines-statements", + "sourcePath": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "passed": true + }, + { + "id": "earning-intelligence-defines-recommendations", + "sourcePath": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "passed": true + }, + { + "id": "earning-intelligence-forbids-source-leakage", + "sourcePath": "packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts", + "passed": true + }, + { + "id": "asset-pack-package-exports-intelligence", + "sourcePath": "packages/pipelines/asset-pack/src/index.ts", + "passed": true + }, + { + "id": "asset-pack-manifest-exports-intelligence", + "sourcePath": "packages/pipelines/asset-pack/package.json", + "passed": true + }, + { + "id": "deposit-model-uses-intelligence", + "sourcePath": "uapi/app/deposit/deposit-route-model.ts", + "passed": true + }, + { + "id": "deposit-client-renders-earnings", + "sourcePath": "uapi/app/deposit/DepositPageClient.tsx", + "passed": true + }, + { + "id": "earning-test-covers-intelligence", + "sourcePath": "packages/pipelines/asset-pack/src/__tests__/depositor-earning-supply-intelligence.test.ts", + "passed": true + }, + { + "id": "route-test-covers-intelligence", + "sourcePath": "uapi/tests/depositRouteModel.test.ts", + "passed": true + }, + { + "id": "page-test-covers-intelligence", + "sourcePath": "uapi/tests/depositPageClient.test.tsx", + "passed": true + }, + { + "id": "source-to-shares-prerequisite-present", + "sourcePath": "packages/btd/src/source-to-shares.ts", + "passed": true + }, + { + "id": "package-test-covers-gate5", + "sourcePath": "packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js", + "passed": true + }, + { + "id": "package-exports-gate5", + "sourcePath": "packages/protocol/src/index.js", + "passed": true + }, + { + "id": "package-types-export-gate5", + "sourcePath": "packages/protocol/src/index.d.ts", + "passed": true + }, + { + "id": "package-json-exposes-gate5", + "sourcePath": "package.json", + "passed": true + }, + { + "id": "gate-workflow-runs-gate5", + "sourcePath": ".github/workflows/bitcode-gate-quality.yml", + "passed": true + }, + { + "id": "canon-workflow-runs-gate5", + "sourcePath": ".github/workflows/bitcode-canon-quality.yml", + "passed": true + }, + { + "id": "generator-exists", + "sourcePath": "scripts/generate-v44-depositor-earnings-supply-opportunities.mjs", + "passed": true + }, + { + "id": "checker-exists", + "sourcePath": "scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs", + "passed": true + } + ], + "coverage": { + "depositorEarningSupplyIntelligenceImplemented": true, + "likelyDemandImplemented": true, + "unfitNeedOpportunitiesImplemented": true, + "roiPostureImplemented": true, + "sourceCriticalityPostureImplemented": true, + "expectedCompensationRangesImplemented": true, + "earningStatementsImplemented": true, + "sourceSafeSupplyRecommendationsImplemented": true, + "depositRouteUiImplemented": true, + "sourceToSharesEstimateBoundaryImplemented": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawSourceTextVisible": false, + "sourceSnippetVisible": false, + "rawPromptVisible": false, + "interpolatedPromptVisible": false, + "rawProviderResponseVisible": false, + "unpaidAssetPackSourceVisible": false, + "credentialsSerialized": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetAdmitted": false, + "requiredPredicateCount": 33, + "passedPredicateCount": 33, + "failedPredicateIds": [] + } +} diff --git a/.bitcode/v44-economic-domain-model.json b/.bitcode/v44-economic-domain-model.json index 2fcda699..1db3e59b 100644 --- a/.bitcode/v44-economic-domain-model.json +++ b/.bitcode/v44-economic-domain-model.json @@ -5,7 +5,7 @@ "currentTarget": "V43", "sourceSafetyVerdict": "source-safe-economic-domain-model-metadata", "generatedAt": "deterministic", - "artifactRoot": "v44-economic-domain-model:ec44bc6e9df92162dfa92bfe", + "artifactRoot": "v44-economic-domain-model:a043eb060041550b6d966f70", "passed": true, "economicObjectIds": [ "EnterprisePackPortfolio", @@ -759,18 +759,18 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", - "spec": "BITCODE_SPEC_V44.md:c5081509af1ff529f93578c2", - "delta": "BITCODE_SPEC_V44_DELTA.md:3bb300cfcf9848e84dd567b8", - "notes": "BITCODE_SPEC_V44_NOTES.md:2fb9c45ff4d5aab74d4877f1", - "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:3e6dbeeeb9c4acf7949e55b3", - "roadmap": "SPECIFICATIONS_ROADMAP.md:b68526af5b69fcfd077db62a", - "readme": "README.md:57205081ca8e0253edb60d83", - "protocolReadme": "packages/protocol/README.md:503724d451dd53ba1895cedf", - "packageJson": "package.json:60ace742266c6fa5ef22049b", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:1e58eb822e2b550fc7c7fcba", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:6d06d4145fc763240d239fe7", - "packageIndex": "packages/protocol/src/index.js:e359325bd742aff90897b6ec", - "packageTypes": "packages/protocol/src/index.d.ts:4904191a7254fdf41b8b79ff", + "spec": "BITCODE_SPEC_V44.md:f42417c87b28658f95bfc5e2", + "delta": "BITCODE_SPEC_V44_DELTA.md:67047539c440859038b21e0e", + "notes": "BITCODE_SPEC_V44_NOTES.md:65d2a226a68ddc14e10d4f1d", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:720f3406bcadd2098ba3a509", + "roadmap": "SPECIFICATIONS_ROADMAP.md:2ef8f1bf59c26479728c3153", + "readme": "README.md:a6409b31ee2230d6889bf26f", + "protocolReadme": "packages/protocol/README.md:e33e94fa5584a2a44cd49c1f", + "packageJson": "package.json:8d6cf25f9345ca24f1a6aa3b", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:11c68267a63ed03d95524e98", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:dfd0de96bd301ec722e4ea67", + "packageIndex": "packages/protocol/src/index.js:806cfbf3ee86977fead7b928", + "packageTypes": "packages/protocol/src/index.d.ts:907bd1de313f4d5503462765", "packageSource": "packages/protocol/src/canonical/v44-economic-domain-model.js:21b8f5c80ad8322dff2909ed", "packageTest": "packages/protocol/test/v44-economic-domain-model.test.js:b89f71aa0cf578dabbec3cd9", "generator": "scripts/generate-v44-economic-domain-model.mjs:3390fbc087e919bedb14550c", diff --git a/.bitcode/v44-packs-portfolio-market-intelligence.json b/.bitcode/v44-packs-portfolio-market-intelligence.json index 4f125dd9..01fc336a 100644 --- a/.bitcode/v44-packs-portfolio-market-intelligence.json +++ b/.bitcode/v44-packs-portfolio-market-intelligence.json @@ -5,7 +5,7 @@ "currentTarget": "V43", "sourceSafetyVerdict": "source-safe-packs-portfolio-market-intelligence-metadata", "generatedAt": "deterministic", - "artifactRoot": "v44-packs-portfolio-market-intelligence:a8a9feee64f670ea7bed9afc", + "artifactRoot": "v44-packs-portfolio-market-intelligence:7285b92f4d7d0c1634de4446", "passed": true, "portfolioViewIds": [ "enterprise-pack-portfolio", @@ -109,23 +109,23 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", - "spec": "BITCODE_SPEC_V44.md:c5081509af1ff529f93578c2", - "delta": "BITCODE_SPEC_V44_DELTA.md:3bb300cfcf9848e84dd567b8", - "notes": "BITCODE_SPEC_V44_NOTES.md:2fb9c45ff4d5aab74d4877f1", - "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:3e6dbeeeb9c4acf7949e55b3", - "roadmap": "SPECIFICATIONS_ROADMAP.md:b68526af5b69fcfd077db62a", - "readme": "README.md:57205081ca8e0253edb60d83", - "protocolReadme": "packages/protocol/README.md:503724d451dd53ba1895cedf", - "packageJson": "package.json:60ace742266c6fa5ef22049b", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:1e58eb822e2b550fc7c7fcba", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:6d06d4145fc763240d239fe7", + "spec": "BITCODE_SPEC_V44.md:f42417c87b28658f95bfc5e2", + "delta": "BITCODE_SPEC_V44_DELTA.md:67047539c440859038b21e0e", + "notes": "BITCODE_SPEC_V44_NOTES.md:65d2a226a68ddc14e10d4f1d", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:720f3406bcadd2098ba3a509", + "roadmap": "SPECIFICATIONS_ROADMAP.md:2ef8f1bf59c26479728c3153", + "readme": "README.md:a6409b31ee2230d6889bf26f", + "protocolReadme": "packages/protocol/README.md:e33e94fa5584a2a44cd49c1f", + "packageJson": "package.json:8d6cf25f9345ca24f1a6aa3b", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:11c68267a63ed03d95524e98", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:dfd0de96bd301ec722e4ea67", "economicModel": "packages/protocol/src/canonical/v44-economic-domain-model.js:21b8f5c80ad8322dff2909ed", "model": "uapi/components/base/bitcode/activity/pack-activity-model.ts:77058cc82039a3bd1b7514bf", "route": "uapi/app/api/packs/activity/route.ts:97c5a4539d48562eb5de66e8", "client": "uapi/app/packs/PacksPageClient.tsx:b70aa97a8022a9c42995a030", "uapiTest": "uapi/tests/packActivityModel.test.ts:541e71f2806dc1497379d0f1", - "packageIndex": "packages/protocol/src/index.js:e359325bd742aff90897b6ec", - "packageTypes": "packages/protocol/src/index.d.ts:4904191a7254fdf41b8b79ff", + "packageIndex": "packages/protocol/src/index.js:806cfbf3ee86977fead7b928", + "packageTypes": "packages/protocol/src/index.d.ts:907bd1de313f4d5503462765", "packageTest": "packages/protocol/test/v44-packs-portfolio-market-intelligence.test.js:ea02fa03d210e6480036fc0f", "generator": "scripts/generate-v44-packs-portfolio-market-intelligence.mjs:c106ef7138e3a330d405bec2", "checker": "scripts/check-v44-gate3-packs-portfolio-market-intelligence.mjs:0de0b87cbc96bb307cc1533a" diff --git a/.bitcode/v44-reading-budget-quote-policy.json b/.bitcode/v44-reading-budget-quote-policy.json index f7534b2e..47924f23 100644 --- a/.bitcode/v44-reading-budget-quote-policy.json +++ b/.bitcode/v44-reading-budget-quote-policy.json @@ -5,7 +5,7 @@ "currentTarget": "V43", "sourceSafetyVerdict": "source-safe-reading-budget-quote-policy-metadata", "generatedAt": "deterministic", - "artifactRoot": "v44-reading-budget-quote-policy:8ee2dddcc13bb816acf6e881", + "artifactRoot": "v44-reading-budget-quote-policy:89af8933000a377911238076", "passed": true, "objectIds": [ "ReadingBudgetPolicy", @@ -145,24 +145,24 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", - "spec": "BITCODE_SPEC_V44.md:c5081509af1ff529f93578c2", - "delta": "BITCODE_SPEC_V44_DELTA.md:3bb300cfcf9848e84dd567b8", - "notes": "BITCODE_SPEC_V44_NOTES.md:2fb9c45ff4d5aab74d4877f1", - "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:3e6dbeeeb9c4acf7949e55b3", - "roadmap": "SPECIFICATIONS_ROADMAP.md:b68526af5b69fcfd077db62a", - "readme": "README.md:57205081ca8e0253edb60d83", - "protocolReadme": "packages/protocol/README.md:503724d451dd53ba1895cedf", - "packageJson": "package.json:60ace742266c6fa5ef22049b", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:1e58eb822e2b550fc7c7fcba", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:6d06d4145fc763240d239fe7", + "spec": "BITCODE_SPEC_V44.md:f42417c87b28658f95bfc5e2", + "delta": "BITCODE_SPEC_V44_DELTA.md:67047539c440859038b21e0e", + "notes": "BITCODE_SPEC_V44_NOTES.md:65d2a226a68ddc14e10d4f1d", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:720f3406bcadd2098ba3a509", + "roadmap": "SPECIFICATIONS_ROADMAP.md:2ef8f1bf59c26479728c3153", + "readme": "README.md:a6409b31ee2230d6889bf26f", + "protocolReadme": "packages/protocol/README.md:e33e94fa5584a2a44cd49c1f", + "packageJson": "package.json:8d6cf25f9345ca24f1a6aa3b", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:11c68267a63ed03d95524e98", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:dfd0de96bd301ec722e4ea67", "economicModel": "packages/protocol/src/canonical/v44-economic-domain-model.js:21b8f5c80ad8322dff2909ed", "readModel": "uapi/app/read/read-route-model.ts:a31ae532904b0ba357eb9e67", "readClient": "uapi/app/read/ReadPageClient.tsx:8c810ed63b6cf895cead0a01", "readModelTest": "uapi/tests/readRouteModel.test.ts:622a125a72c8457baf4c9d6d", "sourceToShares": "packages/btd/src/source-to-shares.ts:6e2e84251b29ba2477766708", "btcFeeOperation": "packages/btd/src/btc-fee-operation.ts:65f910e8e471fe199939e9c4", - "packageIndex": "packages/protocol/src/index.js:e359325bd742aff90897b6ec", - "packageTypes": "packages/protocol/src/index.d.ts:4904191a7254fdf41b8b79ff", + "packageIndex": "packages/protocol/src/index.js:806cfbf3ee86977fead7b928", + "packageTypes": "packages/protocol/src/index.d.ts:907bd1de313f4d5503462765", "packageSource": "packages/protocol/src/canonical/v44-reading-budget-quote-policy.js:d663034fe86ccbe85d5749f5", "packageTest": "packages/protocol/test/v44-reading-budget-quote-policy.test.js:2d9b19c509e0b28a829c44a3", "generator": "scripts/generate-v44-reading-budget-quote-policy.mjs:e2c376cb03ef80c210eef688", diff --git a/.github/workflows/bitcode-canon-quality.yml b/.github/workflows/bitcode-canon-quality.yml index daa5b774..d3ac55c4 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -373,6 +373,9 @@ jobs: if [ -f scripts/check-v44-gate4-reading-budget-quote-policy.mjs ]; then node scripts/check-v44-gate4-reading-budget-quote-policy.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ -f scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs ]; then + node scripts/check-v44-gate5-depositor-earnings-supply-opportunities.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 3e71d29a..c72646b2 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -502,6 +502,9 @@ jobs: if [ -f scripts/check-v44-gate4-reading-budget-quote-policy.mjs ]; then node scripts/check-v44-gate4-reading-budget-quote-policy.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ -f scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs ]; then + node scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 @@ -546,6 +549,9 @@ jobs: if [ "$POINTER" = "V43" ] && [ -f scripts/check-v44-gate4-reading-budget-quote-policy.mjs ]; then node scripts/check-v44-gate4-reading-budget-quote-policy.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ "$POINTER" = "V43" ] && [ -f scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs ]; then + node scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests + fi if [ "$POINTER" != "V43" ]; then if [ -f scripts/check-v43-gate1-packs-read-deposit-roadmap.mjs ]; then node scripts/check-v43-gate1-packs-read-deposit-roadmap.mjs --skip-branch-check diff --git a/BITCODE_SPEC_V44.md b/BITCODE_SPEC_V44.md index 3ca127ac..4c6300b7 100644 --- a/BITCODE_SPEC_V44.md +++ b/BITCODE_SPEC_V44.md @@ -3,12 +3,12 @@ ## Status - Version: `V44` -- V44 state: draft Gate 4 Reading budget quote policy work over promoted V43 product routes +- V44 state: draft Gate 5 Depositor earnings supply opportunity work over promoted V43 product routes - Current canonical/latest target: `V43` - Prior canonical anchor: `BITCODE_SPEC_V43.md` - Prior generated proof appendix: `BITCODE_SPEC_V43_PROVEN.md` -- Generated structured artifact inventory: draft `.bitcode/v44-*` artifacts now include Gate 2 economic domain, Gate 3 Packs portfolio market intelligence, and Gate 4 Reading budget quote policy reports; all remain source-safe metadata only -- Source parity state: V44 begins from promoted `/packs`, `/read`, `/deposit`, agentic Depositing, five-step Reading, BTD/BTC settlement, and PackActivity canon; Gate 4 binds `/read` budget and quote policy without changing settlement law +- Generated structured artifact inventory: draft `.bitcode/v44-*` artifacts now include Gate 2 economic domain, Gate 3 Packs portfolio market intelligence, Gate 4 Reading budget quote policy, and Gate 5 Depositor earnings supply opportunity reports; all remain source-safe metadata only +- Source parity state: V44 begins from promoted `/packs`, `/read`, `/deposit`, agentic Depositing, five-step Reading, BTD/BTC settlement, and PackActivity canon; Gate 5 binds `/deposit` earning, demand, ROI, criticality, compensation range, and source-safe supply recommendation readback without minting BTD or admitting value-bearing mainnet - Notes companion: `BITCODE_SPEC_V44_NOTES.md` - Delta companion: `BITCODE_SPEC_V44_DELTA.md` - Parity companion: `BITCODE_SPEC_V44_PARITY_MATRIX.md` @@ -246,6 +246,20 @@ Gate 5 must bind deposit-side economic clarity: likely demand, unfit Need opportunities, ROI posture, source criticality, expected compensation ranges, earning statements, and source-safe Depository supply recommendations. +Gate 5 closes through `V44DepositorEarningsSupplyOpportunities` in +`packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js`, +deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json`, +`generate:v44-depositor-earnings-supply-opportunities`, +`check:v44-depositor-earnings-supply-opportunities`, and `check:v44-gate5`. +The `/deposit` route session now projects `DepositorEarningSupplyIntelligence` +with source-safe likely demand, unfit Need opportunity signals, ROI posture, +source criticality posture, estimate-only BTC compensation ranges, +source-to-shares proof boundaries, earning statements, and supply +recommendations. `/deposit` renders those earning, opportunity, compensation, +and recommendation fields without exposing protected source, raw source text, +unpaid AssetPack source, prompts, provider responses, wallet private material, +private settlement payloads, or value-bearing mainnet admission. + ## V44 Gate 6 BTD/BTC Accounting And Contributor Compensation Statements Gate 6 must bind BTD range state, BTC settlement observations, source-to-shares @@ -607,7 +621,7 @@ quality, accessibility, visual inspectability, and generated quality evidence. | `.bitcode/v44-economic-domain-model.json` | economic domain model | implemented-source-safe | | `.bitcode/v44-packs-portfolio-market-intelligence.json` | Packs portfolio and market intelligence | implemented-source-safe | | `.bitcode/v44-reading-budget-quote-policy.json` | Reading budget and quote policy | implemented-source-safe | -| `.bitcode/v44-depositor-earnings-supply-opportunities.json` | depositor earnings and supply opportunities | planned | +| `.bitcode/v44-depositor-earnings-supply-opportunities.json` | depositor earnings and supply opportunities | implemented-source-safe | | `.bitcode/v44-btd-btc-compensation-statements.json` | BTD/BTC compensation statements | planned | | `.bitcode/v44-organization-policy-wallet-authority.json` | organization policy and wallet authority | planned | | `.bitcode/v44-enterprise-economic-ux.json` | enterprise economic UX | planned | @@ -682,6 +696,10 @@ Gate 3 validates with Gate 4 validates with `pnpm run generate:v44-reading-budget-quote-policy`, `pnpm run check:v44-reading-budget-quote-policy`, and `pnpm run check:v44-gate4`. +Gate 5 validates with +`pnpm run generate:v44-depositor-earnings-supply-opportunities`, +`pnpm run check:v44-depositor-earnings-supply-opportunities`, and +`pnpm run check:v44-gate5`. Shared draft posture validates with `node scripts/check-bitcode-spec-family.mjs --version V44 --mode draft --current-target V43`, `node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V43 --draft-target V44`, @@ -756,7 +774,7 @@ Inherited. | `.bitcode/v44-economic-domain-model.json` | economic domain model | implemented-source-safe | | `.bitcode/v44-packs-portfolio-market-intelligence.json` | portfolio and market intelligence | implemented-source-safe | | `.bitcode/v44-reading-budget-quote-policy.json` | budget and quote policy | implemented-source-safe | -| `.bitcode/v44-depositor-earnings-supply-opportunities.json` | depositor earning opportunity | planned | +| `.bitcode/v44-depositor-earnings-supply-opportunities.json` | depositor earning opportunity | implemented-source-safe | | `.bitcode/v44-btd-btc-compensation-statements.json` | BTD/BTC/source-to-shares statement | planned | | `.bitcode/v44-organization-policy-wallet-authority.json` | organization policy and wallet authority | planned | | `.bitcode/v44-enterprise-economic-ux.json` | enterprise economic UX | planned | diff --git a/BITCODE_SPEC_V44_DELTA.md b/BITCODE_SPEC_V44_DELTA.md index b4cc23aa..1e79a4c6 100644 --- a/BITCODE_SPEC_V44_DELTA.md +++ b/BITCODE_SPEC_V44_DELTA.md @@ -3,12 +3,12 @@ ## Status - Version: `V44` -- V44 state: draft Gate 4 Reading budget quote policy work over promoted V43 +- V44 state: draft Gate 5 Depositor earnings supply opportunity work over promoted V43 - Current canonical/latest target: `V43` - Prior canonical anchor: `BITCODE_SPEC_V43.md` - Prior generated proof appendix: `BITCODE_SPEC_V43_PROVEN.md` -- Generated structured artifact inventory: Gate 2 adds deterministic `.bitcode/v44-economic-domain-model.json`; Gate 3 adds deterministic `.bitcode/v44-packs-portfolio-market-intelligence.json` -- Source parity state: Gate 3 binds package-backed Packs portfolio/market intelligence, route/API/UI projections, docs, workflow, package script, checker, and protocol/UAPI tests +- Generated structured artifact inventory: Gate 2 adds deterministic `.bitcode/v44-economic-domain-model.json`; Gate 3 adds deterministic `.bitcode/v44-packs-portfolio-market-intelligence.json`; Gate 4 adds deterministic `.bitcode/v44-reading-budget-quote-policy.json`; Gate 5 adds deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json` +- Source parity state: Gate 5 binds package-backed Depositor earning supply intelligence, `/deposit` route/UI projections, docs, workflow, package script, checker, and protocol/package/UAPI tests - Notes companion: `BITCODE_SPEC_V44_NOTES.md` - Delta companion: `BITCODE_SPEC_V44_DELTA.md` - Parity companion: `BITCODE_SPEC_V44_PARITY_MATRIX.md` @@ -69,6 +69,11 @@ V44 Gate 4 closes `/read` budget and quote governance around source-safe AssetPack previews. It does not observe payment, transfer BTD rights, execute contributor payouts, or admit value-bearing mainnet operation. +V44 Gate 5 closes `/deposit` depositor earning and supply opportunity +intelligence over source-safe deposit options. It does not execute payout, +mint BTD, disclose protected source, or convert estimated compensation ranges +into final settlement truth. + ## Pre-Implementation Sequence 1. Open V44 spec family, roadmap, checker, package script, workflow posture, @@ -96,6 +101,10 @@ Gate 3 validates with Gate 4 validates with `pnpm run generate:v44-reading-budget-quote-policy`, `pnpm run check:v44-reading-budget-quote-policy`, and `pnpm run check:v44-gate4`. +Gate 5 validates with +`pnpm run generate:v44-depositor-earnings-supply-opportunities`, +`pnpm run check:v44-depositor-earnings-supply-opportunities`, and +`pnpm run check:v44-gate5`. Shared draft posture validates with `node scripts/check-bitcode-spec-family.mjs --version V44 --mode draft --current-target V43`, `node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V43 --draft-target V44`, diff --git a/BITCODE_SPEC_V44_NOTES.md b/BITCODE_SPEC_V44_NOTES.md index 6779f214..2810b62b 100644 --- a/BITCODE_SPEC_V44_NOTES.md +++ b/BITCODE_SPEC_V44_NOTES.md @@ -3,12 +3,12 @@ ## Status - Version: `V44` -- V44 state: draft notes include Gate 4 Reading budget quote policy work over promoted V43 +- V44 state: draft notes include Gate 5 Depositor earnings supply opportunity work over promoted V43 - Current canonical/latest target: `V43` - Prior canonical anchor: `BITCODE_SPEC_V43.md` - Prior generated proof appendix: `BITCODE_SPEC_V43_PROVEN.md` -- Generated structured artifact inventory: Gate 2 adds deterministic `.bitcode/v44-economic-domain-model.json`; Gate 3 adds deterministic `.bitcode/v44-packs-portfolio-market-intelligence.json`; Gate 4 adds deterministic `.bitcode/v44-reading-budget-quote-policy.json` -- Source parity state: notes align roadmap, docs, workflow posture, package source, generated artifact, receipt taxonomy, `/packs` portfolio market intelligence, and `/read` budget quote policy for active V43 / draft V44 +- Generated structured artifact inventory: Gate 2 adds deterministic `.bitcode/v44-economic-domain-model.json`; Gate 3 adds deterministic `.bitcode/v44-packs-portfolio-market-intelligence.json`; Gate 4 adds deterministic `.bitcode/v44-reading-budget-quote-policy.json`; Gate 5 adds deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json` +- Source parity state: notes align roadmap, docs, workflow posture, package source, generated artifact, receipt taxonomy, `/packs` portfolio market intelligence, `/read` budget quote policy, and `/deposit` earning supply opportunity intelligence for active V43 / draft V44 - Scope: V44 notes for digitizing and tokenizing scaled engineering economies through enterprise AssetPack portfolio, market intelligence, BTD/BTC accounting, governance, and compensation operation - Last fully realized canonical target preserved in source: `V43` @@ -106,6 +106,16 @@ settlement private material, and it cannot treat a quote as final settlement. Payment observation, BTD rights transfer, delivery unlock, and contributor compensation remain later receipt-backed steps. +## Gate 5 note + +Gate 5 makes `/deposit` economically clearer without changing deposit law. +The route can show likely demand, unfit Need opportunities, source +criticality, ROI, estimate-only BTC compensation ranges, earning statements, +and source-safe supply recommendations. It cannot mint BTD, execute +compensation, disclose protected source, or treat estimated earning ranges as +final settlement truth. Source-to-shares remains the future receipt-backed +allocation method after a paid Need-Fit settlement selects admitted supply. + ## Gate 3 note Gate 3 makes `/packs` the first scaled economic inspection surface. It keeps diff --git a/BITCODE_SPEC_V44_PARITY_MATRIX.md b/BITCODE_SPEC_V44_PARITY_MATRIX.md index b59c467b..88d3f6aa 100644 --- a/BITCODE_SPEC_V44_PARITY_MATRIX.md +++ b/BITCODE_SPEC_V44_PARITY_MATRIX.md @@ -3,12 +3,12 @@ ## Status - Version: `V44` -- V44 state: draft parity includes Gate 4 Reading budget quote policy work +- V44 state: draft parity includes Gate 5 Depositor earnings supply opportunity work - Current canonical/latest target: `V43` - Prior canonical anchor: `BITCODE_SPEC_V43.md` - Prior generated proof appendix: `BITCODE_SPEC_V43_PROVEN.md` -- Generated structured artifact inventory: Gate 2 adds deterministic `.bitcode/v44-economic-domain-model.json`; Gate 3 adds deterministic `.bitcode/v44-packs-portfolio-market-intelligence.json` -- Source parity state: Gate 3 requires package/API/UI/docs/workflow/checker/test parity for Packs portfolio market intelligence +- Generated structured artifact inventory: Gate 2 adds deterministic `.bitcode/v44-economic-domain-model.json`; Gate 3 adds deterministic `.bitcode/v44-packs-portfolio-market-intelligence.json`; Gate 4 adds deterministic `.bitcode/v44-reading-budget-quote-policy.json`; Gate 5 adds deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json` +- Source parity state: Gate 5 requires package/route/UI/docs/workflow/checker/test parity for Depositor earning supply opportunity intelligence - Scope: parity for V44 enterprise economic operation over promoted V43 product routes - Last fully realized canonical target preserved in source: `V43` @@ -32,7 +32,7 @@ artifacts, workflow checks, and local/staging rehearsal receipts. | Economic domain model | Portfolio positions, market signals, quote states, settlement states, statements, repair cases | implemented | | Packs portfolio | `/packs` portfolio search, market intelligence, saved filters, economic facets | implemented | | Reading procurement | Budget, quote policy, approval thresholds, purchase governance through `.bitcode/v44-reading-budget-quote-policy.json` | implemented | -| Depositor earnings | ROI, demand, compensation opportunity, supply recommendations | drafted | +| Depositor earnings | ROI, demand, compensation opportunity, supply recommendations through `.bitcode/v44-depositor-earnings-supply-opportunities.json` | implemented | | Accounting statements | BTD/BTC/source-to-shares statements and reconciliation | drafted | | Organization governance | Roles, budgets, wallet authority, source criticality, approvals | drafted | | Enterprise UX | Dense economic surfaces, proof expansion, responsive/accessibility proof | drafted | diff --git a/README.md b/README.md index d90a5e2f..923bf1db 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ The promoted V43 enterprise routes are: The active V44 draft target makes those routes economically operable at enterprise scale: `/packs` becomes the portfolio and market-intelligence surface, `/read` gains budgeted procurement and quote governance, and -`/deposit` gains earning, demand, ROI, and compensation-statement visibility. +`/deposit` gains earning, demand, ROI, compensation-range, and source-safe +supply opportunity visibility. V41 Gate 1 opens the prompts-as-programs specification family over active V40 with `check:v41-gate1`. V41 will catalogue every raw PromptPart and composed @@ -322,6 +323,18 @@ readback, and tests that continue withholding protected source, unpaid AssetPack source, raw prompts, provider payloads, wallet private material, private settlement payloads, and value-bearing mainnet operation. +V44 Gate 5 adds `V44DepositorEarningsSupplyOpportunities`, +`.bitcode/v44-depositor-earnings-supply-opportunities.json`, +`generate:v44-depositor-earnings-supply-opportunities`, +`check:v44-depositor-earnings-supply-opportunities`, and `check:v44-gate5`. +It binds `/deposit` to source-safe `DepositorEarningSupplyIntelligence`: +likely demand, unfit Need opportunities, source criticality, ROI posture, +estimate-only BTC compensation ranges, source-to-shares proof boundaries, +earning statements, supply recommendations, route UI readback, and tests that +continue withholding protected source, raw source text, unpaid AssetPack +source, prompts, provider payloads, wallet private material, private +settlement payloads, and value-bearing mainnet operation. + 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 63f75d19..7ac9ad43 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -5,14 +5,15 @@ - Current active canonical pointer: `BITCODE_SPEC.txt` -> `V43` - Current active canon: `BITCODE_SPEC_V43.md` - Current draft target: `BITCODE_SPEC_V44.md`. -- Current working gate: V44 Gate 4 Reading Budget, Quote Policy, And Procurement Governance. -- Next queued work after V44 Gate 4: Depositor earning intelligence, BTD/BTC compensation statements, organization policy, enterprise UX, scaled local/staging rehearsal, and V44 promotion readiness. +- Current working gate: V44 Gate 5 Depositor Earnings, ROI, And Supply Opportunity Intelligence. +- Next queued work after V44 Gate 5: BTD/BTC compensation statements, organization policy, enterprise UX, scaled local/staging rehearsal, and V44 promotion readiness. - Latest closed version: V43 Route Product Cleanup, which promoted `/packs`, `/read`, and `/deposit`; PackActivity master-detail; five-step Reading route UX; deposit AssetPack option synthesis; deposit criticality/ROI/compensation policy; option admission; product route UX; cross-route rehearsal; and V43 promotion readiness. - Recent V43 canonical promotion anchor: V43 canonical promotion updated `BITCODE_SPEC.txt` to `V43`, generated `BITCODE_SPEC_V43_PROVEN.md`, preserved active V43 / draft V44 runtime posture, and closed route-product cleanup canon. - V44 Gate 1 opening anchor: scaled engineering economy opens over promoted V43 with V44 SPEC, DELTA, NOTES, and PARITY files, `check:v44-gate1`, active V43 / draft V44 posture, and a ten-gate plan for economic domain models, Packs portfolio intelligence, Reading budget/quote governance, Depositor earnings/ROI intelligence, BTD/BTC compensation statements, organization policy/wallet authority, enterprise economic UX, scaled local/staging rehearsal, and promotion readiness. - V44 Gate 2 closure anchor: scaled engineering economy now owns package-backed `V44EconomicDomainModel`, deterministic `.bitcode/v44-economic-domain-model.json`, source-safe object contracts for EnterprisePackPortfolio, PackPortfolioPosition, PackMarketSignal, ReadDemandSignal, UnfitNeedSignal, DepositSupplyOpportunity, ReadingBudgetPolicy, AssetPackQuotePolicy, ProcurementApprovalReceipt, DepositorEarningStatement, ContributorCompensationStatement, PackEconomicStatement, OrganizationPackPolicy, PackGovernanceDecision, ScaledNetworkRehearsalReceipt, and PortfolioRepairCase, receipt taxonomy coverage for portfolio positions, market signals, quote states, settlement states, compensation statements, governance decisions, repair cases, budget policies, supply opportunities, and network rehearsals, distinct estimate/quote/observed payment/final settlement/contributor allocation/delivery/repair labels, source-safe forbidden payload checks, package exports, protocol tests, workflow wiring, and `check:v44-gate2`. - V44 Gate 3 closure anchor: scaled engineering economy now owns package-backed `V44PacksPortfolioMarketIntelligence`, deterministic `.bitcode/v44-packs-portfolio-market-intelligence.json`, `/api/packs/activity` `marketIntelligence` projection, source-safe `PackPortfolioPositionProjection`, `PackMarketSignalProjection`, saved filter presets, organization views, demand/supply/unfit-Need/settlement/compensation/delivery/repair signals, settlement/compensation/delivery/repair facets, `/packs` portfolio and market panels, proof-root drilldown continuity, no-source-leak tests, package exports, UAPI model tests, protocol tests, workflow wiring, and `check:v44-gate3`. - V44 Gate 4 closure anchor: scaled engineering economy now owns package-backed `V44ReadingBudgetQuotePolicy`, deterministic `.bitcode/v44-reading-budget-quote-policy.json`, `/read` `ReadProcurementGovernance`, source-safe Reading budget envelopes, approval thresholds, quote expiry, deterministic measurement-weight-volume share-to-fee policy, buyer authorization, wallet authority, BTC/BTD settlement readiness blockers, pre-purchase review boundaries, route UI readback, no-source-leak tests, package exports, UAPI route model tests, protocol tests, workflow wiring, and `check:v44-gate4`. +- V44 Gate 5 closure anchor: scaled engineering economy now owns package-backed `V44DepositorEarningsSupplyOpportunities`, deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json`, `DepositorEarningSupplyIntelligence`, source-safe likely demand, unfit Need opportunities, ROI posture, source criticality posture, estimate-only BTC compensation ranges, earning statements, source-to-shares proof boundaries, supply recommendations, `/deposit` route UI readback, package exports, pipeline/package/UAPI/protocol tests, workflow wiring, and `check:v44-gate5`. - Latest prior 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. diff --git a/package.json b/package.json index 91fd5a53..2f9e6b13 100644 --- a/package.json +++ b/package.json @@ -368,6 +368,9 @@ "generate:v44-reading-budget-quote-policy": "node scripts/generate-v44-reading-budget-quote-policy.mjs", "check:v44-reading-budget-quote-policy": "node scripts/generate-v44-reading-budget-quote-policy.mjs --check", "check:v44-gate4": "node scripts/check-v44-gate4-reading-budget-quote-policy.mjs", + "generate:v44-depositor-earnings-supply-opportunities": "node scripts/generate-v44-depositor-earnings-supply-opportunities.mjs", + "check:v44-depositor-earnings-supply-opportunities": "node scripts/generate-v44-depositor-earnings-supply-opportunities.mjs --check", + "check:v44-gate5": "node scripts/check-v44-gate5-depositor-earnings-supply-opportunities.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 1a20b60d..a86ea670 100644 --- a/packages/pipelines/asset-pack/package.json +++ b/packages/pipelines/asset-pack/package.json @@ -15,6 +15,7 @@ "./deposit-asset-pack-options": "./src/deposit-asset-pack-options.ts", "./deposit-asset-pack-option-policy": "./src/deposit-asset-pack-option-policy.ts", "./deposit-asset-pack-option-admission": "./src/deposit-asset-pack-option-admission.ts", + "./depositor-earning-supply-intelligence": "./src/depositor-earning-supply-intelligence.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__/depositor-earning-supply-intelligence.test.ts b/packages/pipelines/asset-pack/src/__tests__/depositor-earning-supply-intelligence.test.ts new file mode 100644 index 00000000..98067a41 --- /dev/null +++ b/packages/pipelines/asset-pack/src/__tests__/depositor-earning-supply-intelligence.test.ts @@ -0,0 +1,109 @@ +import { + assertDepositorEarningSupplyIntelligenceSourceSafe, + buildDepositorEarningSupplyIntelligence, +} from '../depositor-earning-supply-intelligence'; +import { buildDepositAssetPackOptionPolicyReport } from '../deposit-asset-pack-option-policy'; +import { buildDepositAssetPackOptionSynthesis } from '../deposit-asset-pack-options'; + +function reviewablePolicyReport() { + const synthesis = buildDepositAssetPackOptionSynthesis({ + repositoryFullName: 'engineeredsoftware/ENGI', + sourceBranch: 'main', + sourceCommit: '31bbc0c5227b6b3aed5d107fd8507d35ec22970a', + depositorInstructions: 'Prepare source-safe options likely to satisfy unfit Reading demand.', + sourcePathHints: [ + 'uapi/app/deposit/DepositPageClient.tsx', + 'packages/pipelines/asset-pack/src/depository-supply-index.ts', + ], + depositoryDemandSignals: [ + { id: 'portfolio-gap', label: 'Portfolio needs supply for common route operations.', weight: 0.82 }, + ], + readingDemandSignals: [ + { id: 'unfit-read-demand', label: 'Recent Reads need better source-safe deposit supply.', weight: 0.88 }, + ], + existingDepositorySignals: [ + { id: 'low-coverage-supply', label: 'Existing Depository coverage is thin for route proof work.', weight: 0.62 }, + ], + }); + + return buildDepositAssetPackOptionPolicyReport({ + synthesis, + sourceCriticalitySignals: [ + { + id: 'sub-critical-route-surface', + label: 'Route surface is sub-critical to expose after settlement.', + severity: 'sub-critical', + weight: 0.86, + }, + ], + depositorWalletId: 'wallet-depositor-1', + developmentCostSats: 1500, + expectedSettlementSats: 5600, + }); +} + +describe('Depositor earning supply intelligence', () => { + it('builds source-safe earning statements and supply recommendations', () => { + const intelligence = buildDepositorEarningSupplyIntelligence({ + policyReport: reviewablePolicyReport(), + unfitNeedOpportunitySignals: [ + { + id: 'unfit-need-route-proof', + label: 'Unfit Reads need route proof and source-safe delivery evidence.', + weight: 0.84, + }, + ], + }); + + expect(intelligence.schema).toBe('bitcode.deposit.earning-supply-intelligence'); + expect(intelligence.intelligence).toBe('DepositorEarningSupplyIntelligence'); + expect(intelligence.route).toBe('/deposit'); + expect(intelligence.likelyDemand.state).toBe('strong-demand-opportunity'); + expect(intelligence.unfitNeedOpportunities.opportunityCount).toBe(1); + expect(intelligence.earningStatements).toHaveLength(3); + expect(intelligence.earningStatements[0]).toMatchObject({ + schema: 'bitcode.deposit.depositor-earning-statement', + valueLabel: 'estimate', + expectedCompensationRangeSats: { + priceAsset: 'BTC', + rangeBasis: 'estimated-future-reader-settlement-share', + }, + sourceToShares: { + allocationMethod: 'source-to-shares-largest-remainder', + proofState: 'not-created-until-accepted-need-fit-and-settlement', + }, + }); + expect(intelligence.aggregate.eligibleEarningStatementCount).toBeGreaterThan(0); + expect(intelligence.aggregate.totalExpectedCompensationSats).toBeGreaterThan(0); + expect(intelligence.supplyRecommendations.length).toBe(3); + expect(intelligence.roots.intelligenceRoot).toMatch(/^deposit-earning-supply-intelligence:/u); + expect(assertDepositorEarningSupplyIntelligenceSourceSafe(intelligence)).toEqual({ + admitted: true, + reason: 'source_safe_depositor_earning_supply_intelligence', + }); + }); + + it('blocks critical source from earning readiness without leaking protected payloads', () => { + const synthesis = buildDepositAssetPackOptionSynthesis({ + repositoryFullName: 'engineeredsoftware/ENGI', + sourceBranch: 'main', + sourceCommit: '31bbc0c5227b6b3aed5d107fd8507d35ec22970a', + sourcePathHints: ['packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts'], + readingDemandSignals: [{ id: 'demand', label: 'Demand exists.', weight: 0.8 }], + }); + const policyReport = buildDepositAssetPackOptionPolicyReport({ + synthesis, + sourceCriticalitySignals: [{ id: 'critical', severity: 'critical', weight: 1 }], + developmentCostSats: 9200, + expectedSettlementSats: 1800, + depositorWalletId: null, + }); + const intelligence = buildDepositorEarningSupplyIntelligence({ policyReport }); + + expect(intelligence.aggregate.blockedCriticalSourceCount).toBe(3); + expect(intelligence.earningStatements.every((statement) => statement.state === 'blocked-critical-source')).toBe(true); + expect(intelligence.supplyRecommendations.every((recommendation) => recommendation.action === 'withhold-critical-source')).toBe(true); + expect(assertDepositorEarningSupplyIntelligenceSourceSafe(intelligence).admitted).toBe(true); + expect(JSON.stringify(intelligence)).not.toContain('PRIVATE_SOURCE_DO_NOT_SERIALIZE'); + }); +}); diff --git a/packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts b/packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts new file mode 100644 index 00000000..601c7236 --- /dev/null +++ b/packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts @@ -0,0 +1,478 @@ +import type { + DepositAssetPackOptionPolicyEvaluation, + DepositAssetPackOptionPolicyReport, +} from './deposit-asset-pack-option-policy'; +import type { DepositOptionDemandSignal } from './deposit-asset-pack-options'; + +export type DepositorDemandOpportunityState = + | 'strong-demand-opportunity' + | 'moderate-demand-opportunity' + | 'weak-demand-opportunity'; + +export type DepositorEarningRangeState = + | 'compensation-range-estimated' + | 'repair-required-before-earning' + | 'blocked-critical-source'; + +export type DepositorSupplyRecommendationAction = + | 'approve-for-depository-review' + | 'repair-policy-before-admission' + | 'resynthesize-for-demand' + | 'withhold-critical-source'; + +export interface DepositorEarningSupplyIntelligenceInput { + policyReport: DepositAssetPackOptionPolicyReport; + unfitNeedOpportunitySignals?: DepositOptionDemandSignal[] | null; + createdAt?: string | null; +} + +export interface DepositorUnfitNeedOpportunity { + id: string; + label: string; + weight: number; + state: DepositorDemandOpportunityState; + opportunityRoot: string; +} + +export interface DepositorEarningStatement { + schema: 'bitcode.deposit.depositor-earning-statement'; + optionId: string; + title: string; + valueLabel: 'estimate'; + state: DepositorEarningRangeState; + demandState: DepositAssetPackOptionPolicyEvaluation['demand']['state']; + sourceCriticalityState: DepositAssetPackOptionPolicyEvaluation['sourceCriticality']['state']; + roiState: DepositAssetPackOptionPolicyEvaluation['roi']['state']; + expectedCompensationRangeSats: { + low: number; + expected: number; + high: number; + priceAsset: 'BTC'; + rangeBasis: 'estimated-future-reader-settlement-share'; + }; + expectedNetRangeSats: { + low: number; + expected: number; + high: number; + }; + sourceToShares: { + allocationMethod: 'source-to-shares-largest-remainder'; + depositorShareBasisPoints: number; + proofState: 'not-created-until-accepted-need-fit-and-settlement'; + }; + blockers: string[]; + warnings: string[]; + statementRoot: string; +} + +export interface DepositorSupplyRecommendation { + optionId: string; + title: string; + action: DepositorSupplyRecommendationAction; + reasons: string[]; + recommendationRoot: string; +} + +export interface DepositorEarningSupplyIntelligence { + schema: 'bitcode.deposit.earning-supply-intelligence'; + intelligence: 'DepositorEarningSupplyIntelligence'; + createdAt: string; + route: '/deposit'; + synthesisRequestId: string; + optionCount: number; + likelyDemand: { + state: DepositorDemandOpportunityState; + averageConfidence: number; + strongestOptionId: string | null; + strongDemandOptionCount: number; + demandRoot: string; + }; + unfitNeedOpportunities: { + state: DepositorDemandOpportunityState; + opportunityCount: number; + opportunities: DepositorUnfitNeedOpportunity[]; + opportunityRoot: string; + }; + earningStatements: DepositorEarningStatement[]; + supplyRecommendations: DepositorSupplyRecommendation[]; + aggregate: { + valueLabel: 'estimate'; + eligibleEarningStatementCount: number; + blockedCriticalSourceCount: number; + repairRequiredCount: number; + totalExpectedCompensationSats: number; + expectedCompensationRangeSats: { + low: number; + expected: number; + high: number; + priceAsset: 'BTC'; + }; + sourceSafeSupplyRecommendationCount: number; + unfitNeedOpportunityCount: number; + aggregateRoot: string; + }; + disclosure: { + sourceSafeMetadataOnly: true; + protectedSourceVisible: false; + rawSourceTextVisible: false; + unpaidAssetPackSourceVisible: false; + rawPromptVisible: false; + interpolatedPromptVisible: false; + rawProviderResponseVisible: false; + walletPrivateMaterialVisible: false; + settlementPrivatePayloadVisible: false; + valueBearingMainnetAdmitted: false; + }; + roots: { + intelligenceRoot: string; + policyReportRoot: string; + likelyDemandRoot: string; + unfitNeedOpportunityRoot: string; + earningStatementRoots: string[]; + supplyRecommendationRoots: string[]; + aggregateRoot: string; + }; +} + +const FORBIDDEN_SOURCE_MARKERS = [ + 'PRIVATE_SOURCE_DO_NOT_SERIALIZE', + `BEGIN_${'PRIVATE'}_KEY`, + 'wallet_private_material', + 'raw_provider_response', + 'unpaid_assetpack_source', + 'protected_source_payload', + 'value_bearing_mainnet', +]; + +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 opportunityStateFor(weight: number): DepositorDemandOpportunityState { + if (weight >= 0.76) return 'strong-demand-opportunity'; + if (weight >= 0.56) return 'moderate-demand-opportunity'; + return 'weak-demand-opportunity'; +} + +function normalizedOpportunitySignals(value: DepositOptionDemandSignal[] | null | undefined) { + return (value || []) + .map((signal, index) => { + const weight = boundedUnit(signal.weight, 0.5); + const label = + normalizedText(signal.label) || + normalizedText(signal.summary) || + `Unfit Need opportunity ${index + 1}`; + const id = normalizedText(signal.id) || `unfit-need-opportunity-${index + 1}`; + return { + id, + label, + weight, + state: opportunityStateFor(weight), + opportunityRoot: root('deposit-unfit-need-opportunity', { id, label, weight }), + }; + }) + .sort((left, right) => left.id.localeCompare(right.id)); +} + +function statementStateFor( + evaluation: DepositAssetPackOptionPolicyEvaluation, +): DepositorEarningRangeState { + if (evaluation.sourceCriticality.state === 'blocked-critical-source') return 'blocked-critical-source'; + if (!evaluation.compensation.eligibleIfApprovedAndSelected) return 'repair-required-before-earning'; + return 'compensation-range-estimated'; +} + +function compensationRangeFor(evaluation: DepositAssetPackOptionPolicyEvaluation) { + const expected = Math.max( + 0, + Math.round( + (evaluation.roi.estimatedGrossSats * evaluation.compensation.depositorShareBasisPoints) / 10_000, + ), + ); + return { + low: Math.round(expected * 0.7), + expected, + high: Math.round(expected * 1.3), + priceAsset: 'BTC' as const, + rangeBasis: 'estimated-future-reader-settlement-share' as const, + }; +} + +function netRangeFor( + range: DepositorEarningStatement['expectedCompensationRangeSats'], + evaluation: DepositAssetPackOptionPolicyEvaluation, +) { + const developmentCost = evaluation.roi.estimatedDevelopmentCostSats; + return { + low: range.low - developmentCost, + expected: range.expected - developmentCost, + high: range.high - developmentCost, + }; +} + +function recommendationFor(evaluation: DepositAssetPackOptionPolicyEvaluation): DepositorSupplyRecommendation { + const action: DepositorSupplyRecommendationAction = + evaluation.sourceCriticality.state === 'blocked-critical-source' + ? 'withhold-critical-source' + : !evaluation.compensation.eligibleIfApprovedAndSelected + ? 'repair-policy-before-admission' + : evaluation.demand.state === 'weak-likely-demand' || evaluation.roi.state !== 'positive-expected-value' + ? 'resynthesize-for-demand' + : 'approve-for-depository-review'; + const reasons = [ + evaluation.sourceCriticality.state, + evaluation.demand.state, + evaluation.roi.state, + evaluation.compensation.state, + ]; + return { + optionId: evaluation.optionId, + title: evaluation.title, + action, + reasons, + recommendationRoot: root('deposit-supply-recommendation', { + optionId: evaluation.optionId, + action, + reasons, + }), + }; +} + +export function buildDepositorEarningSupplyIntelligence( + input: DepositorEarningSupplyIntelligenceInput, +): DepositorEarningSupplyIntelligence { + const createdAt = normalizedText(input.createdAt) || input.policyReport.createdAt || 'deterministic'; + const opportunities = normalizedOpportunitySignals(input.unfitNeedOpportunitySignals); + const optionDemandAverage = input.policyReport.evaluations.length + ? Number( + ( + input.policyReport.evaluations.reduce( + (sum, evaluation) => sum + evaluation.demand.weightedDemand, + 0, + ) / input.policyReport.evaluations.length + ).toFixed(2), + ) + : 0; + const strongestEvaluation = [...input.policyReport.evaluations].sort( + (left, right) => right.demand.weightedDemand - left.demand.weightedDemand, + )[0]; + const likelyDemandState = opportunityStateFor(optionDemandAverage); + const opportunitiesAverage = opportunities.length + ? opportunities.reduce((sum, opportunity) => sum + opportunity.weight, 0) / opportunities.length + : optionDemandAverage; + const unfitNeedState = opportunityStateFor(Number(opportunitiesAverage.toFixed(2))); + + const earningStatements = input.policyReport.evaluations.map((evaluation) => { + const expectedCompensationRangeSats = compensationRangeFor(evaluation); + const expectedNetRangeSats = netRangeFor(expectedCompensationRangeSats, evaluation); + const state = statementStateFor(evaluation); + const blockers = [...new Set(evaluation.compensation.blockers)].sort(); + const warnings = [...new Set(evaluation.compensation.warnings)].sort(); + const statementSeed = { + optionId: evaluation.optionId, + state, + demandState: evaluation.demand.state, + sourceCriticalityState: evaluation.sourceCriticality.state, + roiState: evaluation.roi.state, + expectedCompensationRangeSats, + expectedNetRangeSats, + blockers, + warnings, + }; + return { + schema: 'bitcode.deposit.depositor-earning-statement' as const, + optionId: evaluation.optionId, + title: evaluation.title, + valueLabel: 'estimate' as const, + state, + demandState: evaluation.demand.state, + sourceCriticalityState: evaluation.sourceCriticality.state, + roiState: evaluation.roi.state, + expectedCompensationRangeSats, + expectedNetRangeSats, + sourceToShares: { + allocationMethod: evaluation.compensation.allocationMethod, + depositorShareBasisPoints: evaluation.compensation.depositorShareBasisPoints, + proofState: evaluation.compensation.sourceToSharesProofState, + }, + blockers, + warnings, + statementRoot: root('deposit-earning-statement', statementSeed), + }; + }); + + const supplyRecommendations = input.policyReport.evaluations.map(recommendationFor); + const eligibleStatements = earningStatements.filter( + (statement) => statement.state === 'compensation-range-estimated', + ); + const totalExpectedCompensationSats = eligibleStatements.reduce( + (sum, statement) => sum + statement.expectedCompensationRangeSats.expected, + 0, + ); + const range = { + low: eligibleStatements.reduce((sum, statement) => sum + statement.expectedCompensationRangeSats.low, 0), + expected: totalExpectedCompensationSats, + high: eligibleStatements.reduce((sum, statement) => sum + statement.expectedCompensationRangeSats.high, 0), + priceAsset: 'BTC' as const, + }; + const likelyDemandRoot = root('deposit-likely-demand', { + likelyDemandState, + optionDemandAverage, + strongestOptionId: strongestEvaluation?.optionId || null, + }); + const unfitNeedOpportunityRoot = root('deposit-unfit-need-opportunities', opportunities); + const aggregateRoot = root('deposit-earning-supply-aggregate', { + totalExpectedCompensationSats, + eligibleCount: eligibleStatements.length, + range, + recommendationRoots: supplyRecommendations.map((entry) => entry.recommendationRoot), + opportunityRoots: opportunities.map((entry) => entry.opportunityRoot), + }); + const earningStatementRoots = earningStatements.map((statement) => statement.statementRoot); + const supplyRecommendationRoots = supplyRecommendations.map( + (recommendation) => recommendation.recommendationRoot, + ); + const intelligenceRoot = root('deposit-earning-supply-intelligence', { + policyReportRoot: input.policyReport.roots.policyReportRoot, + likelyDemandRoot, + unfitNeedOpportunityRoot, + earningStatementRoots, + supplyRecommendationRoots, + aggregateRoot, + }); + + return { + schema: 'bitcode.deposit.earning-supply-intelligence', + intelligence: 'DepositorEarningSupplyIntelligence', + createdAt, + route: '/deposit', + synthesisRequestId: input.policyReport.synthesisRequestId, + optionCount: input.policyReport.optionCount, + likelyDemand: { + state: likelyDemandState, + averageConfidence: optionDemandAverage, + strongestOptionId: strongestEvaluation?.optionId || null, + strongDemandOptionCount: input.policyReport.evaluations.filter( + (evaluation) => evaluation.demand.state === 'strong-likely-demand', + ).length, + demandRoot: likelyDemandRoot, + }, + unfitNeedOpportunities: { + state: unfitNeedState, + opportunityCount: opportunities.length, + opportunities, + opportunityRoot: unfitNeedOpportunityRoot, + }, + earningStatements, + supplyRecommendations, + aggregate: { + valueLabel: 'estimate', + eligibleEarningStatementCount: eligibleStatements.length, + blockedCriticalSourceCount: earningStatements.filter( + (statement) => statement.state === 'blocked-critical-source', + ).length, + repairRequiredCount: earningStatements.filter( + (statement) => statement.state === 'repair-required-before-earning', + ).length, + totalExpectedCompensationSats, + expectedCompensationRangeSats: range, + sourceSafeSupplyRecommendationCount: supplyRecommendations.filter( + (recommendation) => recommendation.action === 'approve-for-depository-review', + ).length, + unfitNeedOpportunityCount: opportunities.length, + aggregateRoot, + }, + disclosure: { + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawSourceTextVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + valueBearingMainnetAdmitted: false, + }, + roots: { + intelligenceRoot, + policyReportRoot: input.policyReport.roots.policyReportRoot, + likelyDemandRoot, + unfitNeedOpportunityRoot, + earningStatementRoots, + supplyRecommendationRoots, + aggregateRoot, + }, + }; +} + +export function assertDepositorEarningSupplyIntelligenceSourceSafe( + intelligence: DepositorEarningSupplyIntelligence, +) { + const serialized = stableStringify(intelligence); + const noForbiddenMarkers = FORBIDDEN_SOURCE_MARKERS.every((marker) => !serialized.includes(marker)); + const sourceSafe = + noForbiddenMarkers && + intelligence.schema === 'bitcode.deposit.earning-supply-intelligence' && + intelligence.intelligence === 'DepositorEarningSupplyIntelligence' && + intelligence.route === '/deposit' && + intelligence.aggregate.valueLabel === 'estimate' && + intelligence.earningStatements.every( + (statement) => + statement.schema === 'bitcode.deposit.depositor-earning-statement' && + statement.valueLabel === 'estimate' && + statement.expectedCompensationRangeSats.priceAsset === 'BTC' && + statement.expectedCompensationRangeSats.rangeBasis === + 'estimated-future-reader-settlement-share' && + statement.sourceToShares.allocationMethod === 'source-to-shares-largest-remainder' && + statement.sourceToShares.proofState === + 'not-created-until-accepted-need-fit-and-settlement', + ) && + intelligence.disclosure.sourceSafeMetadataOnly === true && + intelligence.disclosure.protectedSourceVisible === false && + intelligence.disclosure.rawSourceTextVisible === false && + intelligence.disclosure.unpaidAssetPackSourceVisible === false && + intelligence.disclosure.rawPromptVisible === false && + intelligence.disclosure.interpolatedPromptVisible === false && + intelligence.disclosure.rawProviderResponseVisible === false && + intelligence.disclosure.walletPrivateMaterialVisible === false && + intelligence.disclosure.settlementPrivatePayloadVisible === false && + intelligence.disclosure.valueBearingMainnetAdmitted === false; + + return { + admitted: sourceSafe, + reason: sourceSafe + ? 'source_safe_depositor_earning_supply_intelligence' + : 'depositor_earning_supply_intelligence_source_safety_boundary_violation', + }; +} diff --git a/packages/pipelines/asset-pack/src/index.ts b/packages/pipelines/asset-pack/src/index.ts index 2803567e..f031cdcb 100644 --- a/packages/pipelines/asset-pack/src/index.ts +++ b/packages/pipelines/asset-pack/src/index.ts @@ -54,6 +54,8 @@ import { synthesizeReadNeedForPipelineInput, } from './read-need'; +export * from './depositor-earning-supply-intelligence'; + // ==================== FACTORIES ==================== function storePreprocessedSnapshot( @@ -411,7 +413,7 @@ function factoryDevelopPhase(): Executor { /** * Main AssetPack written-asset synthesis pipeline with guided gate execution. - * Routes execution through Design → Develop → Digest gates + * Routes execution through Design -> Develop -> Digest gates */ export const assetPackPipeline: Executor = createGuidedPipelineExecution({ Design: async (input, execution) => { diff --git a/packages/protocol/README.md b/packages/protocol/README.md index 9b3f3466..154fa41e 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -219,6 +219,18 @@ share-to-fee policy, buyer authorization, wallet authority, BTC/BTD settlement readiness blockers, pre-purchase review boundaries, route UI readback, BTD fee/source-to-shares prerequisites, and source-safety tests. +V44 Gate 5 adds `V44DepositorEarningsSupplyOpportunities` through +`packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js`, +`packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js`, +`.bitcode/v44-depositor-earnings-supply-opportunities.json`, +`generate:v44-depositor-earnings-supply-opportunities`, +`check:v44-depositor-earnings-supply-opportunities`, and `check:v44-gate5`. +It binds `/deposit` to source-safe Depositor earning supply intelligence: +likely demand, unfit Need opportunities, source criticality, ROI posture, +estimate-only BTC compensation ranges, source-to-shares proof boundaries, +earning statements, supply recommendations, route UI readback, and +source-safety tests. + 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/v44-depositor-earnings-supply-opportunities.js b/packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js new file mode 100644 index 00000000..232355f0 --- /dev/null +++ b/packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js @@ -0,0 +1,273 @@ +// @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 V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH = + '.bitcode/v44-depositor-earnings-supply-opportunities.json'; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SCHEMA_ID = + 'bitcode.v44.depositorEarningsSupplyOpportunities.v1'; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_VERSION = 'V44'; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_CURRENT_TARGET = 'V43'; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SOURCE_SAFETY_VERDICT = + 'source-safe-depositor-earnings-supply-opportunity-metadata'; + +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OBJECT_IDS = Object.freeze([ + 'DepositorEarningSupplyIntelligence', + 'DepositorEarningStatement', + 'DepositSupplyOpportunity', + 'UnfitNeedOpportunity', + 'SourceCriticalityPosture', + 'ExpectedCompensationRange', + 'SourceSafeSupplyRecommendation', +]); + +export const V44_DEPOSITOR_EARNING_STATE_IDS = Object.freeze([ + 'compensation-range-estimated', + 'repair-required-before-earning', + 'blocked-critical-source', +]); + +export const V44_DEPOSITOR_SUPPLY_RECOMMENDATION_IDS = Object.freeze([ + 'approve-for-depository-review', + 'repair-policy-before-admission', + 'resynthesize-for-demand', + 'withhold-critical-source', +]); + +export const V44_DEPOSITOR_DEMAND_OPPORTUNITY_STATE_IDS = Object.freeze([ + 'strong-demand-opportunity', + 'moderate-demand-opportunity', + 'weak-demand-opportunity', +]); + +export const V44_DEPOSITOR_EARNINGS_SUPPLY_FORBIDDEN_PAYLOAD_IDS = Object.freeze([ + 'protected-source-payloads', + 'raw-source-text', + 'unpaid-assetpack-source', + 'raw-prompts', + 'interpolated-prompts', + 'raw-provider-responses', + 'credentials', + 'wallet-private-material', + 'private-settlement-payloads', + 'value-bearing-mainnet-admission', +]); + +const SOURCE_ROOTS = Object.freeze({ + activePointer: 'BITCODE_SPEC.txt', + spec: 'BITCODE_SPEC_V44.md', + delta: 'BITCODE_SPEC_V44_DELTA.md', + notes: 'BITCODE_SPEC_V44_NOTES.md', + parity: 'BITCODE_SPEC_V44_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', + economicModel: 'packages/protocol/src/canonical/v44-economic-domain-model.js', + portfolioMarketIntelligence: 'packages/protocol/src/canonical/v44-packs-portfolio-market-intelligence.js', + optionPolicy: 'packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts', + earningSupplyIntelligence: 'packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts', + earningSupplyIntelligenceTest: 'packages/pipelines/asset-pack/src/__tests__/depositor-earning-supply-intelligence.test.ts', + depositModel: 'uapi/app/deposit/deposit-route-model.ts', + depositClient: 'uapi/app/deposit/DepositPageClient.tsx', + depositRouteTest: 'uapi/tests/depositRouteModel.test.ts', + depositPageTest: 'uapi/tests/depositPageClient.test.tsx', + assetPackPackageIndex: 'packages/pipelines/asset-pack/src/index.ts', + assetPackPackageManifest: 'packages/pipelines/asset-pack/package.json', + sourceToShares: 'packages/btd/src/source-to-shares.ts', + packageIndex: 'packages/protocol/src/index.js', + packageTypes: 'packages/protocol/src/index.d.ts', + packageSource: 'packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js', + packageTest: 'packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js', + generator: 'scripts/generate-v44-depositor-earnings-supply-opportunities.mjs', + checker: 'scripts/check-v44-gate5-depositor-earnings-supply-opportunities.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) }; +} + +function sourceRoot(sourcePath) { + return `${sourcePath}:${digest(readSource(DEFAULT_REPO_ROOT, sourcePath))}`; +} + +export const V44_DEPOSITOR_EARNINGS_SUPPLY_ROWS = Object.freeze([ + { + rowId: 'likely-demand-intelligence', + owner: SOURCE_ROOTS.earningSupplyIntelligence, + contract: + 'DepositorEarningSupplyIntelligence aggregates likely Reading demand from source-safe option policy evaluations.', + requiredFields: ['likelyDemand', 'averageConfidence', 'strongDemandOptionCount', 'demandRoot'], + }, + { + rowId: 'unfit-need-opportunities', + owner: SOURCE_ROOTS.earningSupplyIntelligence, + contract: + 'Unfit Need opportunities are represented as source-safe weighted demand signals that guide supply creation without exposing Read or source payloads.', + requiredFields: ['unfitNeedOpportunities', 'opportunityCount', 'opportunityRoot'], + }, + { + rowId: 'earning-statements', + owner: SOURCE_ROOTS.earningSupplyIntelligence, + contract: + 'Depositor earning statements label all values as estimates and expose BTC compensation ranges, ROI, criticality, blockers, warnings, and statement roots.', + requiredFields: ['DepositorEarningStatement', 'valueLabel', 'expectedCompensationRangeSats', 'blocked-critical-source'], + }, + { + rowId: 'source-safe-supply-recommendations', + owner: SOURCE_ROOTS.earningSupplyIntelligence, + contract: + 'Supply recommendations choose approve, repair, resynthesize, or withhold actions from source-safe demand, criticality, ROI, and compensation posture.', + requiredFields: ['approve-for-depository-review', 'repair-policy-before-admission', 'resynthesize-for-demand', 'withhold-critical-source'], + }, + { + rowId: 'deposit-route-earning-readback', + owner: SOURCE_ROOTS.depositClient, + contract: + '/deposit renders earning estimates, unfit Need opportunities, source-safe recommendations, and opportunity roots beside the five-step Depositing path.', + requiredFields: ['Supply opportunity', 'Earning estimate', 'Unfit Need opportunities', 'DepositorEarningSupplyIntelligence'], + }, + { + rowId: 'source-to-shares-compensation-basis', + owner: SOURCE_ROOTS.sourceToShares, + contract: + 'Depositor earning ranges remain estimate-only until future Need-Fit settlement produces source-to-shares allocation receipts.', + requiredFields: ['source-to-shares-largest-remainder', 'settlementAllocations', 'settlementConservation'], + }, +]); + +function buildPredicateResults(repoRoot) { + const sources = Object.fromEntries( + Object.entries(SOURCE_ROOTS).map(([key, sourcePath]) => [key, readSource(repoRoot, sourcePath)]), + ); + + return [ + predicateResult('active-canon-pointer-remains-v43', SOURCE_ROOTS.activePointer, sources.activePointer.trim() === 'V43'), + predicateResult('spec-defines-gate5', SOURCE_ROOTS.spec, sources.spec.includes('V44 Gate 5 Depositor Earnings, ROI, And Supply Opportunity Intelligence')), + predicateResult('spec-names-gate5-artifact', SOURCE_ROOTS.spec, sources.spec.includes('v44-depositor-earnings-supply-opportunities')), + predicateResult('delta-records-gate5', SOURCE_ROOTS.delta, sources.delta.includes('Gate 5') && sources.delta.includes('v44-depositor-earnings-supply-opportunities')), + predicateResult('notes-records-gate5', SOURCE_ROOTS.notes, sources.notes.includes('Gate 5') && sources.notes.includes('earning')), + predicateResult('parity-records-gate5', SOURCE_ROOTS.parity, sources.parity.includes('v44-depositor-earnings-supply-opportunities')), + predicateResult('roadmap-records-gate5', SOURCE_ROOTS.roadmap, sources.roadmap.includes('V44 Gate 5 closure anchor')), + predicateResult('readme-records-gate5', SOURCE_ROOTS.readme, sources.readme.includes('V44 Gate 5')), + predicateResult('protocol-readme-records-gate5', SOURCE_ROOTS.protocolReadme, sources.protocolReadme.includes('V44 Gate 5')), + predicateResult('economic-model-prerequisite-present', SOURCE_ROOTS.economicModel, sources.economicModel.includes('DepositorEarningStatement') && sources.economicModel.includes('DepositSupplyOpportunity')), + predicateResult('portfolio-market-prerequisite-present', SOURCE_ROOTS.portfolioMarketIntelligence, sources.portfolioMarketIntelligence.includes('supply') && sources.portfolioMarketIntelligence.includes('compensation')), + predicateResult('option-policy-prerequisite-present', SOURCE_ROOTS.optionPolicy, sources.optionPolicy.includes('DepositAssetPackOptionPolicyReport') && sources.optionPolicy.includes('future-reader-btc-source-to-shares-route-preview')), + predicateResult('earning-intelligence-defines-builder', SOURCE_ROOTS.earningSupplyIntelligence, sources.earningSupplyIntelligence.includes('buildDepositorEarningSupplyIntelligence') && sources.earningSupplyIntelligence.includes('DepositorEarningSupplyIntelligence')), + predicateResult('earning-intelligence-defines-demand', SOURCE_ROOTS.earningSupplyIntelligence, V44_DEPOSITOR_DEMAND_OPPORTUNITY_STATE_IDS.every((id) => sources.earningSupplyIntelligence.includes(id))), + predicateResult('earning-intelligence-defines-statements', SOURCE_ROOTS.earningSupplyIntelligence, V44_DEPOSITOR_EARNING_STATE_IDS.every((id) => sources.earningSupplyIntelligence.includes(id))), + predicateResult('earning-intelligence-defines-recommendations', SOURCE_ROOTS.earningSupplyIntelligence, V44_DEPOSITOR_SUPPLY_RECOMMENDATION_IDS.every((id) => sources.earningSupplyIntelligence.includes(id))), + predicateResult('earning-intelligence-forbids-source-leakage', SOURCE_ROOTS.earningSupplyIntelligence, sources.earningSupplyIntelligence.includes('protectedSourceVisible: false') && sources.earningSupplyIntelligence.includes('valueBearingMainnetAdmitted: false')), + predicateResult('asset-pack-package-exports-intelligence', SOURCE_ROOTS.assetPackPackageIndex, sources.assetPackPackageIndex.includes("export * from './depositor-earning-supply-intelligence'")), + predicateResult('asset-pack-manifest-exports-intelligence', SOURCE_ROOTS.assetPackPackageManifest, sources.assetPackPackageManifest.includes('"./depositor-earning-supply-intelligence"')), + predicateResult('deposit-model-uses-intelligence', SOURCE_ROOTS.depositModel, sources.depositModel.includes('earningSupplyIntelligence') && sources.depositModel.includes('buildDepositorEarningSupplyIntelligence')), + predicateResult('deposit-client-renders-earnings', SOURCE_ROOTS.depositClient, sources.depositClient.includes('Supply opportunity') && sources.depositClient.includes('Earning estimate')), + predicateResult('earning-test-covers-intelligence', SOURCE_ROOTS.earningSupplyIntelligenceTest, sources.earningSupplyIntelligenceTest.includes('buildDepositorEarningSupplyIntelligence') && sources.earningSupplyIntelligenceTest.includes('blocked-critical-source')), + predicateResult('route-test-covers-intelligence', SOURCE_ROOTS.depositRouteTest, sources.depositRouteTest.includes('earningSupplyIntelligence') && sources.depositRouteTest.includes('unfit Need')), + predicateResult('page-test-covers-intelligence', SOURCE_ROOTS.depositPageTest, sources.depositPageTest.includes('Supply opportunity') && sources.depositPageTest.includes('DepositorEarningSupplyIntelligence')), + predicateResult('source-to-shares-prerequisite-present', SOURCE_ROOTS.sourceToShares, sources.sourceToShares.includes('settlementConservation') && sources.sourceToShares.includes('largest_remainder')), + predicateResult('package-test-covers-gate5', SOURCE_ROOTS.packageTest, sources.packageTest.includes('buildV44DepositorEarningsSupplyOpportunities')), + predicateResult('package-exports-gate5', SOURCE_ROOTS.packageIndex, sources.packageIndex.includes('buildV44DepositorEarningsSupplyOpportunities')), + predicateResult('package-types-export-gate5', SOURCE_ROOTS.packageTypes, sources.packageTypes.includes('buildV44DepositorEarningsSupplyOpportunities')), + predicateResult('package-json-exposes-gate5', SOURCE_ROOTS.packageJson, sources.packageJson.includes('"generate:v44-depositor-earnings-supply-opportunities"') && sources.packageJson.includes('"check:v44-gate5"')), + predicateResult('gate-workflow-runs-gate5', SOURCE_ROOTS.gateWorkflow, sources.gateWorkflow.includes('check-v44-gate5-depositor-earnings-supply-opportunities.mjs')), + predicateResult('canon-workflow-runs-gate5', SOURCE_ROOTS.canonWorkflow, sources.canonWorkflow.includes('check-v44-gate5-depositor-earnings-supply-opportunities.mjs')), + predicateResult('generator-exists', SOURCE_ROOTS.generator, sources.generator.includes('buildV44DepositorEarningsSupplyOpportunities')), + predicateResult('checker-exists', SOURCE_ROOTS.checker, sources.checker.includes('V44 Gate 5 Depositor earnings supply opportunities check')), + ]; +} + +export function buildV44DepositorEarningsSupplyOpportunities(options = {}) { + const repoRoot = options.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 = `v44-depositor-earnings-supply-opportunities:${digest(JSON.stringify({ + objectIds: V44_DEPOSITOR_EARNINGS_SUPPLY_OBJECT_IDS, + earningStateIds: V44_DEPOSITOR_EARNING_STATE_IDS, + recommendationIds: V44_DEPOSITOR_SUPPLY_RECOMMENDATION_IDS, + demandOpportunityStateIds: V44_DEPOSITOR_DEMAND_OPPORTUNITY_STATE_IDS, + rowIds: V44_DEPOSITOR_EARNINGS_SUPPLY_ROWS.map((row) => row.rowId), + sourceRoots, + failedPredicateIds, + }))}`; + + return { + artifactId: 'v44-depositor-earnings-supply-opportunities', + schemaId: V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SCHEMA_ID, + version: V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_VERSION, + currentTarget: V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_CURRENT_TARGET, + sourceSafetyVerdict: V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SOURCE_SAFETY_VERDICT, + generatedAt: 'deterministic', + artifactRoot, + passed: failedPredicateIds.length === 0, + objectIds: [...V44_DEPOSITOR_EARNINGS_SUPPLY_OBJECT_IDS], + earningStateIds: [...V44_DEPOSITOR_EARNING_STATE_IDS], + recommendationIds: [...V44_DEPOSITOR_SUPPLY_RECOMMENDATION_IDS], + demandOpportunityStateIds: [...V44_DEPOSITOR_DEMAND_OPPORTUNITY_STATE_IDS], + forbiddenPayloadIds: [...V44_DEPOSITOR_EARNINGS_SUPPLY_FORBIDDEN_PAYLOAD_IDS], + rows: V44_DEPOSITOR_EARNINGS_SUPPLY_ROWS.map((row) => ({ + ...row, + rowRoot: `v44-depositor-earning-supply-row:${digest(row.rowId)}`, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + unpaidAssetPackSourceVisible: false, + })), + sourceRoots, + predicateResults, + coverage: { + depositorEarningSupplyIntelligenceImplemented: true, + likelyDemandImplemented: true, + unfitNeedOpportunitiesImplemented: true, + roiPostureImplemented: true, + sourceCriticalityPostureImplemented: true, + expectedCompensationRangesImplemented: true, + earningStatementsImplemented: true, + sourceSafeSupplyRecommendationsImplemented: true, + depositRouteUiImplemented: true, + sourceToSharesEstimateBoundaryImplemented: true, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawSourceTextVisible: false, + sourceSnippetVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + unpaidAssetPackSourceVisible: false, + credentialsSerialized: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + valueBearingMainnetAdmitted: false, + requiredPredicateCount: predicateResults.length, + passedPredicateCount: predicateResults.length - failedPredicateIds.length, + failedPredicateIds, + }, + }; +} + +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SOURCE_ROOTS = Object.freeze( + Object.fromEntries(Object.entries(SOURCE_ROOTS).map(([key, sourcePath]) => [key, sourceRoot(sourcePath)])), +); diff --git a/packages/protocol/src/index.d.ts b/packages/protocol/src/index.d.ts index 0ed58769..710c11a8 100644 --- a/packages/protocol/src/index.d.ts +++ b/packages/protocol/src/index.d.ts @@ -720,6 +720,19 @@ export const V44_READING_SETTLEMENT_READINESS_IDS: readonly string[]; export const V44_READING_BUDGET_QUOTE_FORBIDDEN_PAYLOAD_IDS: readonly string[]; export const V44_READING_BUDGET_QUOTE_POLICY_ROWS: readonly Record[]; export function buildV44ReadingBudgetQuotePolicy(input?: Record): BitcodeProtocolReport; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH: string; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_CURRENT_TARGET: string; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SCHEMA_ID: string; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_VERSION: string; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SOURCE_SAFETY_VERDICT: string; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SOURCE_ROOTS: Readonly>; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_OBJECT_IDS: readonly string[]; +export const V44_DEPOSITOR_EARNING_STATE_IDS: readonly string[]; +export const V44_DEPOSITOR_SUPPLY_RECOMMENDATION_IDS: readonly string[]; +export const V44_DEPOSITOR_DEMAND_OPPORTUNITY_STATE_IDS: readonly string[]; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_FORBIDDEN_PAYLOAD_IDS: readonly string[]; +export const V44_DEPOSITOR_EARNINGS_SUPPLY_ROWS: readonly Record[]; +export function buildV44DepositorEarningsSupplyOpportunities(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 0fe5e243..3a504193 100644 --- a/packages/protocol/src/index.js +++ b/packages/protocol/src/index.js @@ -818,6 +818,21 @@ export { V44_READING_SETTLEMENT_READINESS_IDS, buildV44ReadingBudgetQuotePolicy } from './canonical/v44-reading-budget-quote-policy.js'; +export { + V44_DEPOSITOR_DEMAND_OPPORTUNITY_STATE_IDS, + V44_DEPOSITOR_EARNINGS_SUPPLY_FORBIDDEN_PAYLOAD_IDS, + V44_DEPOSITOR_EARNINGS_SUPPLY_OBJECT_IDS, + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH, + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_CURRENT_TARGET, + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SCHEMA_ID, + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SOURCE_ROOTS, + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_SOURCE_SAFETY_VERDICT, + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_VERSION, + V44_DEPOSITOR_EARNINGS_SUPPLY_ROWS, + V44_DEPOSITOR_EARNING_STATE_IDS, + V44_DEPOSITOR_SUPPLY_RECOMMENDATION_IDS, + buildV44DepositorEarningsSupplyOpportunities +} from './canonical/v44-depositor-earnings-supply-opportunities.js'; export { EXCHANGE_INTENT_ACTION_KINDS, EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH, diff --git a/packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js b/packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js new file mode 100644 index 00000000..fb9a3dc6 --- /dev/null +++ b/packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js @@ -0,0 +1,59 @@ +import assert from 'node:assert/strict'; +import test from 'node:test'; + +import { + V44_DEPOSITOR_DEMAND_OPPORTUNITY_STATE_IDS, + V44_DEPOSITOR_EARNINGS_SUPPLY_FORBIDDEN_PAYLOAD_IDS, + V44_DEPOSITOR_EARNINGS_SUPPLY_OBJECT_IDS, + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH, + V44_DEPOSITOR_EARNINGS_SUPPLY_ROWS, + V44_DEPOSITOR_EARNING_STATE_IDS, + V44_DEPOSITOR_SUPPLY_RECOMMENDATION_IDS, + buildV44DepositorEarningsSupplyOpportunities, +} from '../src/canonical/v44-depositor-earnings-supply-opportunities.js'; + +test('V44 Depositor earnings supply opportunities bind source-safe deposit-side economics', () => { + const artifact = buildV44DepositorEarningsSupplyOpportunities(); + + assert.equal(artifact.artifactId, 'v44-depositor-earnings-supply-opportunities'); + assert.equal(artifact.schemaId, 'bitcode.v44.depositorEarningsSupplyOpportunities.v1'); + assert.equal(artifact.version, 'V44'); + assert.equal(artifact.currentTarget, 'V43'); + assert.equal(artifact.passed, true); + assert.match(artifact.artifactRoot, /^v44-depositor-earnings-supply-opportunities:[a-f0-9]{24}$/u); + assert.equal(artifact.objectIds.length, V44_DEPOSITOR_EARNINGS_SUPPLY_OBJECT_IDS.length); + assert.equal(artifact.earningStateIds.length, V44_DEPOSITOR_EARNING_STATE_IDS.length); + assert.equal(artifact.recommendationIds.length, V44_DEPOSITOR_SUPPLY_RECOMMENDATION_IDS.length); + assert.equal(artifact.demandOpportunityStateIds.length, V44_DEPOSITOR_DEMAND_OPPORTUNITY_STATE_IDS.length); + assert.equal(artifact.rows.length, V44_DEPOSITOR_EARNINGS_SUPPLY_ROWS.length); + assert.equal(artifact.sourceRoots.earningSupplyIntelligence.startsWith('packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts:'), true); + assert.equal(artifact.sourceRoots.depositClient.startsWith('uapi/app/deposit/DepositPageClient.tsx:'), true); + assert.equal(artifact.coverage.depositorEarningSupplyIntelligenceImplemented, true); + assert.equal(artifact.coverage.likelyDemandImplemented, true); + assert.equal(artifact.coverage.unfitNeedOpportunitiesImplemented, true); + assert.equal(artifact.coverage.expectedCompensationRangesImplemented, true); + assert.equal(artifact.coverage.earningStatementsImplemented, true); + assert.equal(artifact.coverage.sourceSafeSupplyRecommendationsImplemented, true); + assert.equal(artifact.coverage.depositRouteUiImplemented, true); + assert.equal(artifact.coverage.failedPredicateIds.length, 0); +}); + +test('V44 Depositor earnings supply opportunities rows remain source-safe', () => { + const artifact = buildV44DepositorEarningsSupplyOpportunities(); + + assert.equal(artifact.coverage.sourceSafeMetadataOnly, true); + assert.equal(artifact.coverage.protectedSourceVisible, false); + assert.equal(artifact.coverage.rawSourceTextVisible, false); + assert.equal(artifact.coverage.unpaidAssetPackSourceVisible, false); + assert.equal(artifact.coverage.rawPromptVisible, false); + assert.equal(artifact.coverage.rawProviderResponseVisible, false); + assert.equal(artifact.coverage.walletPrivateMaterialVisible, false); + assert.equal(artifact.coverage.settlementPrivatePayloadVisible, false); + assert.equal(artifact.coverage.valueBearingMainnetAdmitted, false); + assert.equal(artifact.forbiddenPayloadIds.length, V44_DEPOSITOR_EARNINGS_SUPPLY_FORBIDDEN_PAYLOAD_IDS.length); + assert.equal(artifact.rows.every((row) => row.sourceSafeMetadataOnly), true); + assert.equal(artifact.rows.every((row) => row.protectedSourceVisible === false), true); + assert.equal(artifact.rows.every((row) => row.unpaidAssetPackSourceVisible === false), true); + assert.equal(artifact.sourceSafetyVerdict, 'source-safe-depositor-earnings-supply-opportunity-metadata'); + assert.equal(V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH, '.bitcode/v44-depositor-earnings-supply-opportunities.json'); +}); diff --git a/scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs b/scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs new file mode 100644 index 00000000..b7c1e679 --- /dev/null +++ b/scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs @@ -0,0 +1,198 @@ +#!/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 { + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH, + buildV44DepositorEarningsSupplyOpportunities, +} from '../packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const defaultRepoRoot = path.resolve(__dirname, '..'); + +function read(root, relativePath) { + return readFileSync(path.join(root, relativePath), 'utf8'); +} + +function exists(root, relativePath) { + return existsSync(path.join(root, relativePath)); +} + +function git(root, args) { + return execFileSync('git', args, { cwd: root, encoding: 'utf8' }).trim(); +} + +function run(root, command, args) { + execFileSync(command, args, { cwd: root, stdio: 'pipe', encoding: 'utf8' }); +} + +function assertCheck(failures, condition, message) { + if (!condition) failures.push(message); +} + +function parseArgs(argv) { + const args = { + repoRoot: defaultRepoRoot, + skipBranchCheck: false, + 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-v44-gate5-depositor-earnings-supply-opportunities.mjs [--skip-branch-check] [--skip-uapi-tests] [--skip-package-tests] [--repo-root ]', + '', + 'V44 Gate 5 Depositor earnings supply opportunities check: validates likely demand, unfit Need opportunities, ROI posture, source criticality, expected BTC compensation ranges, earning statements, source-safe supply recommendations, route UI, tests, workflows, and generated artifact freshness.', + ].join('\n'), + ); + process.stdout.write('\n'); +} + +function main() { + const args = parseArgs(process.argv.slice(2)); + if (args.help) { + printHelp(); + return; + } + + const root = args.repoRoot; + const failures = []; + const pointer = read(root, 'BITCODE_SPEC.txt').trim(); + + assertCheck(failures, pointer === 'V43', `BITCODE_SPEC.txt must remain V43 during V44 gate work. Observed ${pointer || 'empty'}.`); + + if (!args.skipBranchCheck) { + const branch = git(root, ['branch', '--show-current']); + assertCheck( + failures, + branch === 'version/v44' || /^v44\/gate-\d+-[a-z0-9][a-z0-9-]*$/u.test(branch), + `V44 work must occur on version/v44 or v44/gate-N-* branches. Observed ${branch || 'detached HEAD'}.`, + ); + } + + for (const relativePath of [ + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH, + 'packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts', + 'packages/pipelines/asset-pack/src/__tests__/depositor-earning-supply-intelligence.test.ts', + 'packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts', + 'uapi/app/deposit/deposit-route-model.ts', + 'uapi/app/deposit/DepositPageClient.tsx', + 'uapi/tests/depositRouteModel.test.ts', + 'uapi/tests/depositPageClient.test.tsx', + 'packages/btd/src/source-to-shares.ts', + 'packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js', + 'packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js', + 'scripts/generate-v44-depositor-earnings-supply-opportunities.mjs', + 'scripts/check-v44-gate5-depositor-earnings-supply-opportunities.mjs', + 'BITCODE_SPEC_V44.md', + 'BITCODE_SPEC_V44_DELTA.md', + 'BITCODE_SPEC_V44_NOTES.md', + 'BITCODE_SPEC_V44_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 V44 Gate 5 file: ${relativePath}`); + } + + const artifact = buildV44DepositorEarningsSupplyOpportunities({ repoRoot: root }); + assertCheck(failures, artifact.passed, `V44 Depositor earnings supply opportunity predicates failed: ${artifact.coverage.failedPredicateIds.join(', ')}`); + assertCheck(failures, artifact.coverage.depositorEarningSupplyIntelligenceImplemented === true, 'Depositor earning supply intelligence must be implemented.'); + assertCheck(failures, artifact.coverage.likelyDemandImplemented === true, 'Likely demand must be implemented.'); + assertCheck(failures, artifact.coverage.unfitNeedOpportunitiesImplemented === true, 'Unfit Need opportunities must be implemented.'); + assertCheck(failures, artifact.coverage.roiPostureImplemented === true, 'ROI posture must be implemented.'); + assertCheck(failures, artifact.coverage.sourceCriticalityPostureImplemented === true, 'Source criticality posture must be implemented.'); + assertCheck(failures, artifact.coverage.expectedCompensationRangesImplemented === true, 'Expected compensation ranges must be implemented.'); + assertCheck(failures, artifact.coverage.earningStatementsImplemented === true, 'Earning statements must be implemented.'); + assertCheck(failures, artifact.coverage.sourceSafeSupplyRecommendationsImplemented === true, 'Source-safe supply recommendations must be implemented.'); + assertCheck(failures, artifact.coverage.depositRouteUiImplemented === true, '/deposit earning UI must be implemented.'); + 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.rawSourceTextVisible === false, 'Artifact must not expose raw source text.'); + assertCheck(failures, artifact.coverage.unpaidAssetPackSourceVisible === false, 'Artifact must not expose unpaid AssetPack source.'); + assertCheck(failures, artifact.coverage.rawPromptVisible === false, 'Artifact must not expose raw prompts.'); + assertCheck(failures, artifact.coverage.rawProviderResponseVisible === false, 'Artifact must not expose raw provider responses.'); + assertCheck(failures, artifact.coverage.walletPrivateMaterialVisible === false, 'Artifact must not expose wallet private material.'); + assertCheck(failures, artifact.coverage.settlementPrivatePayloadVisible === false, 'Artifact must not expose private settlement payloads.'); + assertCheck(failures, artifact.coverage.valueBearingMainnetAdmitted === false, 'Artifact must not admit value-bearing mainnet operation.'); + + const serialized = `${JSON.stringify(artifact, null, 2)}\n`; + assertCheck( + failures, + exists(root, V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH) && + read(root, V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH) === serialized, + `${V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_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:v44-depositor-earnings-supply-opportunities"'), 'package.json must expose generate:v44-depositor-earnings-supply-opportunities.'); + assertCheck(failures, packageJson.includes('"check:v44-depositor-earnings-supply-opportunities"'), 'package.json must expose check:v44-depositor-earnings-supply-opportunities.'); + assertCheck(failures, packageJson.includes('"check:v44-gate5"'), 'package.json must expose check:v44-gate5.'); + assertCheck(failures, gateWorkflow.includes('check-v44-gate5-depositor-earnings-supply-opportunities.mjs'), 'Gate workflow must run V44 Gate 5 checker.'); + assertCheck(failures, canonWorkflow.includes('check-v44-gate5-depositor-earnings-supply-opportunities.mjs'), 'Canon workflow must run V44 Gate 5 checker.'); + + try { + run(root, 'node', ['scripts/generate-v44-depositor-earnings-supply-opportunities.mjs', '--check']); + } catch { + failures.push('V44 Depositor earnings supply opportunities artifact must be fresh.'); + } + + if (!args.skipPackageTests) { + try { + run(root, 'pnpm', ['--dir', 'packages/protocol', 'exec', 'node', '--test', '--test-force-exit', 'test/v44-depositor-earnings-supply-opportunities.test.js']); + } catch { + failures.push('packages/protocol/test/v44-depositor-earnings-supply-opportunities.test.js must pass.'); + } + + try { + run(root, 'pnpm', ['--filter', '@bitcode/pipeline-asset-pack', 'test', '--', 'depositor-earning-supply-intelligence.test.ts', '--runInBand']); + } catch { + failures.push('packages/pipelines/asset-pack depositor earning supply intelligence tests must pass.'); + } + } + + if (!args.skipUapiTests) { + try { + run(root, 'pnpm', ['--dir', 'uapi', 'exec', 'jest', 'depositRouteModel.test.ts', 'depositPageClient.test.tsx', '--runInBand']); + } catch { + failures.push('uapi deposit route/page tests must pass.'); + } + } + + if (failures.length > 0) { + process.stderr.write('V44 Gate 5 Depositor earnings supply opportunities check failed:\n'); + for (const failure of failures.filter(Boolean)) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write('V44 Gate 5 Depositor earnings supply opportunities 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-v44-depositor-earnings-supply-opportunities.mjs b/scripts/generate-v44-depositor-earnings-supply-opportunities.mjs new file mode 100644 index 00000000..be16a9f7 --- /dev/null +++ b/scripts/generate-v44-depositor-earnings-supply-opportunities.mjs @@ -0,0 +1,27 @@ +#!/usr/bin/env node + +import { existsSync, readFileSync, writeFileSync } from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; +import { + V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH, + buildV44DepositorEarningsSupplyOpportunities, +} from '../packages/protocol/src/canonical/v44-depositor-earnings-supply-opportunities.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); +const artifactPath = path.join(repoRoot, V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH); +const check = process.argv.includes('--check'); +const artifact = buildV44DepositorEarningsSupplyOpportunities({ repoRoot }); +const serialized = `${JSON.stringify(artifact, null, 2)}\n`; + +if (check) { + if (!existsSync(artifactPath) || readFileSync(artifactPath, 'utf8') !== serialized) { + process.stderr.write(`${V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH} is stale. Run pnpm run generate:v44-depositor-earnings-supply-opportunities.\n`); + process.exitCode = 1; + } +} else { + writeFileSync(artifactPath, serialized); + process.stdout.write(`wrote ${V44_DEPOSITOR_EARNINGS_SUPPLY_OPPORTUNITIES_ARTIFACT_PATH}\n`); +} diff --git a/uapi/app/deposit/DepositPageClient.tsx b/uapi/app/deposit/DepositPageClient.tsx index 3e75b83a..85844044 100644 --- a/uapi/app/deposit/DepositPageClient.tsx +++ b/uapi/app/deposit/DepositPageClient.tsx @@ -9,6 +9,7 @@ import { RefreshCw, ShieldCheck, Sparkles, + TrendingUp, } from "lucide-react"; import { useRouter, useSearchParams } from "next/navigation"; @@ -60,6 +61,8 @@ import type { const DEPOSIT_OPTION_PIPELINE_ID = "DepositAssetPackOptionSynthesis"; const DEPOSIT_OPTION_POLICY_ID = "DepositAssetPackOptionPolicy"; const DEPOSIT_OPTION_ADMISSION_ID = "DepositAssetPackOptionAdmissionReport"; +const DEPOSITOR_EARNING_SUPPLY_INTELLIGENCE_ID = + "DepositorEarningSupplyIntelligence"; function shortIdentifier(value: string | null | undefined) { if (!value) return "pending"; @@ -78,6 +81,11 @@ function formatDate(value: string | null | undefined) { }); } +function formatSats(value: number | null | undefined) { + if (typeof value !== "number" || !Number.isFinite(value)) return "pending"; + return `${value.toLocaleString()} sats`; +} + function readStringField(source: unknown, ...keys: string[]) { if (!source || typeof source !== "object") return null; const record = source as Record; @@ -367,6 +375,20 @@ export default function DepositPageClient() { weight: 0.58, }, ], + unfitNeedOpportunitySignals: [ + { + id: "unfit-need-route-proof-supply", + label: + "Unfit Reads need more source-safe route proof and delivery supply.", + weight: 0.82, + }, + { + id: "unfit-need-depository-search-supply", + label: + "Finding Fits benefits from more indexed Depository implementation patterns.", + weight: 0.74, + }, + ], sourceCriticalitySignals, developmentCostSats: Math.max(1600, 1200 + sourcePathHints.length * 240), expectedSettlementSats: Math.max( @@ -431,6 +453,7 @@ export default function DepositPageClient() { { label: "Pipeline", value: DEPOSIT_OPTION_PIPELINE_ID }, { label: "Policy", value: DEPOSIT_OPTION_POLICY_ID }, { label: "Admission", value: DEPOSIT_OPTION_ADMISSION_ID }, + { label: "Earnings", value: DEPOSITOR_EARNING_SUPPLY_INTELLIGENCE_ID }, { label: "Option roots", value: String(depositRouteSession.synthesis.roots.optionRoots.length), @@ -443,6 +466,13 @@ export default function DepositPageClient() { label: "Admitted options", value: String(depositRouteSession.admission.admittedCount), }, + { + label: "Expected compensation", + value: formatSats( + depositRouteSession.earningSupplyIntelligence.aggregate + .totalExpectedCompensationSats, + ), + }, ]; const recentDepositRuns = useMemo( @@ -642,6 +672,13 @@ export default function DepositPageClient() { value: depositRouteSession.synthesis.optionCount, }, { label: "Boundary", value: "source-safe" }, + { + label: "Earning estimate", + value: formatSats( + depositRouteSession.earningSupplyIntelligence.aggregate + .totalExpectedCompensationSats, + ), + }, ]} > receipt.optionId === option.optionId, ); + const earningStatement = + depositRouteSession.earningSupplyIntelligence.earningStatements.find( + (statement) => statement.optionId === option.optionId, + ); + const supplyRecommendation = + depositRouteSession.earningSupplyIntelligence.supplyRecommendations.find( + (recommendation) => + recommendation.optionId === option.optionId, + ); return (
) : null} + {earningStatement ? ( +
+
+ Earning estimate +
+
+ { + earningStatement + .expectedCompensationRangeSats.low + } + -{ + earningStatement + .expectedCompensationRangeSats.high + }{" "} + sats / {earningStatement.state} +
+
+ ) : null} + {supplyRecommendation ? ( +
+
+ Recommendation +
+
+ {supplyRecommendation.action} +
+
+ ) : null} ) : null} {option.measurements.map((measurement) => ( @@ -980,6 +1054,106 @@ export default function DepositPageClient() {