diff --git a/.bitcode/v44-btd-btc-compensation-statements.json b/.bitcode/v44-btd-btc-compensation-statements.json index 543d72ed..1fbd5346 100644 --- a/.bitcode/v44-btd-btc-compensation-statements.json +++ b/.bitcode/v44-btd-btc-compensation-statements.json @@ -5,7 +5,7 @@ "currentTarget": "V43", "sourceSafetyVerdict": "source-safe-btd-btc-compensation-statement-metadata", "generatedAt": "deterministic", - "artifactRoot": "v44-btd-btc-compensation-statements:7f735a88ce95c297b2f2bf5f", + "artifactRoot": "v44-btd-btc-compensation-statements:4deb21b419ea4de49c934761", "passed": true, "objectIds": [ "BtdBtcCompensationStatements", @@ -179,16 +179,16 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", - "spec": "BITCODE_SPEC_V44.md:992ae5c680f4035900a87f6d", - "delta": "BITCODE_SPEC_V44_DELTA.md:8b0510905db9a702fec88696", - "notes": "BITCODE_SPEC_V44_NOTES.md:9897826394794b53459c4359", - "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:5d9b0b7f8b510621a518bbb5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:411696552a2be710bcdc9d01", - "readme": "README.md:4f63eaea3d2660cdc80b7c0f", - "protocolReadme": "packages/protocol/README.md:03c496b8817bbd8cf8b6927d", - "packageJson": "package.json:45bafd0a9f3cd7cea6a1bcff", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:10d2fccdd6178ca00ef821c0", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:6f97f7499bd7d4b1d69aed83", + "spec": "BITCODE_SPEC_V44.md:e215c9d702cfca700f5c709b", + "delta": "BITCODE_SPEC_V44_DELTA.md:0ef890b5bb1435b44780ee4b", + "notes": "BITCODE_SPEC_V44_NOTES.md:951e0798b5d9c4f7f063a2da", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:089ca0f30ddd7a1902e41a34", + "roadmap": "SPECIFICATIONS_ROADMAP.md:87d18b6eb15464c3c4249532", + "readme": "README.md:62cc39fe7b3cb4f730e581f9", + "protocolReadme": "packages/protocol/README.md:6af505bd152611328b055bbd", + "packageJson": "package.json:809fa4b7a82a5d58f10c365f", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:d97de3b662a26bc83c225e89", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:07a7006c556f6f107fac74a0", "economicModel": "packages/protocol/src/canonical/v44-economic-domain-model.js:21b8f5c80ad8322dff2909ed", "settlementBoundary": "packages/pipelines/asset-pack/src/asset-pack-settlement-rights-delivery.ts:4e5eebe66c2075acef628682", "accountingStatements": "packages/pipelines/asset-pack/src/btd-btc-compensation-statements.ts:a239683c231a0127c4777a3f", @@ -197,14 +197,14 @@ "btdSettlement": "packages/btd/src/settlement.ts:871ea57357f464d8fbb0c6af", "btdReceipts": "packages/btd/src/receipts.ts:663e799baf0715924cb67c14", "btdReconciliation": "packages/btd/src/reconciliation.ts:d4bc6c129196572ae673c05b", - "packActivityModel": "uapi/components/base/bitcode/activity/pack-activity-model.ts:dcbe49cf25b13fea054dfff6", - "packsClient": "uapi/app/packs/PacksPageClient.tsx:3404c916cdd9f96ed1708065", - "packActivityModelTest": "uapi/tests/packActivityModel.test.ts:972f495ee8658eac72c234ca", - "packsClientTest": "uapi/tests/packsPageClient.test.tsx:60075282ab5c41917233c44f", - "assetPackPackageIndex": "packages/pipelines/asset-pack/src/index.ts:c55bc5e29f7d0b30f9060222", - "assetPackPackageManifest": "packages/pipelines/asset-pack/package.json:d43190e869c08b6d84ee81fa", - "packageIndex": "packages/protocol/src/index.js:eac2606fb210e2c0dd38ae7a", - "packageTypes": "packages/protocol/src/index.d.ts:621beb875ce903727d5daf24", + "packActivityModel": "uapi/components/base/bitcode/activity/pack-activity-model.ts:0c69746f1b9cbb70e2b0be09", + "packsClient": "uapi/app/packs/PacksPageClient.tsx:5dbaae660c70de141a780e58", + "packActivityModelTest": "uapi/tests/packActivityModel.test.ts:882c5ac213f83d8b57a6e5ff", + "packsClientTest": "uapi/tests/packsPageClient.test.tsx:400aa55dbeae6bbdb90a08b4", + "assetPackPackageIndex": "packages/pipelines/asset-pack/src/index.ts:48330699ed60ccb1db2bb77d", + "assetPackPackageManifest": "packages/pipelines/asset-pack/package.json:45926bffaa0fe93aee0d41cb", + "packageIndex": "packages/protocol/src/index.js:a394466468bf6e59ee72b2f7", + "packageTypes": "packages/protocol/src/index.d.ts:1a6ef5f0300aceb3b4f34b9c", "packageSource": "packages/protocol/src/canonical/v44-btd-btc-compensation-statements.js:b7cd49efa70c18f93be91661", "packageTest": "packages/protocol/test/v44-btd-btc-compensation-statements.test.js:8c8bff4a58a07f01c94b1d90", "generator": "scripts/generate-v44-btd-btc-compensation-statements.mjs:603d3af279f716d625f891c9", diff --git a/.bitcode/v44-depositor-earnings-supply-opportunities.json b/.bitcode/v44-depositor-earnings-supply-opportunities.json index 1548d060..6c37a80a 100644 --- a/.bitcode/v44-depositor-earnings-supply-opportunities.json +++ b/.bitcode/v44-depositor-earnings-supply-opportunities.json @@ -5,7 +5,7 @@ "currentTarget": "V43", "sourceSafetyVerdict": "source-safe-depositor-earnings-supply-opportunity-metadata", "generatedAt": "deterministic", - "artifactRoot": "v44-depositor-earnings-supply-opportunities:1dc94c212a971a2277424d63", + "artifactRoot": "v44-depositor-earnings-supply-opportunities:c5f0242af75bf0f13517b017", "passed": true, "objectIds": [ "DepositorEarningSupplyIntelligence", @@ -136,30 +136,30 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", - "spec": "BITCODE_SPEC_V44.md:992ae5c680f4035900a87f6d", - "delta": "BITCODE_SPEC_V44_DELTA.md:8b0510905db9a702fec88696", - "notes": "BITCODE_SPEC_V44_NOTES.md:9897826394794b53459c4359", - "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:5d9b0b7f8b510621a518bbb5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:411696552a2be710bcdc9d01", - "readme": "README.md:4f63eaea3d2660cdc80b7c0f", - "protocolReadme": "packages/protocol/README.md:03c496b8817bbd8cf8b6927d", - "packageJson": "package.json:45bafd0a9f3cd7cea6a1bcff", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:10d2fccdd6178ca00ef821c0", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:6f97f7499bd7d4b1d69aed83", + "spec": "BITCODE_SPEC_V44.md:e215c9d702cfca700f5c709b", + "delta": "BITCODE_SPEC_V44_DELTA.md:0ef890b5bb1435b44780ee4b", + "notes": "BITCODE_SPEC_V44_NOTES.md:951e0798b5d9c4f7f063a2da", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:089ca0f30ddd7a1902e41a34", + "roadmap": "SPECIFICATIONS_ROADMAP.md:87d18b6eb15464c3c4249532", + "readme": "README.md:62cc39fe7b3cb4f730e581f9", + "protocolReadme": "packages/protocol/README.md:6af505bd152611328b055bbd", + "packageJson": "package.json:809fa4b7a82a5d58f10c365f", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:d97de3b662a26bc83c225e89", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:07a7006c556f6f107fac74a0", "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:c55bc5e29f7d0b30f9060222", - "assetPackPackageManifest": "packages/pipelines/asset-pack/package.json:d43190e869c08b6d84ee81fa", + "depositModel": "uapi/app/deposit/deposit-route-model.ts:6485e388dd745c79907f992c", + "depositClient": "uapi/app/deposit/DepositPageClient.tsx:4f5cb4d29e42ca1f6a84c628", + "depositRouteTest": "uapi/tests/depositRouteModel.test.ts:3f7377f8c55ce132f970ad09", + "depositPageTest": "uapi/tests/depositPageClient.test.tsx:d72a8acb191b6d62d49f8679", + "assetPackPackageIndex": "packages/pipelines/asset-pack/src/index.ts:48330699ed60ccb1db2bb77d", + "assetPackPackageManifest": "packages/pipelines/asset-pack/package.json:45926bffaa0fe93aee0d41cb", "sourceToShares": "packages/btd/src/source-to-shares.ts:6e2e84251b29ba2477766708", - "packageIndex": "packages/protocol/src/index.js:eac2606fb210e2c0dd38ae7a", - "packageTypes": "packages/protocol/src/index.d.ts:621beb875ce903727d5daf24", + "packageIndex": "packages/protocol/src/index.js:a394466468bf6e59ee72b2f7", + "packageTypes": "packages/protocol/src/index.d.ts:1a6ef5f0300aceb3b4f34b9c", "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", diff --git a/.bitcode/v44-economic-domain-model.json b/.bitcode/v44-economic-domain-model.json index 7c1de5c2..4f10b066 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:49cb52f14d9b584c13c190e2", + "artifactRoot": "v44-economic-domain-model:a257d37a58207887e068716d", "passed": true, "economicObjectIds": [ "EnterprisePackPortfolio", @@ -759,18 +759,18 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", - "spec": "BITCODE_SPEC_V44.md:992ae5c680f4035900a87f6d", - "delta": "BITCODE_SPEC_V44_DELTA.md:8b0510905db9a702fec88696", - "notes": "BITCODE_SPEC_V44_NOTES.md:9897826394794b53459c4359", - "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:5d9b0b7f8b510621a518bbb5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:411696552a2be710bcdc9d01", - "readme": "README.md:4f63eaea3d2660cdc80b7c0f", - "protocolReadme": "packages/protocol/README.md:03c496b8817bbd8cf8b6927d", - "packageJson": "package.json:45bafd0a9f3cd7cea6a1bcff", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:10d2fccdd6178ca00ef821c0", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:6f97f7499bd7d4b1d69aed83", - "packageIndex": "packages/protocol/src/index.js:eac2606fb210e2c0dd38ae7a", - "packageTypes": "packages/protocol/src/index.d.ts:621beb875ce903727d5daf24", + "spec": "BITCODE_SPEC_V44.md:e215c9d702cfca700f5c709b", + "delta": "BITCODE_SPEC_V44_DELTA.md:0ef890b5bb1435b44780ee4b", + "notes": "BITCODE_SPEC_V44_NOTES.md:951e0798b5d9c4f7f063a2da", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:089ca0f30ddd7a1902e41a34", + "roadmap": "SPECIFICATIONS_ROADMAP.md:87d18b6eb15464c3c4249532", + "readme": "README.md:62cc39fe7b3cb4f730e581f9", + "protocolReadme": "packages/protocol/README.md:6af505bd152611328b055bbd", + "packageJson": "package.json:809fa4b7a82a5d58f10c365f", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:d97de3b662a26bc83c225e89", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:07a7006c556f6f107fac74a0", + "packageIndex": "packages/protocol/src/index.js:a394466468bf6e59ee72b2f7", + "packageTypes": "packages/protocol/src/index.d.ts:1a6ef5f0300aceb3b4f34b9c", "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-organization-policy-wallet-authority.json b/.bitcode/v44-organization-policy-wallet-authority.json new file mode 100644 index 00000000..b37fda75 --- /dev/null +++ b/.bitcode/v44-organization-policy-wallet-authority.json @@ -0,0 +1,427 @@ +{ + "artifactId": "v44-organization-policy-wallet-authority", + "schemaId": "bitcode.v44.organizationPolicyWalletAuthority.v1", + "version": "V44", + "currentTarget": "V43", + "sourceSafetyVerdict": "source-safe-organization-policy-wallet-authority-metadata", + "objectIds": [ + "OrganizationPolicyWalletAuthority", + "OrganizationPolicyActionStatement", + "OrganizationBudgetApprovalPolicy", + "OrganizationDepositApprovalPolicy", + "OrganizationWalletAuthorityStatement", + "OrganizationGovernanceDecision", + "PackActivityGovernanceReadback", + "BtdOrganizationPolicyAuthority" + ], + "routeIds": [ + "/read", + "/deposit", + "/packs" + ], + "actionIds": [ + "request_read", + "review_need", + "request_finding_fits", + "review_asset_pack_preview", + "pay_btc_fee", + "unlock_asset_pack_source", + "deliver_asset_pack", + "synthesize_deposit_options", + "approve_deposit_option", + "submit_deposit", + "read_transaction", + "repair_projection", + "administer_organization" + ], + "stateIds": [ + "allowed", + "denied", + "repair-required", + "within-limit", + "approval-required", + "limit-exceeded", + "sub-critical-approved", + "source-criticality-approval-required", + "critical-source-blocked", + "deposit-approval-required", + "verified", + "missing", + "not-required" + ], + "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": "btd-deposit-actions", + "owner": "packages/btd/src/authority.ts", + "contract": "BTD organization authority covers deposit option synthesis, approval, and submission beside Reading spend, source unlock, delivery, repair, and administration.", + "requiredFields": [ + "synthesize_deposit_options", + "approve_deposit_option", + "submit_deposit", + "wallet_binding_missing" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "walletPrivateMaterialVisible": false, + "valueBearingMainnetAdmitted": false, + "rowRoot": "v44-organization-policy-row:f1d23f21ef4fb9a1f52cc75f" + }, + { + "rowId": "source-safe-governance-statement", + "owner": "packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts", + "contract": "OrganizationPolicyWalletAuthority composes budget approval, deposit approval, wallet authority, action statements, aggregate blockers, roots, and source-safety disclosure.", + "requiredFields": [ + "OrganizationPolicyWalletAuthority", + "budgetApproval", + "depositApproval", + "walletAuthority" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "walletPrivateMaterialVisible": false, + "valueBearingMainnetAdmitted": false, + "rowRoot": "v44-organization-policy-row:8037685c886ebaab143f55b5" + }, + { + "rowId": "read-route-authority", + "owner": "uapi/app/read/read-route-model.ts", + "contract": "/read binds organization policy wallet authority to budgeted quotes, buyer approval, wallet authority, and source-safe route assertions.", + "requiredFields": [ + "organizationPolicyWalletAuthority", + "pay_btc_fee", + "source_safe_read_route_metadata" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "walletPrivateMaterialVisible": false, + "valueBearingMainnetAdmitted": false, + "rowRoot": "v44-organization-policy-row:e97e951d1651226fc8ff3e19" + }, + { + "rowId": "deposit-route-authority", + "owner": "uapi/app/deposit/deposit-route-model.ts", + "contract": "/deposit binds source criticality approval, deposit approval, wallet authority, and deposit admission policy into route state.", + "requiredFields": [ + "organizationPolicyWalletAuthority", + "sourceCriticalityApproved", + "admissionAndIndexingPolicyPresent" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "walletPrivateMaterialVisible": false, + "valueBearingMainnetAdmitted": false, + "rowRoot": "v44-organization-policy-row:fa255c011ff1467242e2fc55" + }, + { + "rowId": "packs-governance-readback", + "owner": "uapi/components/base/bitcode/activity/pack-activity-model.ts", + "contract": "/packs projects source-safe governance readback into searchable activity detail without serializing secrets or protected source.", + "requiredFields": [ + "PackActivityGovernanceReadback", + "buildGovernanceReadback", + "authorityRoot" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "walletPrivateMaterialVisible": false, + "valueBearingMainnetAdmitted": false, + "rowRoot": "v44-organization-policy-row:bc943098dad2eaa05dcd226b" + }, + { + "rowId": "read-deposit-ui-governance", + "owner": "uapi/app/read/ReadPageClient.tsx", + "contract": "/read and /deposit render Organization authority sections with authority state, wallet state, blockers, and authority roots.", + "requiredFields": [ + "Organization authority", + "Authority blockers", + "organizationPolicyWalletAuthority" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "walletPrivateMaterialVisible": false, + "valueBearingMainnetAdmitted": false, + "rowRoot": "v44-organization-policy-row:e4341cfac5e8d6251829e726" + }, + { + "rowId": "fail-closed-tests", + "owner": "packages/pipelines/asset-pack/src/__tests__/organization-policy-wallet-authority.test.ts", + "contract": "Focused tests prove approved Reading spend, missing wallet denial, approved deposit submission, and critical-source deposit blocking.", + "requiredFields": [ + "pay_btc_fee", + "wallet_binding_missing", + "sub-critical-approved", + "critical-source-blocked" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "walletPrivateMaterialVisible": false, + "valueBearingMainnetAdmitted": false, + "rowRoot": "v44-organization-policy-row:49e0624bb053f6a95c5cd0b5" + }, + { + "rowId": "workflow-and-artifact-wiring", + "owner": "scripts/check-v44-gate7-organization-policy-wallet-authority.mjs", + "contract": "Gate 7 closes only when generator, checker, package exports, protocol exports, docs, workflows, and generated artifact are current.", + "requiredFields": [ + "check-v44-gate7-organization-policy-wallet-authority", + "generate-v44-organization-policy-wallet-authority" + ], + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "walletPrivateMaterialVisible": false, + "valueBearingMainnetAdmitted": false, + "rowRoot": "v44-organization-policy-row:ddbda655a267ec781d168a50" + } + ], + "predicateResults": [ + { + "id": "active-canon-pointer-remains-v43", + "sourcePath": "BITCODE_SPEC.txt", + "passed": true + }, + { + "id": "spec-defines-gate7", + "sourcePath": "BITCODE_SPEC_V44.md", + "passed": true + }, + { + "id": "spec-names-gate7-artifact", + "sourcePath": "BITCODE_SPEC_V44.md", + "passed": true + }, + { + "id": "delta-records-gate7", + "sourcePath": "BITCODE_SPEC_V44_DELTA.md", + "passed": true + }, + { + "id": "notes-records-gate7", + "sourcePath": "BITCODE_SPEC_V44_NOTES.md", + "passed": true + }, + { + "id": "parity-records-gate7", + "sourcePath": "BITCODE_SPEC_V44_PARITY_MATRIX.md", + "passed": true + }, + { + "id": "roadmap-records-gate7", + "sourcePath": "SPECIFICATIONS_ROADMAP.md", + "passed": true + }, + { + "id": "readme-records-gate7", + "sourcePath": "README.md", + "passed": true + }, + { + "id": "protocol-readme-records-gate7", + "sourcePath": "packages/protocol/README.md", + "passed": true + }, + { + "id": "btd-authority-actions-defined", + "sourcePath": "packages/btd/src/authority.ts", + "passed": true + }, + { + "id": "btd-authority-test-covers-deposit-actions", + "sourcePath": "packages/btd/__tests__/btd.test.ts", + "passed": true + }, + { + "id": "package-helper-defined", + "sourcePath": "packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts", + "passed": true + }, + { + "id": "package-helper-source-safe-assertion", + "sourcePath": "packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts", + "passed": true + }, + { + "id": "package-helper-test-covers-policy-paths", + "sourcePath": "packages/pipelines/asset-pack/src/__tests__/organization-policy-wallet-authority.test.ts", + "passed": true + }, + { + "id": "asset-pack-package-exports-helper", + "sourcePath": "packages/pipelines/asset-pack/src/index.ts", + "passed": true + }, + { + "id": "asset-pack-manifest-exports-helper", + "sourcePath": "packages/pipelines/asset-pack/package.json", + "passed": true + }, + { + "id": "read-route-model-binds-authority", + "sourcePath": "uapi/app/read/read-route-model.ts", + "passed": true + }, + { + "id": "read-route-test-covers-authority", + "sourcePath": "uapi/tests/readRouteModel.test.ts", + "passed": true + }, + { + "id": "read-client-renders-authority", + "sourcePath": "uapi/app/read/ReadPageClient.tsx", + "passed": true + }, + { + "id": "read-client-test-covers-authority", + "sourcePath": "uapi/tests/readPageClient.test.tsx", + "passed": true + }, + { + "id": "deposit-route-model-binds-authority", + "sourcePath": "uapi/app/deposit/deposit-route-model.ts", + "passed": true + }, + { + "id": "deposit-route-test-covers-authority", + "sourcePath": "uapi/tests/depositRouteModel.test.ts", + "passed": true + }, + { + "id": "deposit-client-renders-authority", + "sourcePath": "uapi/app/deposit/DepositPageClient.tsx", + "passed": true + }, + { + "id": "deposit-client-test-covers-authority", + "sourcePath": "uapi/tests/depositPageClient.test.tsx", + "passed": true + }, + { + "id": "packs-model-projects-governance", + "sourcePath": "uapi/components/base/bitcode/activity/pack-activity-model.ts", + "passed": true + }, + { + "id": "packs-client-renders-governance", + "sourcePath": "uapi/app/packs/PacksPageClient.tsx", + "passed": true + }, + { + "id": "pack-activity-test-covers-governance", + "sourcePath": "uapi/tests/packActivityModel.test.ts", + "passed": true + }, + { + "id": "packs-client-test-covers-governance", + "sourcePath": "uapi/tests/packsPageClient.test.tsx", + "passed": true + }, + { + "id": "package-test-covers-gate7", + "sourcePath": "packages/protocol/test/v44-organization-policy-wallet-authority.test.js", + "passed": true + }, + { + "id": "package-exports-gate7", + "sourcePath": "packages/protocol/src/index.js", + "passed": true + }, + { + "id": "package-types-export-gate7", + "sourcePath": "packages/protocol/src/index.d.ts", + "passed": true + }, + { + "id": "package-json-exposes-gate7", + "sourcePath": "package.json", + "passed": true + }, + { + "id": "gate-workflow-runs-gate7", + "sourcePath": ".github/workflows/bitcode-gate-quality.yml", + "passed": true + }, + { + "id": "canon-workflow-runs-gate7", + "sourcePath": ".github/workflows/bitcode-canon-quality.yml", + "passed": true + }, + { + "id": "generator-exists", + "sourcePath": "scripts/generate-v44-organization-policy-wallet-authority.mjs", + "passed": true + }, + { + "id": "checker-exists", + "sourcePath": "scripts/check-v44-gate7-organization-policy-wallet-authority.mjs", + "passed": true + } + ], + "sourceRoots": { + "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", + "spec": "BITCODE_SPEC_V44.md:e215c9d702cfca700f5c709b", + "delta": "BITCODE_SPEC_V44_DELTA.md:0ef890b5bb1435b44780ee4b", + "notes": "BITCODE_SPEC_V44_NOTES.md:951e0798b5d9c4f7f063a2da", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:089ca0f30ddd7a1902e41a34", + "roadmap": "SPECIFICATIONS_ROADMAP.md:87d18b6eb15464c3c4249532", + "readme": "README.md:62cc39fe7b3cb4f730e581f9", + "protocolReadme": "packages/protocol/README.md:6af505bd152611328b055bbd", + "packageJson": "package.json:809fa4b7a82a5d58f10c365f", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:d97de3b662a26bc83c225e89", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:07a7006c556f6f107fac74a0", + "btdAuthority": "packages/btd/src/authority.ts:20b1fe9ef12d791fab3e1de7", + "btdAuthorityTest": "packages/btd/__tests__/btd.test.ts:21a5e15a3ec931d2c4c7a1cd", + "packageHelper": "packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts:ed6fa07bc3f69caaca598249", + "packageHelperTest": "packages/pipelines/asset-pack/src/__tests__/organization-policy-wallet-authority.test.ts:dffe4b5f7918abac32d9930b", + "assetPackPackageIndex": "packages/pipelines/asset-pack/src/index.ts:48330699ed60ccb1db2bb77d", + "assetPackPackageManifest": "packages/pipelines/asset-pack/package.json:45926bffaa0fe93aee0d41cb", + "readRouteModel": "uapi/app/read/read-route-model.ts:670e1abd63cccea6365a491f", + "readRouteTest": "uapi/tests/readRouteModel.test.ts:5ad610c538f65fb0c860777f", + "readClient": "uapi/app/read/ReadPageClient.tsx:8c8219f42275485d4dffd327", + "readClientTest": "uapi/tests/readPageClient.test.tsx:116589281edef9c19e57b9ba", + "depositRouteModel": "uapi/app/deposit/deposit-route-model.ts:6485e388dd745c79907f992c", + "depositRouteTest": "uapi/tests/depositRouteModel.test.ts:3f7377f8c55ce132f970ad09", + "depositClient": "uapi/app/deposit/DepositPageClient.tsx:4f5cb4d29e42ca1f6a84c628", + "depositClientTest": "uapi/tests/depositPageClient.test.tsx:d72a8acb191b6d62d49f8679", + "packActivityModel": "uapi/components/base/bitcode/activity/pack-activity-model.ts:0c69746f1b9cbb70e2b0be09", + "packsClient": "uapi/app/packs/PacksPageClient.tsx:5dbaae660c70de141a780e58", + "packActivityModelTest": "uapi/tests/packActivityModel.test.ts:882c5ac213f83d8b57a6e5ff", + "packsClientTest": "uapi/tests/packsPageClient.test.tsx:400aa55dbeae6bbdb90a08b4", + "packageIndex": "packages/protocol/src/index.js:a394466468bf6e59ee72b2f7", + "packageTypes": "packages/protocol/src/index.d.ts:1a6ef5f0300aceb3b4f34b9c", + "packageSource": "packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js:6936c960db233b0cee9b588a", + "packageTest": "packages/protocol/test/v44-organization-policy-wallet-authority.test.js:95d6dc48346a60a88d83d4b7", + "generator": "scripts/generate-v44-organization-policy-wallet-authority.mjs:faabf63e75da42310d30df06", + "checker": "scripts/check-v44-gate7-organization-policy-wallet-authority.mjs:fd3dc2088ab6e5a322658257" + }, + "coverage": { + "organizationPolicyWalletAuthorityImplemented": true, + "btdDepositActionsImplemented": true, + "readRouteAuthorityImplemented": true, + "depositRouteAuthorityImplemented": true, + "packsGovernanceReadbackImplemented": true, + "testsImplemented": true, + "sourceSafeMetadataOnly": true, + "protectedSourceVisible": false, + "rawSourceTextVisible": false, + "unpaidAssetPackSourceVisible": false, + "rawPromptVisible": false, + "rawProviderResponseVisible": false, + "walletPrivateMaterialVisible": false, + "settlementPrivatePayloadVisible": false, + "valueBearingMainnetAdmitted": false, + "failedPredicateIds": [] + }, + "passed": true, + "artifactRoot": "v44-organization-policy-wallet-authority:ee9d985a2321657c540eadea" +} diff --git a/.bitcode/v44-packs-portfolio-market-intelligence.json b/.bitcode/v44-packs-portfolio-market-intelligence.json index 9bdc5895..82c90349 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:1a78e4a8b514891a3e8b6c0b", + "artifactRoot": "v44-packs-portfolio-market-intelligence:cfeb721035b117cf09239cbb", "passed": true, "portfolioViewIds": [ "enterprise-pack-portfolio", @@ -109,23 +109,23 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", - "spec": "BITCODE_SPEC_V44.md:992ae5c680f4035900a87f6d", - "delta": "BITCODE_SPEC_V44_DELTA.md:8b0510905db9a702fec88696", - "notes": "BITCODE_SPEC_V44_NOTES.md:9897826394794b53459c4359", - "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:5d9b0b7f8b510621a518bbb5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:411696552a2be710bcdc9d01", - "readme": "README.md:4f63eaea3d2660cdc80b7c0f", - "protocolReadme": "packages/protocol/README.md:03c496b8817bbd8cf8b6927d", - "packageJson": "package.json:45bafd0a9f3cd7cea6a1bcff", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:10d2fccdd6178ca00ef821c0", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:6f97f7499bd7d4b1d69aed83", + "spec": "BITCODE_SPEC_V44.md:e215c9d702cfca700f5c709b", + "delta": "BITCODE_SPEC_V44_DELTA.md:0ef890b5bb1435b44780ee4b", + "notes": "BITCODE_SPEC_V44_NOTES.md:951e0798b5d9c4f7f063a2da", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:089ca0f30ddd7a1902e41a34", + "roadmap": "SPECIFICATIONS_ROADMAP.md:87d18b6eb15464c3c4249532", + "readme": "README.md:62cc39fe7b3cb4f730e581f9", + "protocolReadme": "packages/protocol/README.md:6af505bd152611328b055bbd", + "packageJson": "package.json:809fa4b7a82a5d58f10c365f", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:d97de3b662a26bc83c225e89", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:07a7006c556f6f107fac74a0", "economicModel": "packages/protocol/src/canonical/v44-economic-domain-model.js:21b8f5c80ad8322dff2909ed", - "model": "uapi/components/base/bitcode/activity/pack-activity-model.ts:dcbe49cf25b13fea054dfff6", + "model": "uapi/components/base/bitcode/activity/pack-activity-model.ts:0c69746f1b9cbb70e2b0be09", "route": "uapi/app/api/packs/activity/route.ts:97c5a4539d48562eb5de66e8", - "client": "uapi/app/packs/PacksPageClient.tsx:3404c916cdd9f96ed1708065", - "uapiTest": "uapi/tests/packActivityModel.test.ts:972f495ee8658eac72c234ca", - "packageIndex": "packages/protocol/src/index.js:eac2606fb210e2c0dd38ae7a", - "packageTypes": "packages/protocol/src/index.d.ts:621beb875ce903727d5daf24", + "client": "uapi/app/packs/PacksPageClient.tsx:5dbaae660c70de141a780e58", + "uapiTest": "uapi/tests/packActivityModel.test.ts:882c5ac213f83d8b57a6e5ff", + "packageIndex": "packages/protocol/src/index.js:a394466468bf6e59ee72b2f7", + "packageTypes": "packages/protocol/src/index.d.ts:1a6ef5f0300aceb3b4f34b9c", "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 35bd50da..ff70e93f 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:eb9bdf61b50a1d5bc8a210f3", + "artifactRoot": "v44-reading-budget-quote-policy:82b4d9dd98bcf1481d730756", "passed": true, "objectIds": [ "ReadingBudgetPolicy", @@ -145,24 +145,24 @@ ], "sourceRoots": { "activePointer": "BITCODE_SPEC.txt:4ea77b214c66f69c697bff3d", - "spec": "BITCODE_SPEC_V44.md:992ae5c680f4035900a87f6d", - "delta": "BITCODE_SPEC_V44_DELTA.md:8b0510905db9a702fec88696", - "notes": "BITCODE_SPEC_V44_NOTES.md:9897826394794b53459c4359", - "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:5d9b0b7f8b510621a518bbb5", - "roadmap": "SPECIFICATIONS_ROADMAP.md:411696552a2be710bcdc9d01", - "readme": "README.md:4f63eaea3d2660cdc80b7c0f", - "protocolReadme": "packages/protocol/README.md:03c496b8817bbd8cf8b6927d", - "packageJson": "package.json:45bafd0a9f3cd7cea6a1bcff", - "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:10d2fccdd6178ca00ef821c0", - "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:6f97f7499bd7d4b1d69aed83", + "spec": "BITCODE_SPEC_V44.md:e215c9d702cfca700f5c709b", + "delta": "BITCODE_SPEC_V44_DELTA.md:0ef890b5bb1435b44780ee4b", + "notes": "BITCODE_SPEC_V44_NOTES.md:951e0798b5d9c4f7f063a2da", + "parity": "BITCODE_SPEC_V44_PARITY_MATRIX.md:089ca0f30ddd7a1902e41a34", + "roadmap": "SPECIFICATIONS_ROADMAP.md:87d18b6eb15464c3c4249532", + "readme": "README.md:62cc39fe7b3cb4f730e581f9", + "protocolReadme": "packages/protocol/README.md:6af505bd152611328b055bbd", + "packageJson": "package.json:809fa4b7a82a5d58f10c365f", + "gateWorkflow": ".github/workflows/bitcode-gate-quality.yml:d97de3b662a26bc83c225e89", + "canonWorkflow": ".github/workflows/bitcode-canon-quality.yml:07a7006c556f6f107fac74a0", "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", + "readModel": "uapi/app/read/read-route-model.ts:670e1abd63cccea6365a491f", + "readClient": "uapi/app/read/ReadPageClient.tsx:8c8219f42275485d4dffd327", + "readModelTest": "uapi/tests/readRouteModel.test.ts:5ad610c538f65fb0c860777f", "sourceToShares": "packages/btd/src/source-to-shares.ts:6e2e84251b29ba2477766708", "btcFeeOperation": "packages/btd/src/btc-fee-operation.ts:65f910e8e471fe199939e9c4", - "packageIndex": "packages/protocol/src/index.js:eac2606fb210e2c0dd38ae7a", - "packageTypes": "packages/protocol/src/index.d.ts:621beb875ce903727d5daf24", + "packageIndex": "packages/protocol/src/index.js:a394466468bf6e59ee72b2f7", + "packageTypes": "packages/protocol/src/index.d.ts:1a6ef5f0300aceb3b4f34b9c", "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 04bf3e4d..b27dede3 100644 --- a/.github/workflows/bitcode-canon-quality.yml +++ b/.github/workflows/bitcode-canon-quality.yml @@ -379,6 +379,9 @@ jobs: if [ -f scripts/check-v44-gate6-btd-btc-compensation-statements.mjs ]; then node scripts/check-v44-gate6-btd-btc-compensation-statements.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ -f scripts/check-v44-gate7-organization-policy-wallet-authority.mjs ]; then + node scripts/check-v44-gate7-organization-policy-wallet-authority.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 4fd0187e..85229aab 100644 --- a/.github/workflows/bitcode-gate-quality.yml +++ b/.github/workflows/bitcode-gate-quality.yml @@ -508,6 +508,9 @@ jobs: if [ -f scripts/check-v44-gate6-btd-btc-compensation-statements.mjs ]; then node scripts/check-v44-gate6-btd-btc-compensation-statements.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ -f scripts/check-v44-gate7-organization-policy-wallet-authority.mjs ]; then + node scripts/check-v44-gate7-organization-policy-wallet-authority.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests + fi fi else echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2 @@ -558,6 +561,9 @@ jobs: if [ "$POINTER" = "V43" ] && [ -f scripts/check-v44-gate6-btd-btc-compensation-statements.mjs ]; then node scripts/check-v44-gate6-btd-btc-compensation-statements.mjs --skip-branch-check --skip-uapi-tests --skip-package-tests fi + if [ "$POINTER" = "V43" ] && [ -f scripts/check-v44-gate7-organization-policy-wallet-authority.mjs ]; then + node scripts/check-v44-gate7-organization-policy-wallet-authority.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 55e7ae4c..6cf6cd4a 100644 --- a/BITCODE_SPEC_V44.md +++ b/BITCODE_SPEC_V44.md @@ -3,12 +3,12 @@ ## Status - Version: `V44` -- V44 state: draft Gate 6 BTD/BTC compensation statement work over promoted V43 product routes +- V44 state: draft Gate 7 organization policy wallet authority 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, Gate 4 Reading budget quote policy, Gate 5 Depositor earnings supply opportunity, and Gate 6 BTD/BTC compensation statement 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 6 binds source-safe BTD range state, BTC settlement observations, source-to-shares contributor allocations, depositor summaries, treasury routes, reconciliation, repair state, and `/packs` accounting readback without exposing unpaid source or admitting value-bearing mainnet +- 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, Gate 5 Depositor earnings supply opportunity, Gate 6 BTD/BTC compensation statement, and Gate 7 organization policy wallet authority 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 7 binds source-safe organization roles, budget approvals, source criticality approvals, spend/deposit limits, wallet authority, route action statements, and `/packs` governance readback without exposing unpaid source, wallet private material, 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` @@ -287,6 +287,23 @@ Gate 7 must bind organization-level policy across `/read`, `/deposit`, and authority, spend limits, deposit limits, policy receipts, and fail-closed permission checks. +Gate 7 closes through `V44OrganizationPolicyWalletAuthority` in +`packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js`, +deterministic `.bitcode/v44-organization-policy-wallet-authority.json`, +`generate:v44-organization-policy-wallet-authority`, +`check:v44-organization-policy-wallet-authority`, and `check:v44-gate7`. +The BTD authority layer now recognizes Reading spend, source unlock, delivery, +repair, administration, and deposit option synthesis/approval/submission +actions. `OrganizationPolicyWalletAuthority` composes source-safe budget +approval, deposit approval, wallet authority, per-route action statements, +aggregate blockers, authority roots, and disclosure posture. `/read` and +`/deposit` sessions render organization authority state and fail closed on +missing policy, role grants, wallet binding, explicit approval, spend limits, +deposit limits, or critical-source approval. `/packs` projects the same +metadata as searchable governance readback without protected source, raw +prompts, provider responses, private settlement payloads, credentials, wallet +private material, or value-bearing mainnet admission. + ## V44 Gate 8 Enterprise Product UX For Economic Operation Gate 8 must make portfolio, budget, compensation, market signal, and governance @@ -637,7 +654,7 @@ quality, accessibility, visual inspectability, and generated quality evidence. | `.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 | implemented-source-safe | | `.bitcode/v44-btd-btc-compensation-statements.json` | BTD/BTC compensation statements | implemented-source-safe | -| `.bitcode/v44-organization-policy-wallet-authority.json` | organization policy and wallet authority | planned | +| `.bitcode/v44-organization-policy-wallet-authority.json` | organization policy and wallet authority | implemented-source-safe | | `.bitcode/v44-enterprise-economic-ux.json` | enterprise economic UX | planned | | `.bitcode/v44-scaled-network-rehearsal.json` | scaled network rehearsal | planned | | `.bitcode/v44-promotion-readiness-report.json` | promotion readiness | planned | @@ -718,6 +735,10 @@ Gate 6 validates with `pnpm run generate:v44-btd-btc-compensation-statements`, `pnpm run check:v44-btd-btc-compensation-statements`, and `pnpm run check:v44-gate6`. +Gate 7 validates with +`pnpm run generate:v44-organization-policy-wallet-authority`, +`pnpm run check:v44-organization-policy-wallet-authority`, and +`pnpm run check:v44-gate7`. 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`, @@ -794,7 +815,7 @@ Inherited. | `.bitcode/v44-reading-budget-quote-policy.json` | budget and quote policy | implemented-source-safe | | `.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 | implemented-source-safe | -| `.bitcode/v44-organization-policy-wallet-authority.json` | organization policy and wallet authority | planned | +| `.bitcode/v44-organization-policy-wallet-authority.json` | organization policy and wallet authority | implemented-source-safe | | `.bitcode/v44-enterprise-economic-ux.json` | enterprise economic UX | planned | | `.bitcode/v44-scaled-network-rehearsal.json` | scaled rehearsal | planned | | `.bitcode/v44-promotion-readiness-report.json` | promotion readiness | planned | @@ -811,6 +832,7 @@ Gate 4 adds deterministic `.bitcode/v44-reading-budget-quote-policy.json`. Gate 5 adds deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json`. Gate 6 adds deterministic `.bitcode/v44-btd-btc-compensation-statements.json`. +Gate 7 adds deterministic `.bitcode/v44-organization-policy-wallet-authority.json`. ### Shared generated-artifact fields diff --git a/BITCODE_SPEC_V44_DELTA.md b/BITCODE_SPEC_V44_DELTA.md index ea740c16..81220a66 100644 --- a/BITCODE_SPEC_V44_DELTA.md +++ b/BITCODE_SPEC_V44_DELTA.md @@ -3,12 +3,12 @@ ## Status - Version: `V44` -- V44 state: draft Gate 6 BTD/BTC compensation statement work over promoted V43 +- V44 state: draft Gate 7 organization policy wallet authority 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`; Gate 5 adds deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json`; Gate 6 adds deterministic `.bitcode/v44-btd-btc-compensation-statements.json` -- Source parity state: Gate 6 binds package-backed BTD/BTC compensation statements, `/packs` accounting readback, docs, workflow, package script, checker, and protocol/package/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`; Gate 6 adds deterministic `.bitcode/v44-btd-btc-compensation-statements.json`; Gate 7 adds deterministic `.bitcode/v44-organization-policy-wallet-authority.json` +- Source parity state: Gate 7 binds package-backed organization policy wallet authority, BTD deposit authority actions, `/read` and `/deposit` authority readback, `/packs` governance readback, docs, workflow, package scripts, 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` @@ -81,6 +81,18 @@ treasury routes, reconciliation, and repair posture into source-safe `/packs` accounting readback. It does not disclose unpaid source, serialize wallet private material, execute payout, or admit value-bearing mainnet operation. +V44 Gate 7 closes source-safe organization policy and wallet authority over +Reading, Depositing, and Packs inspection. It adds BTD deposit option +synthesis, approval, and submission authority actions; package-backed +`OrganizationPolicyWalletAuthority`; `/read` spend and wallet approval +readback; `/deposit` source criticality, deposit approval, and wallet authority +readback; `/packs` searchable governance readback; deterministic +`.bitcode/v44-organization-policy-wallet-authority.json`; and `check:v44-gate7`. +It does not disclose protected source, serialize wallet private material, +execute value-bearing mainnet movement, or let policy bypass Need review, +Finding Fits, settlement, BTD rights transfer, delivery, or source-to-shares +law. + ## Pre-Implementation Sequence 1. Open V44 spec family, roadmap, checker, package script, workflow posture, @@ -116,6 +128,10 @@ Gate 6 validates with `pnpm run generate:v44-btd-btc-compensation-statements`, `pnpm run check:v44-btd-btc-compensation-statements`, and `pnpm run check:v44-gate6`. +Gate 7 validates with +`pnpm run generate:v44-organization-policy-wallet-authority`, +`pnpm run check:v44-organization-policy-wallet-authority`, and +`pnpm run check:v44-gate7`. 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 2007059f..320d7a0e 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 6 BTD/BTC compensation statement work over promoted V43 +- V44 state: draft notes include Gate 7 organization policy wallet authority 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`; Gate 5 adds deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json`; Gate 6 adds deterministic `.bitcode/v44-btd-btc-compensation-statements.json` -- Source parity state: notes align roadmap, docs, workflow posture, package source, generated artifact, receipt taxonomy, `/packs` portfolio market intelligence and accounting readback, `/read` budget quote policy, and `/deposit` earning supply opportunity intelligence 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`; Gate 6 adds deterministic `.bitcode/v44-btd-btc-compensation-statements.json`; Gate 7 adds deterministic `.bitcode/v44-organization-policy-wallet-authority.json` +- Source parity state: notes align roadmap, docs, workflow posture, package source, generated artifact, receipt taxonomy, `/packs` portfolio market intelligence, accounting and governance readback, `/read` budget quote policy and organization authority, and `/deposit` earning supply opportunity and deposit authority 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` @@ -127,6 +127,18 @@ can render those statements as accounting readback. It cannot disclose unpaid AssetPack source, raw source text, wallet private material, private settlement payloads, raw prompts, provider responses, or value-bearing mainnet authority. +## Gate 7 note + +Gate 7 makes organization policy enforceable and inspectable without changing +protocol law. The route layer can show source-safe organization policy, +approval state, wallet authority, spend limits, deposit limits, critical-source +approval, required denials, and authority roots. BTD authority now covers +deposit option synthesis, approval, and submission alongside Reading spend, +source unlock, delivery, repair, and administration. `/packs` can render that +policy as governance readback. It cannot disclose protected source, unpaid +AssetPack source, raw prompts, provider responses, credentials, wallet private +material, private settlement payloads, or value-bearing mainnet authority. + ## 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 fa1a7c5c..484f9b21 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 6 BTD/BTC compensation statement work +- V44 state: draft parity includes Gate 7 organization policy wallet authority 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`; Gate 4 adds deterministic `.bitcode/v44-reading-budget-quote-policy.json`; Gate 5 adds deterministic `.bitcode/v44-depositor-earnings-supply-opportunities.json`; Gate 6 adds deterministic `.bitcode/v44-btd-btc-compensation-statements.json` -- Source parity state: Gate 6 requires package/route/UI/docs/workflow/checker/test parity for BTD/BTC compensation statements and Packs accounting readback +- 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`; Gate 6 adds deterministic `.bitcode/v44-btd-btc-compensation-statements.json`; Gate 7 adds deterministic `.bitcode/v44-organization-policy-wallet-authority.json` +- Source parity state: Gate 7 requires package/route/UI/docs/workflow/checker/test parity for organization policy wallet authority and Packs governance readback - Scope: parity for V44 enterprise economic operation over promoted V43 product routes - Last fully realized canonical target preserved in source: `V43` @@ -34,7 +34,7 @@ artifacts, workflow checks, and local/staging rehearsal receipts. | 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 through `.bitcode/v44-depositor-earnings-supply-opportunities.json` | implemented | | Accounting statements | BTD/BTC/source-to-shares statements and reconciliation through `.bitcode/v44-btd-btc-compensation-statements.json` | implemented | -| Organization governance | Roles, budgets, wallet authority, source criticality, approvals | drafted | +| Organization governance | Roles, budgets, wallet authority, source criticality, approvals through `.bitcode/v44-organization-policy-wallet-authority.json` | implemented | | Enterprise UX | Dense economic surfaces, proof expansion, responsive/accessibility proof | drafted | | Scaled rehearsal | Many-pack, many-org local/staging-testnet economic rehearsal | drafted | | Promotion readiness | Generated PROVEN, workflow, all V44 artifacts bound | drafted | diff --git a/README.md b/README.md index 612168b0..79972eec 100644 --- a/README.md +++ b/README.md @@ -350,6 +350,18 @@ protected source, raw source text, unpaid AssetPack source, prompts, provider payloads, wallet private material, private settlement payloads, and value-bearing mainnet operation. +V44 Gate 7 adds `V44OrganizationPolicyWalletAuthority`, +`.bitcode/v44-organization-policy-wallet-authority.json`, +`generate:v44-organization-policy-wallet-authority`, +`check:v44-organization-policy-wallet-authority`, and `check:v44-gate7`. It +binds BTD Reading and deposit authority actions to source-safe organization +budget approval, source criticality approval, spend and deposit limits, wallet +authority, `/read` authority readback, `/deposit` authority readback, `/packs` +governance readback, and tests that continue withholding protected source, raw +source text, unpaid AssetPack source, prompts, provider payloads, credentials, +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 40b8ad82..a16ae893 100644 --- a/SPECIFICATIONS_ROADMAP.md +++ b/SPECIFICATIONS_ROADMAP.md @@ -5,8 +5,8 @@ - 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 6 BTD/BTC Accounting And Contributor Compensation Statements. -- Next queued work after V44 Gate 6: organization policy, enterprise UX, scaled local/staging rehearsal, and V44 promotion readiness. +- Current working gate: V44 Gate 7 Organization Policy, Approval, And Wallet Authority. +- Next queued work after V44 Gate 7: 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. @@ -15,6 +15,7 @@ - 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`. - V44 Gate 6 closure anchor: scaled engineering economy now owns package-backed `V44BtdBtcCompensationStatements`, deterministic `.bitcode/v44-btd-btc-compensation-statements.json`, `BtdBtcCompensationStatements`, source-safe BTD range accounting, BTC settlement observations, source-to-shares contributor compensation statements, depositor earning summaries, treasury routes, ledger/database/object-storage reconciliation, repair statements, `/packs` accounting readback, package exports, pipeline/package/UAPI/protocol tests, workflow wiring, and `check:v44-gate6`. +- V44 Gate 7 closure anchor: scaled engineering economy now owns package-backed `V44OrganizationPolicyWalletAuthority`, deterministic `.bitcode/v44-organization-policy-wallet-authority.json`, BTD Reading/deposit authority actions, source-safe organization budget approvals, source criticality approvals, spend/deposit limits, wallet authority, `/read` authority readback, `/deposit` authority readback, `/packs` governance readback, package exports, pipeline/package/UAPI/protocol tests, workflow wiring, and `check:v44-gate7`. - 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 aaf66b90..545f1380 100644 --- a/package.json +++ b/package.json @@ -374,6 +374,9 @@ "generate:v44-btd-btc-compensation-statements": "node scripts/generate-v44-btd-btc-compensation-statements.mjs", "check:v44-btd-btc-compensation-statements": "node scripts/generate-v44-btd-btc-compensation-statements.mjs --check", "check:v44-gate6": "node scripts/check-v44-gate6-btd-btc-compensation-statements.mjs", + "generate:v44-organization-policy-wallet-authority": "node scripts/generate-v44-organization-policy-wallet-authority.mjs", + "check:v44-organization-policy-wallet-authority": "node scripts/generate-v44-organization-policy-wallet-authority.mjs --check", + "check:v44-gate7": "node scripts/check-v44-gate7-organization-policy-wallet-authority.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/btd/__tests__/btd.test.ts b/packages/btd/__tests__/btd.test.ts index 3934c568..5181c3ba 100644 --- a/packages/btd/__tests__/btd.test.ts +++ b/packages/btd/__tests__/btd.test.ts @@ -732,4 +732,64 @@ describe('organization interface authority', () => { ); expect(authority.actionDecision?.decision).toBe('denied'); }); + + it('authorizes deposit admission only with deposit role grant, wallet binding, confirmation, and policy root', () => { + const authority = buildBtdOrganizationPolicyAuthority({ + actorId: 'user-1', + organizationId: 'org-1', + teamId: 'team-core', + memberId: 'member-depositor', + organizationRole: 'admin', + organizationPermissionGrants: ['deposit:submit'], + interfaceSurface: 'terminal', + action: 'submit_deposit', + walletId: 'wallet-depositor', + confirmed: true, + policyId: 'deposit-policy-1', + policyHash: 'deposit-policy-hash-1', + accountAdmitted: true, + interfaceAdmitted: true, + at: '2026-05-29T00:00:00.000Z', + }); + + expect(authority).toMatchObject({ + policyDecision: 'allowed', + depositAdmissionAction: true, + walletBindingState: 'bound', + sourceVisibility: 'source_safe_preview', + policy: { + action: 'submit_deposit', + interfaceSurface: 'terminal', + }, + }); + expect(authority.actionDecision?.decision).toBe('allowed'); + }); + + it('fails deposit approval closed when wallet authority or explicit approval is missing', () => { + const authority = buildBtdOrganizationPolicyAuthority({ + actorId: 'user-1', + organizationId: 'org-1', + organizationRole: 'admin', + organizationPermissionGrants: ['deposit:approve_option'], + interfaceSurface: 'terminal', + action: 'approve_deposit_option', + walletId: null, + confirmed: false, + policyId: 'deposit-policy-1', + policyHash: 'deposit-policy-hash-1', + accountAdmitted: true, + interfaceAdmitted: true, + at: '2026-05-29T00:00:00.000Z', + }); + + expect(authority).toMatchObject({ + policyDecision: 'denied', + depositAdmissionAction: true, + walletBindingState: 'missing', + sourceVisibility: 'source_safe_preview', + }); + expect(authority.denialReasons).toEqual( + expect.arrayContaining(['wallet_binding_missing', 'explicit_confirmation_required']), + ); + }); }); diff --git a/packages/btd/src/authority.ts b/packages/btd/src/authority.ts index 81708b8e..0b72c1f4 100644 --- a/packages/btd/src/authority.ts +++ b/packages/btd/src/authority.ts @@ -23,6 +23,9 @@ export type BtdOrganizationPermissionAction = | 'pay_btc_fee' | 'unlock_asset_pack_source' | 'deliver_asset_pack' + | 'synthesize_deposit_options' + | 'approve_deposit_option' + | 'submit_deposit' | 'repair_projection' | 'administer_organization'; @@ -207,6 +210,7 @@ export interface BtdOrganizationPolicyAuthority { actionDecision: BtdOrganizationInterfaceAuthorityDecision | null; protectedSourceAction: boolean; settlementAdjacentAction: boolean; + depositAdmissionAction: boolean; policyDecision: BtdOrganizationPolicyDecisionKind; denialReason: BtdOrganizationPolicyDenialReason | null; denialReasons: BtdOrganizationPolicyDenialReason[]; @@ -307,6 +311,36 @@ const ACTION_REQUIREMENTS: Record< requiresRepairApproval: false, sourceVisibilityWhenAllowed: 'protected_source_allowed', }, + synthesize_deposit_options: { + minimumRole: 'member', + permissionGrants: ['deposit:synthesize_options'], + requiresWalletBinding: false, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: false, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + approve_deposit_option: { + minimumRole: 'admin', + permissionGrants: ['deposit:approve_option'], + requiresWalletBinding: true, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: true, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, + submit_deposit: { + minimumRole: 'admin', + permissionGrants: ['deposit:submit'], + requiresWalletBinding: true, + requiresRegistryReadAccess: false, + requiresSettledPayment: false, + requiresExplicitConfirmation: true, + requiresRepairApproval: false, + sourceVisibilityWhenAllowed: 'source_safe_preview', + }, repair_projection: { minimumRole: 'admin', permissionGrants: ['settlement:repair_projection'], @@ -342,6 +376,9 @@ const SURFACE_ACTIONS: Record< 'pay_btc_fee', 'unlock_asset_pack_source', 'deliver_asset_pack', + 'synthesize_deposit_options', + 'approve_deposit_option', + 'submit_deposit', 'repair_projection', 'administer_organization', ], @@ -354,6 +391,9 @@ const SURFACE_ACTIONS: Record< 'pay_btc_fee', 'unlock_asset_pack_source', 'deliver_asset_pack', + 'synthesize_deposit_options', + 'approve_deposit_option', + 'submit_deposit', 'repair_projection', 'administer_organization', ], @@ -366,6 +406,9 @@ const SURFACE_ACTIONS: Record< 'pay_btc_fee', 'unlock_asset_pack_source', 'deliver_asset_pack', + 'synthesize_deposit_options', + 'approve_deposit_option', + 'submit_deposit', 'repair_projection', ], chatgpt_app: [ @@ -590,6 +633,10 @@ export function buildBtdOrganizationPolicyAuthority( action === 'unlock_asset_pack_source' || action === 'deliver_asset_pack' || action === 'repair_projection'; + const depositAdmissionAction = + action === 'synthesize_deposit_options' || + action === 'approve_deposit_option' || + action === 'submit_deposit'; const accountAdmitted = input.accountAdmitted === true; const interfaceAdmitted = input.interfaceAdmitted === true; const multiSigPosture = buildMultiSigPosture(input.multiSig); @@ -619,7 +666,7 @@ export function buildBtdOrganizationPolicyAuthority( if (!organizationRole) denialReasons.push('role_missing'); if (!explicitGrantSet.length) denialReasons.push('explicit_permission_grant_required'); if (requirements.requiresWalletBinding && !walletId) denialReasons.push('wallet_binding_missing'); - if ((protectedSourceAction || settlementAdjacentAction) && !policyHash && !policyId) { + if ((protectedSourceAction || settlementAdjacentAction || depositAdmissionAction) && !policyHash && !policyId) { denialReasons.push('policy_missing'); } if (!interfaceAdmitted) denialReasons.push('interface_not_admitted'); @@ -666,6 +713,7 @@ export function buildBtdOrganizationPolicyAuthority( actionDecision, protectedSourceAction, settlementAdjacentAction, + depositAdmissionAction, policyDecision, denialReason: uniqueDenialReasons[0] ?? null, denialReasons: uniqueDenialReasons, diff --git a/packages/pipelines/asset-pack/package.json b/packages/pipelines/asset-pack/package.json index 97acc104..1f2fb465 100644 --- a/packages/pipelines/asset-pack/package.json +++ b/packages/pipelines/asset-pack/package.json @@ -17,6 +17,7 @@ "./deposit-asset-pack-option-admission": "./src/deposit-asset-pack-option-admission.ts", "./depositor-earning-supply-intelligence": "./src/depositor-earning-supply-intelligence.ts", "./btd-btc-compensation-statements": "./src/btd-btc-compensation-statements.ts", + "./organization-policy-wallet-authority": "./src/organization-policy-wallet-authority.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__/organization-policy-wallet-authority.test.ts b/packages/pipelines/asset-pack/src/__tests__/organization-policy-wallet-authority.test.ts new file mode 100644 index 00000000..d2f5c136 --- /dev/null +++ b/packages/pipelines/asset-pack/src/__tests__/organization-policy-wallet-authority.test.ts @@ -0,0 +1,133 @@ +import { + assertOrganizationPolicyWalletAuthoritySourceSafe, + buildOrganizationPolicyWalletAuthority, +} from '../organization-policy-wallet-authority'; + +describe('OrganizationPolicyWalletAuthority', () => { + it('allows budgeted Reading BTC payment with role, grant, wallet authority, and approval', () => { + const statement = buildOrganizationPolicyWalletAuthority({ + route: '/read', + actorId: 'user-1', + organizationId: 'org-1', + teamId: 'team-core', + memberId: 'member-buyer', + organizationRole: 'admin', + organizationPermissionGrants: [ + 'reading:request', + 'reading:review_need', + 'reading:request_finding_fits', + 'asset_pack:review_preview', + 'settlement:pay_btc_fee', + ], + walletId: 'wallet-reader', + walletAuthorityPresent: true, + quoteSats: 12_500, + budgetEnvelopeSats: 50_000, + approvalThresholdSats: 10_000, + procurementApproved: true, + buyerAuthorized: true, + accountAdmitted: true, + interfaceAdmitted: true, + createdAt: '2026-05-29T00:00:00.000Z', + }); + + expect(statement.schema).toBe('bitcode.organization.policy-wallet-authority'); + expect(statement.route).toBe('/read'); + expect(statement.budgetApproval.state).toBe('within-limit'); + expect(statement.walletAuthority.state).toBe('verified'); + expect(statement.actionStatements.find((entry) => entry.action === 'pay_btc_fee')).toMatchObject({ + requiredForRoute: true, + allowed: true, + }); + expect(statement.actionStatements.find((entry) => entry.action === 'deliver_asset_pack')).toMatchObject({ + requiredForRoute: false, + allowed: false, + }); + expect(statement.aggregate.state).toBe('allowed'); + expect(assertOrganizationPolicyWalletAuthoritySourceSafe(statement)).toEqual({ + admitted: true, + reason: 'source_safe_organization_policy_wallet_authority', + }); + }); + + it('fails Reading payment closed when wallet authority is missing', () => { + const statement = buildOrganizationPolicyWalletAuthority({ + route: '/read', + actorId: 'user-1', + organizationId: 'org-1', + organizationRole: 'admin', + organizationPermissionGrants: ['settlement:pay_btc_fee', 'reading:request'], + quoteSats: 10_000, + budgetEnvelopeSats: 50_000, + approvalThresholdSats: 5_000, + procurementApproved: true, + buyerAuthorized: true, + accountAdmitted: true, + interfaceAdmitted: true, + }); + + const payment = statement.actionStatements.find((entry) => entry.action === 'pay_btc_fee'); + + expect(statement.aggregate.state).toBe('denied'); + expect(payment?.allowed).toBe(false); + expect(payment?.denialReasons).toEqual(expect.arrayContaining(['wallet_binding_missing'])); + expect(assertOrganizationPolicyWalletAuthoritySourceSafe(statement).admitted).toBe(true); + }); + + it('allows deposit submission only after source criticality, deposit approval, wallet, and policy admit it', () => { + const statement = buildOrganizationPolicyWalletAuthority({ + route: '/deposit', + actorId: 'user-1', + organizationId: 'org-1', + teamId: 'team-supply', + memberId: 'member-depositor', + organizationRole: 'admin', + organizationPermissionGrants: [ + 'deposit:synthesize_options', + 'deposit:approve_option', + 'deposit:submit', + ], + walletId: 'wallet-depositor', + walletAuthorityPresent: true, + sourceCriticalityState: 'sub-critical', + sourceCriticalityApproved: true, + depositApproved: true, + expectedSettlementSats: 18_000, + depositLimitSats: 100_000, + accountAdmitted: true, + interfaceAdmitted: true, + }); + + expect(statement.depositApproval.state).toBe('sub-critical-approved'); + expect(statement.actionStatements.every((entry) => entry.allowed)).toBe(true); + expect(statement.aggregate.state).toBe('allowed'); + expect(statement.disclosure.protectedSourceVisible).toBe(false); + }); + + it('blocks critical source deposit approval without exposing source-bearing payloads', () => { + const statement = buildOrganizationPolicyWalletAuthority({ + route: '/deposit', + actorId: 'user-1', + organizationId: 'org-1', + organizationRole: 'admin', + organizationPermissionGrants: [ + 'deposit:synthesize_options', + 'deposit:approve_option', + 'deposit:submit', + ], + walletId: 'wallet-depositor', + walletAuthorityPresent: true, + sourceCriticalityState: 'blocked-critical-source', + sourceCriticalityApproved: false, + depositApproved: true, + expectedSettlementSats: 18_000, + accountAdmitted: true, + interfaceAdmitted: true, + }); + + expect(statement.depositApproval.state).toBe('critical-source-blocked'); + expect(statement.aggregate.state).toBe('denied'); + expect(statement.aggregate.blockers).toContain('critical source cannot be deposited without policy repair'); + expect(assertOrganizationPolicyWalletAuthoritySourceSafe(statement).admitted).toBe(true); + }); +}); diff --git a/packages/pipelines/asset-pack/src/index.ts b/packages/pipelines/asset-pack/src/index.ts index 444b2117..62bb22f8 100644 --- a/packages/pipelines/asset-pack/src/index.ts +++ b/packages/pipelines/asset-pack/src/index.ts @@ -444,6 +444,7 @@ export * from './deposit-asset-pack-option-policy'; export * from './deposit-asset-pack-option-admission'; export * from './depositor-earning-supply-intelligence'; export * from './btd-btc-compensation-statements'; +export * from './organization-policy-wallet-authority'; export * from './embedding-config'; export * from './asset-pack-disclosure'; export * from './read-need-review-resynthesis'; diff --git a/packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts b/packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts new file mode 100644 index 00000000..889b1776 --- /dev/null +++ b/packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts @@ -0,0 +1,622 @@ +import { + buildBtdOrganizationPolicyAuthority, + type BtdAccessDecision, + type BtdInterfaceAuthoritySurface, + type BtdOrganizationPermissionAction, + type BtdOrganizationPolicyAuthority, + type BtdOrganizationPolicyMultiSigInput, + type BtdOrganizationRole, + type BtdRepairApprovalState, + type BtdSettlementAuthorityState, +} from '@bitcode/btd'; + +export type OrganizationPolicyRoute = '/read' | '/deposit' | '/packs'; + +export type OrganizationPolicySpendState = + | 'not-applicable' + | 'within-limit' + | 'approval-required' + | 'limit-exceeded'; + +export type OrganizationPolicyDepositState = + | 'not-applicable' + | 'sub-critical-approved' + | 'source-criticality-approval-required' + | 'critical-source-blocked' + | 'deposit-approval-required' + | 'limit-exceeded'; + +export type OrganizationPolicyWalletState = + | 'verified' + | 'missing' + | 'not-required'; + +export type OrganizationPolicyAggregateState = + | 'allowed' + | 'denied' + | 'repair-required'; + +export type OrganizationSourceCriticalityState = + | 'sub-critical' + | 'review-warning' + | 'blocked-critical-source' + | 'not-applicable'; + +export interface OrganizationPolicyWalletAuthorityInput { + createdAt?: string | null; + route?: OrganizationPolicyRoute | null; + actorId?: string | null; + organizationId?: string | null; + teamId?: string | null; + memberId?: string | null; + organizationRole?: BtdOrganizationRole | string | null; + organizationPermissionGrants?: string[] | null; + interfaceSurface?: BtdInterfaceAuthoritySurface | null; + accountAdmitted?: boolean | null; + interfaceAdmitted?: boolean | null; + policyId?: string | null; + policyHash?: string | null; + walletId?: string | null; + walletAuthorityPresent?: boolean | null; + budgetEnvelopeSats?: number | null; + approvalThresholdSats?: number | null; + spendLimitSats?: number | null; + quoteSats?: number | null; + procurementApproved?: boolean | null; + buyerAuthorized?: boolean | null; + expectedSettlementSats?: number | null; + depositLimitSats?: number | null; + depositApproved?: boolean | null; + sourceCriticalityApproved?: boolean | null; + sourceCriticalityState?: OrganizationSourceCriticalityState | null; + settlementState?: BtdSettlementAuthorityState | null; + readAccessDecision?: BtdAccessDecision | null; + repairApprovalState?: BtdRepairApprovalState | null; + multiSig?: BtdOrganizationPolicyMultiSigInput | null; + targetAnchor?: string | null; + recoveryRoute?: string | null; +} + +export interface OrganizationPolicyActionStatement { + schema: 'bitcode.organization.policy-action-statement'; + action: BtdOrganizationPermissionAction; + route: OrganizationPolicyRoute; + requiredForRoute: boolean; + authority: BtdOrganizationPolicyAuthority; + allowed: boolean; + denialReasons: string[]; + sourceVisibility: string; + statementRoot: string; +} + +export interface OrganizationPolicyWalletAuthority { + schema: 'bitcode.organization.policy-wallet-authority'; + statement: 'OrganizationPolicyWalletAuthority'; + createdAt: string; + route: OrganizationPolicyRoute; + organization: { + actorId: string | null; + organizationId: string | null; + teamId: string | null; + memberId: string | null; + role: BtdOrganizationRole | null; + permissionGrantCount: number; + }; + budgetApproval: { + state: OrganizationPolicySpendState; + quoteSats: number; + budgetEnvelopeSats: number; + approvalThresholdSats: number; + spendLimitSats: number; + procurementApproved: boolean; + buyerAuthorized: boolean; + blockers: string[]; + policyRoot: string; + }; + depositApproval: { + state: OrganizationPolicyDepositState; + expectedSettlementSats: number; + depositLimitSats: number; + depositApproved: boolean; + sourceCriticalityApproved: boolean; + sourceCriticalityState: OrganizationSourceCriticalityState; + blockers: string[]; + policyRoot: string; + }; + walletAuthority: { + state: OrganizationPolicyWalletState; + walletId: string | null; + walletAuthorityPresent: boolean; + serverCustody: false; + privateMaterialVisible: false; + policyRoot: string; + }; + actionStatements: OrganizationPolicyActionStatement[]; + aggregate: { + state: OrganizationPolicyAggregateState; + allowedActionCount: number; + deniedActionCount: number; + requiredDeniedActionCount: number; + blockerCount: number; + blockers: string[]; + budgetReady: boolean; + depositReady: boolean; + walletReady: boolean; + authorityRoot: string; + }; + disclosure: { + sourceSafeMetadataOnly: true; + protectedSourceVisible: false; + rawSourceTextVisible: false; + unpaidAssetPackSourceVisible: false; + rawPromptVisible: false; + interpolatedPromptVisible: false; + rawProviderResponseVisible: false; + walletPrivateMaterialVisible: false; + settlementPrivatePayloadVisible: false; + valueBearingMainnetAdmitted: false; + }; + roots: { + policyRoot: string; + budgetPolicyRoot: string; + depositPolicyRoot: string; + walletAuthorityRoot: string; + actionStatementRoots: string[]; + authorityRoot: string; + }; +} + +const ROUTE_ACTIONS: Record = { + '/read': [ + 'request_read', + 'review_need', + 'request_finding_fits', + 'review_asset_pack_preview', + 'pay_btc_fee', + 'unlock_asset_pack_source', + 'deliver_asset_pack', + ], + '/deposit': [ + 'synthesize_deposit_options', + 'approve_deposit_option', + 'submit_deposit', + ], + '/packs': [ + 'read_transaction', + 'repair_projection', + 'administer_organization', + ], +}; + +const FORBIDDEN_SOURCE_MARKERS = [ + 'PRIVATE_SOURCE_DO_NOT_SERIALIZE', + `BEGIN_${'PRIVATE'}_KEY`, + 'wallet_private_material', + 'raw_provider_response', + 'unpaid_assetpack_source', + 'protected source body', + 'private_settlement_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 stableDigest(value: string) { + let hash = 2166136261; + for (let index = 0; index < value.length; index += 1) { + hash ^= value.charCodeAt(index); + hash = Math.imul(hash, 16777619); + } + return (hash >>> 0).toString(16).padStart(8, '0'); +} + +function root(prefix: string, value: unknown) { + return `${prefix}:${stableDigest(stableStringify(value))}`; +} + +function normalizedText(value: string | null | undefined) { + const normalized = value?.trim(); + return normalized ? normalized : null; +} + +function positiveInteger(value: number | null | undefined, fallback: number) { + const numeric = Number(value ?? fallback); + if (!Number.isFinite(numeric) || numeric < 0) return fallback; + return Math.round(numeric); +} + +function normalizeRoute(value: OrganizationPolicyRoute | null | undefined): OrganizationPolicyRoute { + return value === '/deposit' || value === '/packs' ? value : '/read'; +} + +function normalizeRole(value: BtdOrganizationRole | string | null | undefined): BtdOrganizationRole | null { + return value === 'viewer' || value === 'member' || value === 'admin' || value === 'owner' + ? value + : null; +} + +function uniqueStrings(values: string[] | null | undefined) { + return Array.from( + new Set((values || []).map((value) => value.trim()).filter(Boolean)), + ); +} + +function spendPolicy(input: OrganizationPolicyWalletAuthorityInput) { + const quoteSats = positiveInteger(input.quoteSats, 0); + const budgetEnvelopeSats = positiveInteger(input.budgetEnvelopeSats, 250_000); + const approvalThresholdSats = positiveInteger(input.approvalThresholdSats, 100_000); + const spendLimitSats = positiveInteger(input.spendLimitSats, budgetEnvelopeSats); + const procurementApproved = input.procurementApproved === true; + const buyerAuthorized = input.buyerAuthorized !== false; + const blockers: string[] = []; + let state: OrganizationPolicySpendState = 'not-applicable'; + + if (quoteSats > 0) { + if (quoteSats > spendLimitSats || quoteSats > budgetEnvelopeSats) { + state = 'limit-exceeded'; + blockers.push('quote exceeds organization spend limit'); + } else if (quoteSats >= approvalThresholdSats && !procurementApproved) { + state = 'approval-required'; + blockers.push('procurement approval required'); + } else { + state = 'within-limit'; + } + + if (!buyerAuthorized) blockers.push('buyer authorization required'); + } + + const policyRoot = root('organization-budget-policy', { + quoteSats, + budgetEnvelopeSats, + approvalThresholdSats, + spendLimitSats, + procurementApproved, + buyerAuthorized, + state, + blockers, + }); + + return { + state, + quoteSats, + budgetEnvelopeSats, + approvalThresholdSats, + spendLimitSats, + procurementApproved, + buyerAuthorized, + blockers, + policyRoot, + }; +} + +function depositPolicy(input: OrganizationPolicyWalletAuthorityInput) { + const sourceCriticalityState = input.sourceCriticalityState || 'not-applicable'; + const expectedSettlementSats = positiveInteger(input.expectedSettlementSats, 0); + const depositLimitSats = positiveInteger(input.depositLimitSats, 1_000_000); + const sourceCriticalityApproved = + input.sourceCriticalityApproved === true || sourceCriticalityState === 'sub-critical'; + const depositApproved = input.depositApproved === true; + const blockers: string[] = []; + let state: OrganizationPolicyDepositState = 'not-applicable'; + + if (sourceCriticalityState !== 'not-applicable' || expectedSettlementSats > 0 || depositApproved) { + if (sourceCriticalityState === 'blocked-critical-source') { + state = 'critical-source-blocked'; + blockers.push('critical source cannot be deposited without policy repair'); + } else if (!sourceCriticalityApproved) { + state = 'source-criticality-approval-required'; + blockers.push('source criticality approval required'); + } else if (expectedSettlementSats > depositLimitSats) { + state = 'limit-exceeded'; + blockers.push('expected settlement exceeds organization deposit limit'); + } else if (!depositApproved) { + state = 'deposit-approval-required'; + blockers.push('deposit approval required'); + } else { + state = 'sub-critical-approved'; + } + } + + const policyRoot = root('organization-deposit-policy', { + sourceCriticalityState, + expectedSettlementSats, + depositLimitSats, + sourceCriticalityApproved, + depositApproved, + state, + blockers, + }); + + return { + state, + expectedSettlementSats, + depositLimitSats, + depositApproved, + sourceCriticalityApproved, + sourceCriticalityState, + blockers, + policyRoot, + }; +} + +function walletPolicy(input: OrganizationPolicyWalletAuthorityInput) { + const walletId = normalizedText(input.walletId); + const walletAuthorityPresent = input.walletAuthorityPresent === true || Boolean(walletId); + const state: OrganizationPolicyWalletState = walletAuthorityPresent + ? 'verified' + : 'missing'; + const policyRoot = root('organization-wallet-authority', { + walletId, + walletAuthorityPresent, + state, + serverCustody: false, + }); + + return { + state, + walletId, + walletAuthorityPresent, + serverCustody: false as const, + privateMaterialVisible: false as const, + policyRoot, + }; +} + +function requiredActionsForRoute( + route: OrganizationPolicyRoute, + input: OrganizationPolicyWalletAuthorityInput, +) { + const required = new Set(); + if (route === '/read') { + required.add('request_read'); + if (positiveInteger(input.quoteSats, 0) > 0) required.add('pay_btc_fee'); + if (input.settlementState === 'settled') { + required.add('unlock_asset_pack_source'); + required.add('deliver_asset_pack'); + } + } else if (route === '/deposit') { + required.add('synthesize_deposit_options'); + if (input.depositApproved || input.sourceCriticalityApproved) { + required.add('approve_deposit_option'); + required.add('submit_deposit'); + } + } else { + required.add('read_transaction'); + } + return required; +} + +function confirmedForAction( + action: BtdOrganizationPermissionAction, + input: OrganizationPolicyWalletAuthorityInput, + budget: ReturnType, + deposit: ReturnType, +) { + if (action === 'pay_btc_fee') { + return ( + budget.state === 'within-limit' && + budget.buyerAuthorized && + (budget.quoteSats < budget.approvalThresholdSats || budget.procurementApproved) + ); + } + if (action === 'unlock_asset_pack_source' || action === 'deliver_asset_pack') { + return input.settlementState === 'settled' && budget.buyerAuthorized; + } + if (action === 'approve_deposit_option' || action === 'submit_deposit') { + return deposit.state === 'sub-critical-approved'; + } + if (action === 'repair_projection') return input.repairApprovalState === 'approved'; + if (action === 'administer_organization') return input.accountAdmitted === true; + return true; +} + +function buildActionStatement(input: { + action: BtdOrganizationPermissionAction; + route: OrganizationPolicyRoute; + requiredForRoute: boolean; + source: OrganizationPolicyWalletAuthorityInput; + budget: ReturnType; + deposit: ReturnType; + wallet: ReturnType; + policyId: string | null; + policyHash: string; + createdAt: string; +}): OrganizationPolicyActionStatement { + const authority = buildBtdOrganizationPolicyAuthority({ + actorId: input.source.actorId, + organizationId: input.source.organizationId, + teamId: input.source.teamId, + memberId: input.source.memberId, + organizationRole: input.source.organizationRole, + organizationPermissionGrants: input.source.organizationPermissionGrants, + interfaceSurface: input.source.interfaceSurface || 'terminal', + action: input.action, + walletId: input.wallet.walletAuthorityPresent ? input.wallet.walletId : null, + readAccessDecision: input.source.readAccessDecision || null, + settlementState: input.source.settlementState || 'not_required', + confirmed: confirmedForAction(input.action, input.source, input.budget, input.deposit), + repairApprovalState: input.source.repairApprovalState || 'not_required', + targetAnchor: input.source.targetAnchor || `${input.route}:${input.action}`, + policyId: input.policyId, + policyHash: input.policyHash, + accountAdmitted: input.source.accountAdmitted === true, + interfaceAdmitted: input.source.interfaceAdmitted !== false, + multiSig: input.source.multiSig || null, + recoveryRoute: input.source.recoveryRoute || input.route, + at: input.createdAt, + }); + const withoutRoot = { + schema: 'bitcode.organization.policy-action-statement' as const, + action: input.action, + route: input.route, + requiredForRoute: input.requiredForRoute, + authority, + allowed: authority.policyDecision === 'allowed', + denialReasons: authority.denialReasons, + sourceVisibility: authority.sourceVisibility, + }; + + return { + ...withoutRoot, + statementRoot: root('organization-policy-action-statement', withoutRoot), + }; +} + +export function buildOrganizationPolicyWalletAuthority( + input: OrganizationPolicyWalletAuthorityInput = {}, +): OrganizationPolicyWalletAuthority { + const createdAt = normalizedText(input.createdAt) || '2026-05-29T00:00:00.000Z'; + const route = normalizeRoute(input.route); + const permissionGrants = uniqueStrings(input.organizationPermissionGrants); + const budgetApproval = spendPolicy(input); + const depositApproval = depositPolicy(input); + const walletAuthority = walletPolicy(input); + const policyRoot = root('organization-policy-wallet-authority-policy', { + route, + actorId: normalizedText(input.actorId), + organizationId: normalizedText(input.organizationId), + teamId: normalizedText(input.teamId), + memberId: normalizedText(input.memberId), + organizationRole: normalizeRole(input.organizationRole), + permissionGrants, + budgetPolicyRoot: budgetApproval.policyRoot, + depositPolicyRoot: depositApproval.policyRoot, + walletAuthorityRoot: walletAuthority.policyRoot, + }); + const policyHash = normalizedText(input.policyHash) || policyRoot; + const policyId = normalizedText(input.policyId) || `organization-policy:${route.slice(1)}`; + const requiredActions = requiredActionsForRoute(route, input); + const normalizedInput = { + ...input, + organizationPermissionGrants: permissionGrants, + }; + const actionStatements = ROUTE_ACTIONS[route].map((action) => + buildActionStatement({ + action, + route, + requiredForRoute: requiredActions.has(action), + source: normalizedInput, + budget: budgetApproval, + deposit: depositApproval, + wallet: walletAuthority, + policyId, + policyHash, + createdAt, + }), + ); + const deniedActionCount = actionStatements.filter((statement) => !statement.allowed).length; + const requiredDeniedActionCount = actionStatements.filter( + (statement) => statement.requiredForRoute && !statement.allowed, + ).length; + const blockers = Array.from( + new Set([ + ...budgetApproval.blockers, + ...depositApproval.blockers, + ...actionStatements + .filter((statement) => statement.requiredForRoute && !statement.allowed) + .flatMap((statement) => statement.denialReasons.map((reason) => `${statement.action}:${reason}`)), + ]), + ); + const repairRequired = actionStatements.some((statement) => + statement.denialReasons.includes('repair_approval_required') || + statement.denialReasons.includes('multisig_approval_required'), + ); + const aggregateWithoutRoot = { + state: repairRequired ? 'repair-required' as const : blockers.length ? 'denied' as const : 'allowed' as const, + allowedActionCount: actionStatements.filter((statement) => statement.allowed).length, + deniedActionCount, + requiredDeniedActionCount, + blockerCount: blockers.length, + blockers, + budgetReady: budgetApproval.blockers.length === 0, + depositReady: depositApproval.blockers.length === 0, + walletReady: walletAuthority.state === 'verified', + }; + const authorityRoot = root('organization-policy-wallet-authority', { + policyRoot, + route, + createdAt, + actionStatementRoots: actionStatements.map((statement) => statement.statementRoot), + aggregateWithoutRoot, + }); + + return { + schema: 'bitcode.organization.policy-wallet-authority', + statement: 'OrganizationPolicyWalletAuthority', + createdAt, + route, + organization: { + actorId: normalizedText(input.actorId), + organizationId: normalizedText(input.organizationId), + teamId: normalizedText(input.teamId), + memberId: normalizedText(input.memberId), + role: normalizeRole(input.organizationRole), + permissionGrantCount: permissionGrants.length, + }, + budgetApproval, + depositApproval, + walletAuthority, + actionStatements, + aggregate: { + ...aggregateWithoutRoot, + authorityRoot, + }, + disclosure: { + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawSourceTextVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + interpolatedPromptVisible: false, + rawProviderResponseVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + valueBearingMainnetAdmitted: false, + }, + roots: { + policyRoot, + budgetPolicyRoot: budgetApproval.policyRoot, + depositPolicyRoot: depositApproval.policyRoot, + walletAuthorityRoot: walletAuthority.policyRoot, + actionStatementRoots: actionStatements.map((statement) => statement.statementRoot), + authorityRoot, + }, + }; +} + +export function assertOrganizationPolicyWalletAuthoritySourceSafe( + statement: OrganizationPolicyWalletAuthority, +) { + const serialized = JSON.stringify(statement); + const lower = serialized.toLowerCase(); + const sourceSafe = + statement.schema === 'bitcode.organization.policy-wallet-authority' && + statement.statement === 'OrganizationPolicyWalletAuthority' && + statement.disclosure.sourceSafeMetadataOnly === true && + statement.disclosure.protectedSourceVisible === false && + statement.disclosure.rawSourceTextVisible === false && + statement.disclosure.unpaidAssetPackSourceVisible === false && + statement.disclosure.rawPromptVisible === false && + statement.disclosure.interpolatedPromptVisible === false && + statement.disclosure.rawProviderResponseVisible === false && + statement.disclosure.walletPrivateMaterialVisible === false && + statement.disclosure.settlementPrivatePayloadVisible === false && + statement.disclosure.valueBearingMainnetAdmitted === false && + statement.walletAuthority.serverCustody === false && + statement.walletAuthority.privateMaterialVisible === false && + FORBIDDEN_SOURCE_MARKERS.every((marker) => !lower.includes(marker.toLowerCase())); + + return { + admitted: sourceSafe, + reason: sourceSafe + ? 'source_safe_organization_policy_wallet_authority' + : 'organization_policy_wallet_authority_source_safety_boundary_violation', + }; +} diff --git a/packages/protocol/README.md b/packages/protocol/README.md index db2d3414..3e42f448 100644 --- a/packages/protocol/README.md +++ b/packages/protocol/README.md @@ -243,6 +243,17 @@ depositor earning summaries, treasury routes, ledger/database/object-storage reconciliation, repair statements, `/packs` accounting readback, package exports, workflow wiring, and source-safety tests. +V44 Gate 7 adds `V44OrganizationPolicyWalletAuthority` through +`packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js`, +`packages/protocol/test/v44-organization-policy-wallet-authority.test.js`, +`.bitcode/v44-organization-policy-wallet-authority.json`, +`generate:v44-organization-policy-wallet-authority`, +`check:v44-organization-policy-wallet-authority`, and `check:v44-gate7`. It +binds BTD Reading and deposit authority actions to source-safe organization +policy, budget approval, source criticality approval, spend/deposit limits, +wallet authority, `/read` and `/deposit` authority readback, `/packs` +governance readback, package exports, workflow wiring, 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/v43-cross-route-rehearsal-telemetry-repair.js b/packages/protocol/src/canonical/v43-cross-route-rehearsal-telemetry-repair.js index 4fd7f7aa..9b46656e 100644 --- a/packages/protocol/src/canonical/v43-cross-route-rehearsal-telemetry-repair.js +++ b/packages/protocol/src/canonical/v43-cross-route-rehearsal-telemetry-repair.js @@ -275,7 +275,7 @@ function buildPredicateResults(repoRoot) { predicateResult('gate7-artifact-passed', SOURCE_ROOTS.gate7Artifact, artifactPassed(repoRoot, SOURCE_ROOTS.gate7Artifact, 'v43-deposit-option-admission')), predicateResult('gate8-artifact-passed', SOURCE_ROOTS.gate8Artifact, artifactPassed(repoRoot, SOURCE_ROOTS.gate8Artifact, 'v43-route-ux-product-excellence')), predicateResult('deposit-route-covers-admission', SOURCE_ROOTS.depositClient, sources.depositClient.includes('pipeline:deposit-option-admission') && sources.depositClient.includes('DepositAssetPackOptionAdmissionReport')), - predicateResult('deposit-model-covers-repair-boundaries', SOURCE_ROOTS.depositModel, sources.depositModel.includes('sourceCriticalityDemandRoiPolicyOwnedByGate6') && sources.depositModel.includes('admissionAndIndexingOwnedByGate7')), + predicateResult('deposit-model-covers-repair-boundaries', SOURCE_ROOTS.depositModel, sources.depositModel.includes('sourceCriticalityDemandRoiPolicyPresent') && sources.depositModel.includes('sourceCriticalityDemandRoiPolicySourceSafe') && sources.depositModel.includes('admissionAndIndexingPolicyPresent')), predicateResult('read-route-covers-two-pipeline-path', SOURCE_ROOTS.readModel, sources.readModel.includes('ReadNeedComprehensionSynthesis') && sources.readModel.includes('ReadFitsFindingSynthesis') && sources.readModel.includes('deliveryRequiresPaidReadRights')), predicateResult('read-client-covers-preview-settlement-delivery', SOURCE_ROOTS.readClient, sources.readClient.includes('Finding Fits') && sources.readClient.includes('Withheld until paid') && sources.readClient.includes('settlement readback')), predicateResult('packs-route-covers-activity-repair', SOURCE_ROOTS.packsClient, sources.packsClient.includes('PackActivity') && sources.packsClient.includes('repairState') && sources.packsClient.includes('compensationState')), diff --git a/packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js b/packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js new file mode 100644 index 00000000..1de3c53b --- /dev/null +++ b/packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js @@ -0,0 +1,301 @@ +// @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_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH = + '.bitcode/v44-organization-policy-wallet-authority.json'; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SCHEMA_ID = + 'bitcode.v44.organizationPolicyWalletAuthority.v1'; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_VERSION = 'V44'; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_CURRENT_TARGET = 'V43'; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SOURCE_SAFETY_VERDICT = + 'source-safe-organization-policy-wallet-authority-metadata'; + +export const V44_ORGANIZATION_POLICY_OBJECT_IDS = Object.freeze([ + 'OrganizationPolicyWalletAuthority', + 'OrganizationPolicyActionStatement', + 'OrganizationBudgetApprovalPolicy', + 'OrganizationDepositApprovalPolicy', + 'OrganizationWalletAuthorityStatement', + 'OrganizationGovernanceDecision', + 'PackActivityGovernanceReadback', + 'BtdOrganizationPolicyAuthority', +]); + +export const V44_ORGANIZATION_POLICY_ROUTE_IDS = Object.freeze([ + '/read', + '/deposit', + '/packs', +]); + +export const V44_ORGANIZATION_POLICY_ACTION_IDS = Object.freeze([ + 'request_read', + 'review_need', + 'request_finding_fits', + 'review_asset_pack_preview', + 'pay_btc_fee', + 'unlock_asset_pack_source', + 'deliver_asset_pack', + 'synthesize_deposit_options', + 'approve_deposit_option', + 'submit_deposit', + 'read_transaction', + 'repair_projection', + 'administer_organization', +]); + +export const V44_ORGANIZATION_POLICY_STATE_IDS = Object.freeze([ + 'allowed', + 'denied', + 'repair-required', + 'within-limit', + 'approval-required', + 'limit-exceeded', + 'sub-critical-approved', + 'source-criticality-approval-required', + 'critical-source-blocked', + 'deposit-approval-required', + 'verified', + 'missing', + 'not-required', +]); + +export const V44_ORGANIZATION_POLICY_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', + btdAuthority: 'packages/btd/src/authority.ts', + btdAuthorityTest: 'packages/btd/__tests__/btd.test.ts', + packageHelper: 'packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts', + packageHelperTest: 'packages/pipelines/asset-pack/src/__tests__/organization-policy-wallet-authority.test.ts', + assetPackPackageIndex: 'packages/pipelines/asset-pack/src/index.ts', + assetPackPackageManifest: 'packages/pipelines/asset-pack/package.json', + readRouteModel: 'uapi/app/read/read-route-model.ts', + readRouteTest: 'uapi/tests/readRouteModel.test.ts', + readClient: 'uapi/app/read/ReadPageClient.tsx', + readClientTest: 'uapi/tests/readPageClient.test.tsx', + depositRouteModel: 'uapi/app/deposit/deposit-route-model.ts', + depositRouteTest: 'uapi/tests/depositRouteModel.test.ts', + depositClient: 'uapi/app/deposit/DepositPageClient.tsx', + depositClientTest: 'uapi/tests/depositPageClient.test.tsx', + packActivityModel: 'uapi/components/base/bitcode/activity/pack-activity-model.ts', + packsClient: 'uapi/app/packs/PacksPageClient.tsx', + packActivityModelTest: 'uapi/tests/packActivityModel.test.ts', + packsClientTest: 'uapi/tests/packsPageClient.test.tsx', + packageIndex: 'packages/protocol/src/index.js', + packageTypes: 'packages/protocol/src/index.d.ts', + packageSource: 'packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js', + packageTest: 'packages/protocol/test/v44-organization-policy-wallet-authority.test.js', + generator: 'scripts/generate-v44-organization-policy-wallet-authority.mjs', + checker: 'scripts/check-v44-gate7-organization-policy-wallet-authority.mjs', +}); + +function digest(value) { + return crypto.createHash('sha256').update(value).digest('hex').slice(0, 24); +} + +function readSource(repoRoot, sourcePath) { + const absolutePath = path.join(repoRoot, sourcePath); + return existsSync(absolutePath) ? readFileSync(absolutePath, 'utf8') : ''; +} + +function predicateResult(id, sourcePath, passed) { + return { id, sourcePath, passed: Boolean(passed) }; +} + +export const V44_ORGANIZATION_POLICY_ROWS = Object.freeze([ + { + rowId: 'btd-deposit-actions', + owner: SOURCE_ROOTS.btdAuthority, + contract: + 'BTD organization authority covers deposit option synthesis, approval, and submission beside Reading spend, source unlock, delivery, repair, and administration.', + requiredFields: ['synthesize_deposit_options', 'approve_deposit_option', 'submit_deposit', 'wallet_binding_missing'], + }, + { + rowId: 'source-safe-governance-statement', + owner: SOURCE_ROOTS.packageHelper, + contract: + 'OrganizationPolicyWalletAuthority composes budget approval, deposit approval, wallet authority, action statements, aggregate blockers, roots, and source-safety disclosure.', + requiredFields: ['OrganizationPolicyWalletAuthority', 'budgetApproval', 'depositApproval', 'walletAuthority'], + }, + { + rowId: 'read-route-authority', + owner: SOURCE_ROOTS.readRouteModel, + contract: + '/read binds organization policy wallet authority to budgeted quotes, buyer approval, wallet authority, and source-safe route assertions.', + requiredFields: ['organizationPolicyWalletAuthority', 'pay_btc_fee', 'source_safe_read_route_metadata'], + }, + { + rowId: 'deposit-route-authority', + owner: SOURCE_ROOTS.depositRouteModel, + contract: + '/deposit binds source criticality approval, deposit approval, wallet authority, and deposit admission policy into route state.', + requiredFields: ['organizationPolicyWalletAuthority', 'sourceCriticalityApproved', 'admissionAndIndexingPolicyPresent'], + }, + { + rowId: 'packs-governance-readback', + owner: SOURCE_ROOTS.packActivityModel, + contract: + '/packs projects source-safe governance readback into searchable activity detail without serializing secrets or protected source.', + requiredFields: ['PackActivityGovernanceReadback', 'buildGovernanceReadback', 'authorityRoot'], + }, + { + rowId: 'read-deposit-ui-governance', + owner: SOURCE_ROOTS.readClient, + contract: + '/read and /deposit render Organization authority sections with authority state, wallet state, blockers, and authority roots.', + requiredFields: ['Organization authority', 'Authority blockers', 'organizationPolicyWalletAuthority'], + }, + { + rowId: 'fail-closed-tests', + owner: SOURCE_ROOTS.packageHelperTest, + contract: + 'Focused tests prove approved Reading spend, missing wallet denial, approved deposit submission, and critical-source deposit blocking.', + requiredFields: ['pay_btc_fee', 'wallet_binding_missing', 'sub-critical-approved', 'critical-source-blocked'], + }, + { + rowId: 'workflow-and-artifact-wiring', + owner: SOURCE_ROOTS.checker, + contract: + 'Gate 7 closes only when generator, checker, package exports, protocol exports, docs, workflows, and generated artifact are current.', + requiredFields: ['check-v44-gate7-organization-policy-wallet-authority', 'generate-v44-organization-policy-wallet-authority'], + }, +]); + +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-gate7', SOURCE_ROOTS.spec, sources.spec.includes('V44 Gate 7 Organization Policy, Approval, And Wallet Authority')), + predicateResult('spec-names-gate7-artifact', SOURCE_ROOTS.spec, sources.spec.includes('v44-organization-policy-wallet-authority')), + predicateResult('delta-records-gate7', SOURCE_ROOTS.delta, sources.delta.includes('Gate 7') && sources.delta.includes('v44-organization-policy-wallet-authority')), + predicateResult('notes-records-gate7', SOURCE_ROOTS.notes, sources.notes.includes('Gate 7') && sources.notes.includes('organization policy')), + predicateResult('parity-records-gate7', SOURCE_ROOTS.parity, sources.parity.includes('v44-organization-policy-wallet-authority')), + predicateResult('roadmap-records-gate7', SOURCE_ROOTS.roadmap, sources.roadmap.includes('V44 Gate 7 closure anchor')), + predicateResult('readme-records-gate7', SOURCE_ROOTS.readme, sources.readme.includes('V44 Gate 7')), + predicateResult('protocol-readme-records-gate7', SOURCE_ROOTS.protocolReadme, sources.protocolReadme.includes('V44 Gate 7')), + predicateResult('btd-authority-actions-defined', SOURCE_ROOTS.btdAuthority, V44_ORGANIZATION_POLICY_ACTION_IDS.every((id) => sources.btdAuthority.includes(id))), + predicateResult('btd-authority-test-covers-deposit-actions', SOURCE_ROOTS.btdAuthorityTest, sources.btdAuthorityTest.includes('submit_deposit') && sources.btdAuthorityTest.includes('deposit:approve_option')), + predicateResult('package-helper-defined', SOURCE_ROOTS.packageHelper, sources.packageHelper.includes('buildOrganizationPolicyWalletAuthority') && sources.packageHelper.includes('OrganizationPolicyWalletAuthority')), + predicateResult('package-helper-source-safe-assertion', SOURCE_ROOTS.packageHelper, sources.packageHelper.includes('assertOrganizationPolicyWalletAuthoritySourceSafe') && V44_ORGANIZATION_POLICY_FORBIDDEN_PAYLOAD_IDS.every((id) => sources.packageHelper.toLowerCase().includes(id.split('-')[0]) || id === 'credentials')), + predicateResult('package-helper-test-covers-policy-paths', SOURCE_ROOTS.packageHelperTest, sources.packageHelperTest.includes('pay_btc_fee') && sources.packageHelperTest.includes('critical-source-blocked')), + predicateResult('asset-pack-package-exports-helper', SOURCE_ROOTS.assetPackPackageIndex, sources.assetPackPackageIndex.includes("export * from './organization-policy-wallet-authority'")), + predicateResult('asset-pack-manifest-exports-helper', SOURCE_ROOTS.assetPackPackageManifest, sources.assetPackPackageManifest.includes('"./organization-policy-wallet-authority"')), + predicateResult('read-route-model-binds-authority', SOURCE_ROOTS.readRouteModel, sources.readRouteModel.includes('organizationPolicyWalletAuthority') && sources.readRouteModel.includes("route: '/read'")), + predicateResult('read-route-test-covers-authority', SOURCE_ROOTS.readRouteTest, sources.readRouteTest.includes('organizationPolicyWalletAuthority') && sources.readRouteTest.includes('pay_btc_fee')), + predicateResult('read-client-renders-authority', SOURCE_ROOTS.readClient, sources.readClient.includes('Organization authority') && sources.readClient.includes('Authority blockers')), + predicateResult('read-client-test-covers-authority', SOURCE_ROOTS.readClientTest, sources.readClientTest.includes('Organization authority')), + predicateResult('deposit-route-model-binds-authority', SOURCE_ROOTS.depositRouteModel, sources.depositRouteModel.includes('organizationPolicyWalletAuthority') && sources.depositRouteModel.includes('sourceCriticalityApproved')), + predicateResult('deposit-route-test-covers-authority', SOURCE_ROOTS.depositRouteTest, sources.depositRouteTest.includes('organizationPolicyWalletAuthority') && sources.depositRouteTest.includes('sub-critical-approved')), + predicateResult('deposit-client-renders-authority', SOURCE_ROOTS.depositClient, sources.depositClient.includes('Organization authority') && sources.depositClient.includes('Authority blockers')), + predicateResult('deposit-client-test-covers-authority', SOURCE_ROOTS.depositClientTest, sources.depositClientTest.includes('Organization authority')), + predicateResult('packs-model-projects-governance', SOURCE_ROOTS.packActivityModel, sources.packActivityModel.includes('PackActivityGovernanceReadback') && sources.packActivityModel.includes('buildGovernanceReadback')), + predicateResult('packs-client-renders-governance', SOURCE_ROOTS.packsClient, sources.packsClient.includes('Governance') && sources.packsClient.includes('Authority root')), + predicateResult('pack-activity-test-covers-governance', SOURCE_ROOTS.packActivityModelTest, sources.packActivityModelTest.includes('organization-authority-root-abc')), + predicateResult('packs-client-test-covers-governance', SOURCE_ROOTS.packsClientTest, sources.packsClientTest.includes('organization-authority-root-abc')), + predicateResult('package-test-covers-gate7', SOURCE_ROOTS.packageTest, sources.packageTest.includes('buildV44OrganizationPolicyWalletAuthority')), + predicateResult('package-exports-gate7', SOURCE_ROOTS.packageIndex, sources.packageIndex.includes('buildV44OrganizationPolicyWalletAuthority')), + predicateResult('package-types-export-gate7', SOURCE_ROOTS.packageTypes, sources.packageTypes.includes('buildV44OrganizationPolicyWalletAuthority')), + predicateResult('package-json-exposes-gate7', SOURCE_ROOTS.packageJson, sources.packageJson.includes('"generate:v44-organization-policy-wallet-authority"') && sources.packageJson.includes('"check:v44-gate7"')), + predicateResult('gate-workflow-runs-gate7', SOURCE_ROOTS.gateWorkflow, sources.gateWorkflow.includes('check-v44-gate7-organization-policy-wallet-authority.mjs')), + predicateResult('canon-workflow-runs-gate7', SOURCE_ROOTS.canonWorkflow, sources.canonWorkflow.includes('check-v44-gate7-organization-policy-wallet-authority.mjs')), + predicateResult('generator-exists', SOURCE_ROOTS.generator, sources.generator.includes('buildV44OrganizationPolicyWalletAuthority')), + predicateResult('checker-exists', SOURCE_ROOTS.checker, sources.checker.includes('V44 Gate 7 organization policy wallet authority check')), + ]; +} + +export function buildV44OrganizationPolicyWalletAuthority(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-organization-policy-wallet-authority:${digest(JSON.stringify({ + objectIds: V44_ORGANIZATION_POLICY_OBJECT_IDS, + routeIds: V44_ORGANIZATION_POLICY_ROUTE_IDS, + actionIds: V44_ORGANIZATION_POLICY_ACTION_IDS, + stateIds: V44_ORGANIZATION_POLICY_STATE_IDS, + rowIds: V44_ORGANIZATION_POLICY_ROWS.map((row) => row.rowId), + sourceRoots, + failedPredicateIds, + }))}`; + + return { + artifactId: 'v44-organization-policy-wallet-authority', + schemaId: V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SCHEMA_ID, + version: V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_VERSION, + currentTarget: V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_CURRENT_TARGET, + sourceSafetyVerdict: V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SOURCE_SAFETY_VERDICT, + objectIds: [...V44_ORGANIZATION_POLICY_OBJECT_IDS], + routeIds: [...V44_ORGANIZATION_POLICY_ROUTE_IDS], + actionIds: [...V44_ORGANIZATION_POLICY_ACTION_IDS], + stateIds: [...V44_ORGANIZATION_POLICY_STATE_IDS], + forbiddenPayloadIds: [...V44_ORGANIZATION_POLICY_FORBIDDEN_PAYLOAD_IDS], + rows: V44_ORGANIZATION_POLICY_ROWS.map((row) => ({ + ...row, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + walletPrivateMaterialVisible: false, + valueBearingMainnetAdmitted: false, + rowRoot: `v44-organization-policy-row:${digest(JSON.stringify(row))}`, + })), + predicateResults, + sourceRoots, + coverage: { + organizationPolicyWalletAuthorityImplemented: predicateResults.find((predicate) => predicate.id === 'package-helper-defined')?.passed === true, + btdDepositActionsImplemented: predicateResults.find((predicate) => predicate.id === 'btd-authority-actions-defined')?.passed === true, + readRouteAuthorityImplemented: predicateResults.find((predicate) => predicate.id === 'read-route-model-binds-authority')?.passed === true, + depositRouteAuthorityImplemented: predicateResults.find((predicate) => predicate.id === 'deposit-route-model-binds-authority')?.passed === true, + packsGovernanceReadbackImplemented: predicateResults.find((predicate) => predicate.id === 'packs-model-projects-governance')?.passed === true, + testsImplemented: + predicateResults.find((predicate) => predicate.id === 'package-helper-test-covers-policy-paths')?.passed === true && + predicateResults.find((predicate) => predicate.id === 'btd-authority-test-covers-deposit-actions')?.passed === true, + sourceSafeMetadataOnly: true, + protectedSourceVisible: false, + rawSourceTextVisible: false, + unpaidAssetPackSourceVisible: false, + rawPromptVisible: false, + rawProviderResponseVisible: false, + walletPrivateMaterialVisible: false, + settlementPrivatePayloadVisible: false, + valueBearingMainnetAdmitted: false, + failedPredicateIds, + }, + passed: failedPredicateIds.length === 0, + artifactRoot, + }; +} diff --git a/packages/protocol/src/index.d.ts b/packages/protocol/src/index.d.ts index f1c0768a..5a364c64 100644 --- a/packages/protocol/src/index.d.ts +++ b/packages/protocol/src/index.d.ts @@ -748,6 +748,18 @@ export const V44_BTD_BTC_COMPENSATION_VALUE_LABEL_IDS: readonly string[]; export const V44_BTD_BTC_COMPENSATION_FORBIDDEN_PAYLOAD_IDS: readonly string[]; export const V44_BTD_BTC_COMPENSATION_ROWS: readonly Record[]; export function buildV44BtdBtcCompensationStatements(input?: Record): BitcodeProtocolReport; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH: string; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_CURRENT_TARGET: string; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SCHEMA_ID: string; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_VERSION: string; +export const V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SOURCE_SAFETY_VERDICT: string; +export const V44_ORGANIZATION_POLICY_OBJECT_IDS: readonly string[]; +export const V44_ORGANIZATION_POLICY_ROUTE_IDS: readonly string[]; +export const V44_ORGANIZATION_POLICY_ACTION_IDS: readonly string[]; +export const V44_ORGANIZATION_POLICY_STATE_IDS: readonly string[]; +export const V44_ORGANIZATION_POLICY_FORBIDDEN_PAYLOAD_IDS: readonly string[]; +export const V44_ORGANIZATION_POLICY_ROWS: readonly Record[]; +export function buildV44OrganizationPolicyWalletAuthority(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 8b5aa205..8e549350 100644 --- a/packages/protocol/src/index.js +++ b/packages/protocol/src/index.js @@ -850,6 +850,20 @@ export { V44_CONTRIBUTOR_COMPENSATION_STATE_IDS, buildV44BtdBtcCompensationStatements } from './canonical/v44-btd-btc-compensation-statements.js'; +export { + V44_ORGANIZATION_POLICY_ACTION_IDS, + V44_ORGANIZATION_POLICY_FORBIDDEN_PAYLOAD_IDS, + V44_ORGANIZATION_POLICY_OBJECT_IDS, + V44_ORGANIZATION_POLICY_ROUTE_IDS, + V44_ORGANIZATION_POLICY_ROWS, + V44_ORGANIZATION_POLICY_STATE_IDS, + V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH, + V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_CURRENT_TARGET, + V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SCHEMA_ID, + V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SOURCE_SAFETY_VERDICT, + V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_VERSION, + buildV44OrganizationPolicyWalletAuthority +} from './canonical/v44-organization-policy-wallet-authority.js'; export { EXCHANGE_INTENT_ACTION_KINDS, EXCHANGE_INTENT_ORDER_CONTRACTS_ARTIFACT_PATH, diff --git a/packages/protocol/test/v44-organization-policy-wallet-authority.test.js b/packages/protocol/test/v44-organization-policy-wallet-authority.test.js new file mode 100644 index 00000000..2744c07f --- /dev/null +++ b/packages/protocol/test/v44-organization-policy-wallet-authority.test.js @@ -0,0 +1,62 @@ +import assert from 'node:assert/strict'; +import { test } from 'node:test'; +import { + V44_ORGANIZATION_POLICY_ACTION_IDS, + V44_ORGANIZATION_POLICY_OBJECT_IDS, + V44_ORGANIZATION_POLICY_ROUTE_IDS, + V44_ORGANIZATION_POLICY_ROWS, + V44_ORGANIZATION_POLICY_STATE_IDS, + V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH, + V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SCHEMA_ID, + V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SOURCE_SAFETY_VERDICT, + buildV44OrganizationPolicyWalletAuthority, +} from '../src/canonical/v44-organization-policy-wallet-authority.js'; + +test('V44 organization policy wallet authority artifact is source-safe and complete', () => { + const artifact = buildV44OrganizationPolicyWalletAuthority(); + + assert.equal(V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH, '.bitcode/v44-organization-policy-wallet-authority.json'); + assert.equal(artifact.artifactId, 'v44-organization-policy-wallet-authority'); + assert.equal(artifact.schemaId, V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SCHEMA_ID); + assert.equal(artifact.version, 'V44'); + assert.equal(artifact.currentTarget, 'V43'); + assert.equal(artifact.sourceSafetyVerdict, V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_SOURCE_SAFETY_VERDICT); + assert.equal(artifact.passed, true); + assert.match(artifact.artifactRoot, /^v44-organization-policy-wallet-authority:/); + assert.deepEqual(artifact.objectIds, [...V44_ORGANIZATION_POLICY_OBJECT_IDS]); + assert.deepEqual(artifact.routeIds, [...V44_ORGANIZATION_POLICY_ROUTE_IDS]); + assert.deepEqual(artifact.actionIds, [...V44_ORGANIZATION_POLICY_ACTION_IDS]); + assert.deepEqual(artifact.stateIds, [...V44_ORGANIZATION_POLICY_STATE_IDS]); + assert.equal(artifact.coverage.organizationPolicyWalletAuthorityImplemented, true); + assert.equal(artifact.coverage.btdDepositActionsImplemented, true); + assert.equal(artifact.coverage.readRouteAuthorityImplemented, true); + assert.equal(artifact.coverage.depositRouteAuthorityImplemented, true); + assert.equal(artifact.coverage.packsGovernanceReadbackImplemented, true); + assert.equal(artifact.coverage.testsImplemented, true); + 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.walletPrivateMaterialVisible, false); + assert.equal(artifact.coverage.valueBearingMainnetAdmitted, false); +}); + +test('V44 organization policy rows bind BTD, routes, Packs, tests, and workflow evidence', () => { + const artifact = buildV44OrganizationPolicyWalletAuthority(); + const rowIds = artifact.rows.map((row) => row.rowId); + + assert.equal(artifact.rows.length, V44_ORGANIZATION_POLICY_ROWS.length); + assert.ok(rowIds.includes('btd-deposit-actions')); + assert.ok(rowIds.includes('source-safe-governance-statement')); + assert.ok(rowIds.includes('read-route-authority')); + assert.ok(rowIds.includes('deposit-route-authority')); + assert.ok(rowIds.includes('packs-governance-readback')); + + for (const row of artifact.rows) { + assert.equal(row.sourceSafeMetadataOnly, true); + assert.equal(row.protectedSourceVisible, false); + assert.equal(row.walletPrivateMaterialVisible, false); + assert.ok(row.rowRoot.startsWith('v44-organization-policy-row:')); + assert.ok(row.requiredFields.length > 0); + } +}); diff --git a/scripts/check-v44-gate7-organization-policy-wallet-authority.mjs b/scripts/check-v44-gate7-organization-policy-wallet-authority.mjs new file mode 100644 index 00000000..b69c767e --- /dev/null +++ b/scripts/check-v44-gate7-organization-policy-wallet-authority.mjs @@ -0,0 +1,209 @@ +#!/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_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH, + buildV44OrganizationPolicyWalletAuthority, +} from '../packages/protocol/src/canonical/v44-organization-policy-wallet-authority.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-gate7-organization-policy-wallet-authority.mjs [--skip-branch-check] [--skip-uapi-tests] [--skip-package-tests] [--repo-root ]', + '', + 'V44 Gate 7 organization policy wallet authority check: validates BTD deposit actions, package governance statements, /read and /deposit route authority, /packs governance readback, tests, docs, 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_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH, + 'packages/btd/src/authority.ts', + 'packages/btd/__tests__/btd.test.ts', + 'packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts', + 'packages/pipelines/asset-pack/src/__tests__/organization-policy-wallet-authority.test.ts', + 'uapi/app/read/read-route-model.ts', + 'uapi/tests/readRouteModel.test.ts', + 'uapi/app/read/ReadPageClient.tsx', + 'uapi/tests/readPageClient.test.tsx', + 'uapi/app/deposit/deposit-route-model.ts', + 'uapi/tests/depositRouteModel.test.ts', + 'uapi/app/deposit/DepositPageClient.tsx', + 'uapi/tests/depositPageClient.test.tsx', + 'uapi/components/base/bitcode/activity/pack-activity-model.ts', + 'uapi/app/packs/PacksPageClient.tsx', + 'uapi/tests/packActivityModel.test.ts', + 'uapi/tests/packsPageClient.test.tsx', + 'packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js', + 'packages/protocol/test/v44-organization-policy-wallet-authority.test.js', + 'scripts/generate-v44-organization-policy-wallet-authority.mjs', + 'scripts/check-v44-gate7-organization-policy-wallet-authority.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 7 file: ${relativePath}`); + } + + const artifact = buildV44OrganizationPolicyWalletAuthority({ repoRoot: root }); + assertCheck(failures, artifact.passed, `V44 organization policy wallet authority predicates failed: ${artifact.coverage.failedPredicateIds.join(', ')}`); + assertCheck(failures, artifact.coverage.organizationPolicyWalletAuthorityImplemented === true, 'Organization policy wallet authority must be implemented.'); + assertCheck(failures, artifact.coverage.btdDepositActionsImplemented === true, 'BTD deposit actions must be implemented.'); + assertCheck(failures, artifact.coverage.readRouteAuthorityImplemented === true, '/read authority readback must be implemented.'); + assertCheck(failures, artifact.coverage.depositRouteAuthorityImplemented === true, '/deposit authority readback must be implemented.'); + assertCheck(failures, artifact.coverage.packsGovernanceReadbackImplemented === true, '/packs governance readback must be implemented.'); + assertCheck(failures, artifact.coverage.testsImplemented === true, 'Gate 7 tests 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_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH) && + read(root, V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH) === serialized, + `${V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_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-organization-policy-wallet-authority"'), 'package.json must expose generate:v44-organization-policy-wallet-authority.'); + assertCheck(failures, packageJson.includes('"check:v44-organization-policy-wallet-authority"'), 'package.json must expose check:v44-organization-policy-wallet-authority.'); + assertCheck(failures, packageJson.includes('"check:v44-gate7"'), 'package.json must expose check:v44-gate7.'); + assertCheck(failures, gateWorkflow.includes('check-v44-gate7-organization-policy-wallet-authority.mjs'), 'Gate workflow must run V44 Gate 7 checker.'); + assertCheck(failures, canonWorkflow.includes('check-v44-gate7-organization-policy-wallet-authority.mjs'), 'Canon workflow must run V44 Gate 7 checker.'); + + try { + run(root, 'node', ['scripts/generate-v44-organization-policy-wallet-authority.mjs', '--check']); + } catch { + failures.push('V44 organization policy wallet authority artifact must be fresh.'); + } + + if (!args.skipPackageTests) { + try { + run(root, 'pnpm', ['--dir', 'packages/protocol', 'exec', 'node', '--test', '--test-force-exit', 'test/v44-organization-policy-wallet-authority.test.js']); + } catch { + failures.push('packages/protocol/test/v44-organization-policy-wallet-authority.test.js must pass.'); + } + + try { + run(root, 'pnpm', ['--filter', '@bitcode/pipeline-asset-pack', 'test', '--', 'organization-policy-wallet-authority.test.ts', '--runInBand']); + } catch { + failures.push('packages/pipelines/asset-pack organization policy wallet authority tests must pass.'); + } + + try { + run(root, 'pnpm', ['--filter', '@bitcode/btd', 'test', '--', 'btd.test.ts', '--runInBand']); + } catch { + failures.push('packages/btd organization authority tests must pass.'); + } + } + + if (!args.skipUapiTests) { + try { + run(root, 'pnpm', ['--dir', 'uapi', 'exec', 'jest', 'readRouteModel.test.ts', 'depositRouteModel.test.ts', 'packActivityModel.test.ts', 'packsPageClient.test.tsx', 'readPageClient.test.tsx', 'depositPageClient.test.tsx', '--runInBand']); + } catch { + failures.push('uapi route and Packs governance tests must pass.'); + } + } + + if (failures.length > 0) { + process.stderr.write('V44 Gate 7 organization policy wallet authority check failed:\n'); + for (const failure of failures.filter(Boolean)) process.stderr.write(`- ${failure}\n`); + process.exitCode = 1; + return; + } + + process.stdout.write('V44 Gate 7 organization policy wallet authority 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-organization-policy-wallet-authority.mjs b/scripts/generate-v44-organization-policy-wallet-authority.mjs new file mode 100644 index 00000000..3a85894b --- /dev/null +++ b/scripts/generate-v44-organization-policy-wallet-authority.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_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH, + buildV44OrganizationPolicyWalletAuthority, +} from '../packages/protocol/src/canonical/v44-organization-policy-wallet-authority.js'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); +const repoRoot = path.resolve(__dirname, '..'); +const artifactPath = path.join(repoRoot, V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH); +const check = process.argv.includes('--check'); +const artifact = buildV44OrganizationPolicyWalletAuthority({ repoRoot }); +const serialized = `${JSON.stringify(artifact, null, 2)}\n`; + +if (check) { + if (!existsSync(artifactPath) || readFileSync(artifactPath, 'utf8') !== serialized) { + process.stderr.write(`${V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH} is stale. Run pnpm run generate:v44-organization-policy-wallet-authority.\n`); + process.exitCode = 1; + } +} else { + writeFileSync(artifactPath, serialized); + process.stdout.write(`wrote ${V44_ORGANIZATION_POLICY_WALLET_AUTHORITY_ARTIFACT_PATH}\n`); +} diff --git a/uapi/app/deposit/DepositPageClient.tsx b/uapi/app/deposit/DepositPageClient.tsx index 85844044..be7a7544 100644 --- a/uapi/app/deposit/DepositPageClient.tsx +++ b/uapi/app/deposit/DepositPageClient.tsx @@ -398,6 +398,27 @@ export default function DepositPageClient() { depositorWalletId: preferredSignerAddress ? "connected-depositor-wallet" : null, + walletAuthorityPresent: hasVerifiedWalletConnection, + actorId: user?.id || null, + organizationId: + repositoryContext?.selectedRepository?.owner?.username || + repositoryContext?.selectedRepository?.fullName?.split("/")[0] || + null, + teamId: repositoryContext?.selectedRepository?.fullName + ? `repository:${repositoryContext.selectedRepository.fullName}` + : null, + memberId: user?.id || preferredSignerAddress || null, + organizationRole: + hasValidGitHubConnection && hasVerifiedWalletConnection + ? "admin" + : "member", + organizationPermissionGrants: [ + "deposit:synthesize_options", + ...(hasVerifiedWalletConnection + ? ["deposit:approve_option", "deposit:submit"] + : []), + ], + sourceCriticalityApproved: true, reviewerId: user?.id || preferredSignerAddress || null, hasRepositorySource: Boolean(repositoryContext?.selectedRepository), optionsRequested, @@ -409,6 +430,8 @@ export default function DepositPageClient() { depositorInstructions, hasDepositoryReadback, hasSubmittedDeposit, + hasValidGitHubConnection, + hasVerifiedWalletConnection, liveRuns.length, optionsRequested, optionReviewDecisionRecords.length, @@ -475,6 +498,32 @@ export default function DepositPageClient() { }, ]; + const authorityRows = [ + { + label: "Authority", + value: depositRouteSession.organizationPolicyWalletAuthority.aggregate.state, + }, + { + label: "Wallet", + value: depositRouteSession.organizationPolicyWalletAuthority.walletAuthority.state, + }, + { + label: "Deposit policy", + value: depositRouteSession.organizationPolicyWalletAuthority.depositApproval.state, + }, + { + label: "Required denials", + value: String( + depositRouteSession.organizationPolicyWalletAuthority.aggregate + .requiredDeniedActionCount, + ), + }, + { + label: "Authority root", + value: depositRouteSession.organizationPolicyWalletAuthority.roots.authorityRoot, + }, + ]; + const recentDepositRuns = useMemo( () => liveRuns @@ -1154,6 +1203,51 @@ export default function DepositPageClient() { +
+
+
+

+ Governance +

+

+ Organization authority +

+
+
+
+ {authorityRows.map((row) => ( +
+
+ {row.label} +
+
+ {row.value} +
+
+ ))} +
+ {depositRouteSession.organizationPolicyWalletAuthority.aggregate + .blockers.length ? ( +
+ + {depositRouteSession.organizationPolicyWalletAuthority.aggregate.blockers.join( + "; ", + )} + +
+ ) : null} +
+
diff --git a/uapi/app/deposit/deposit-route-model.ts b/uapi/app/deposit/deposit-route-model.ts index 75a6b38d..bc58791e 100644 --- a/uapi/app/deposit/deposit-route-model.ts +++ b/uapi/app/deposit/deposit-route-model.ts @@ -21,6 +21,12 @@ import { buildDepositorEarningSupplyIntelligence, type DepositorEarningSupplyIntelligence, } from '@bitcode/pipeline-asset-pack/depositor-earning-supply-intelligence'; +import { + assertOrganizationPolicyWalletAuthoritySourceSafe, + buildOrganizationPolicyWalletAuthority, + type OrganizationPolicyWalletAuthority, + type OrganizationPolicyWalletAuthorityInput, +} from '@bitcode/pipeline-asset-pack/organization-policy-wallet-authority'; import type { DepositOptionDemandSignal } from '@bitcode/pipeline-asset-pack/deposit-asset-pack-options'; export type DepositRouteStepId = @@ -40,6 +46,18 @@ export interface DepositRouteSessionInput extends DepositOptionSynthesisRequest developmentCostSats?: number | null; expectedSettlementSats?: number | null; depositorWalletId?: string | null; + depositApproved?: boolean | null; + depositLimitSats?: number | null; + sourceCriticalityApproved?: boolean | null; + actorId?: string | null; + organizationId?: string | null; + teamId?: string | null; + memberId?: string | null; + organizationRole?: OrganizationPolicyWalletAuthorityInput['organizationRole']; + organizationPermissionGrants?: string[] | null; + organizationPolicyId?: string | null; + organizationPolicyHash?: string | null; + walletAuthorityPresent?: boolean | null; optionReviewDecisions?: DepositOptionReviewDecision[] | null; reviewerId?: string | null; hasRepositorySource?: boolean; @@ -76,15 +94,16 @@ export interface DepositRouteSession { depositOptionAdmission: 'DepositAssetPackOptionAdmissionReport'; depositorEarningSupplyIntelligence: 'DepositorEarningSupplyIntelligence'; reviewRequiredBeforeDepositAdmission: true; - sourceCriticalityDemandRoiPolicyOwnedByGate6: true; - sourceCriticalityDemandRoiPolicyDeferredToGate6: true; - admissionAndIndexingOwnedByGate7: true; + sourceCriticalityDemandRoiPolicyPresent: true; + sourceCriticalityDemandRoiPolicySourceSafe: true; + admissionAndIndexingPolicyPresent: true; retainedTerminalDebugCompatible: true; }; synthesis: DepositAssetPackOptionSynthesis; policy: DepositAssetPackOptionPolicyReport; admission: DepositAssetPackOptionAdmissionReport; earningSupplyIntelligence: DepositorEarningSupplyIntelligence; + organizationPolicyWalletAuthority: OrganizationPolicyWalletAuthority; disclosure: { sourceSafetyClass: 'source_safe_deposit_option_route_metadata'; lowDetailDefault: true; @@ -246,6 +265,39 @@ export function buildDepositRouteSession(input: DepositRouteSessionInput = {}): unfitNeedOpportunitySignals: input.unfitNeedOpportunitySignals, createdAt: input.createdAt, }); + const sourceCriticalityState = + policy.blockedCount > 0 + ? 'blocked-critical-source' + : policy.warningCount > 0 + ? 'review-warning' + : 'sub-critical'; + const depositApproved = + input.depositApproved === true || + admission.approvedCount > 0 || + admission.admittedCount > 0 || + Boolean(input.hasSubmittedDeposit); + const organizationPolicyWalletAuthority = buildOrganizationPolicyWalletAuthority({ + route: '/deposit', + actorId: normalizedText(input.actorId) || normalizedText(input.reviewerId), + organizationId: normalizedText(input.organizationId), + teamId: normalizedText(input.teamId), + memberId: normalizedText(input.memberId), + organizationRole: input.organizationRole || null, + organizationPermissionGrants: input.organizationPermissionGrants || null, + policyId: normalizedText(input.organizationPolicyId), + policyHash: normalizedText(input.organizationPolicyHash), + walletId: normalizedText(input.depositorWalletId), + walletAuthorityPresent: input.walletAuthorityPresent ?? Boolean(input.depositorWalletId), + sourceCriticalityState, + sourceCriticalityApproved: input.sourceCriticalityApproved ?? policy.blockedCount === 0, + depositApproved, + expectedSettlementSats: input.expectedSettlementSats, + depositLimitSats: input.depositLimitSats, + accountAdmitted: Boolean(input.actorId || input.reviewerId || repositoryFullName), + interfaceAdmitted: true, + targetAnchor: normalizedText(input.transactionId) || repositoryFullName || '/deposit', + createdAt: input.createdAt, + }); const activeStepId = resolveActiveStep(input, admission.admittedCount); const steps = DEPOSIT_ROUTE_STEPS.map((step) => ({ ...step, @@ -262,6 +314,7 @@ export function buildDepositRouteSession(input: DepositRouteSessionInput = {}): policyReportRoot: policy.roots.policyReportRoot, admissionReportRoot: admission.roots.admissionReportRoot, earningSupplyIntelligenceRoot: earningSupplyIntelligence.roots.intelligenceRoot, + organizationPolicyWalletAuthorityRoot: organizationPolicyWalletAuthority.roots.authorityRoot, steps: steps.map((step) => ({ id: step.id, state: step.state, blockers: step.blockers })), }); @@ -284,15 +337,16 @@ export function buildDepositRouteSession(input: DepositRouteSessionInput = {}): depositOptionAdmission: 'DepositAssetPackOptionAdmissionReport', depositorEarningSupplyIntelligence: 'DepositorEarningSupplyIntelligence', reviewRequiredBeforeDepositAdmission: true, - sourceCriticalityDemandRoiPolicyOwnedByGate6: true, - sourceCriticalityDemandRoiPolicyDeferredToGate6: true, - admissionAndIndexingOwnedByGate7: true, + sourceCriticalityDemandRoiPolicyPresent: true, + sourceCriticalityDemandRoiPolicySourceSafe: true, + admissionAndIndexingPolicyPresent: true, retainedTerminalDebugCompatible: true, }, synthesis, policy, admission, earningSupplyIntelligence, + organizationPolicyWalletAuthority, disclosure: { sourceSafetyClass: 'source_safe_deposit_option_route_metadata', lowDetailDefault: true, @@ -314,11 +368,15 @@ export function assertDepositRouteSessionSourceSafe(session: DepositRouteSession const policySafety = assertDepositAssetPackOptionPolicyReportSourceSafe(session.policy); const admissionSafety = assertDepositAssetPackOptionAdmissionReportSourceSafe(session.admission); const earningSupplySafety = assertDepositorEarningSupplyIntelligenceSourceSafe(session.earningSupplyIntelligence); + const organizationSafety = assertOrganizationPolicyWalletAuthoritySourceSafe( + session.organizationPolicyWalletAuthority, + ); const sourceSafe = synthesisSafety.admitted && policySafety.admitted && admissionSafety.admitted && earningSupplySafety.admitted && + organizationSafety.admitted && session.schema === 'bitcode.deposit.route-session' && session.route === '/deposit' && session.stageCount === 5 && @@ -334,9 +392,14 @@ export function assertDepositRouteSessionSourceSafe(session: DepositRouteSession session.earningSupplyIntelligence.disclosure.unpaidAssetPackSourceVisible === false && session.earningSupplyIntelligence.disclosure.walletPrivateMaterialVisible === false && session.earningSupplyIntelligence.disclosure.settlementPrivatePayloadVisible === false && - session.pipelineOwnership.sourceCriticalityDemandRoiPolicyOwnedByGate6 === true && - session.pipelineOwnership.sourceCriticalityDemandRoiPolicyDeferredToGate6 === true && - session.pipelineOwnership.admissionAndIndexingOwnedByGate7 === true && + session.pipelineOwnership.sourceCriticalityDemandRoiPolicyPresent === true && + session.pipelineOwnership.sourceCriticalityDemandRoiPolicySourceSafe === true && + session.pipelineOwnership.admissionAndIndexingPolicyPresent === true && + session.organizationPolicyWalletAuthority.schema === 'bitcode.organization.policy-wallet-authority' && + session.organizationPolicyWalletAuthority.route === '/deposit' && + session.organizationPolicyWalletAuthority.disclosure.sourceSafeMetadataOnly === true && + session.organizationPolicyWalletAuthority.disclosure.protectedSourceVisible === false && + session.organizationPolicyWalletAuthority.disclosure.walletPrivateMaterialVisible === false && session.disclosure.sourceSafetyClass === 'source_safe_deposit_option_route_metadata' && session.disclosure.protectedSourceVisible === false && session.disclosure.rawSourceTextVisible === false && diff --git a/uapi/app/packs/PacksPageClient.tsx b/uapi/app/packs/PacksPageClient.tsx index fa467ba9..8e1e3a03 100644 --- a/uapi/app/packs/PacksPageClient.tsx +++ b/uapi/app/packs/PacksPageClient.tsx @@ -742,6 +742,57 @@ export default function PacksPageClient() { )} + {detail.governance && ( + +
+
+
Authority
+
+ {detail.governance.state || "not recorded"} +
+
+
+
Route
+
+ {detail.governance.route || "not recorded"} +
+
+
+
Wallet
+
+ {detail.governance.walletState || "not recorded"} +
+
+
+
Spend
+
+ {detail.governance.spendState || "not recorded"} +
+
+
+
Deposit
+
+ {detail.governance.depositState || "not recorded"} +
+
+
+
Required denials
+
+ {detail.governance.requiredDeniedActionCount} +
+
+ {detail.governance.authorityRoot && ( +
+
Authority root
+
+ {detail.governance.authorityRoot} +
+
+ )} +
+
+ )} +
{detail.proofRoots.length ? ( diff --git a/uapi/app/read/ReadPageClient.tsx b/uapi/app/read/ReadPageClient.tsx index 8de20f52..139fa7b0 100644 --- a/uapi/app/read/ReadPageClient.tsx +++ b/uapi/app/read/ReadPageClient.tsx @@ -429,6 +429,32 @@ export default function ReadPageClient() { }, ]; + const authorityRows = [ + { + label: "Authority", + value: readRouteSession.organizationPolicyWalletAuthority.aggregate.state, + }, + { + label: "Wallet", + value: readRouteSession.organizationPolicyWalletAuthority.walletAuthority.state, + }, + { + label: "Spend", + value: readRouteSession.organizationPolicyWalletAuthority.budgetApproval.state, + }, + { + label: "Required denials", + value: String( + readRouteSession.organizationPolicyWalletAuthority.aggregate + .requiredDeniedActionCount, + ), + }, + { + label: "Authority root", + value: readRouteSession.organizationPolicyWalletAuthority.roots.authorityRoot, + }, + ]; + return (
+
+
+
+

+ Governance +

+

+ Organization authority +

+
+
+
+ {authorityRows.map((row) => ( +
+
+ {row.label} +
+
+ {row.value} +
+
+ ))} +
+ {readRouteSession.organizationPolicyWalletAuthority.aggregate + .blockers.length ? ( +
+ + {readRouteSession.organizationPolicyWalletAuthority.aggregate.blockers.join( + "; ", + )} + +
+ ) : null} +
+
diff --git a/uapi/app/read/read-route-model.ts b/uapi/app/read/read-route-model.ts index b9c77ed5..212ef970 100644 --- a/uapi/app/read/read-route-model.ts +++ b/uapi/app/read/read-route-model.ts @@ -6,6 +6,12 @@ import { type TerminalEnterpriseReadingStepId, type TerminalEnterpriseReadingUxStateInput, } from '@/app/terminal/terminal-enterprise-reading-ux-state'; +import { + assertOrganizationPolicyWalletAuthoritySourceSafe, + buildOrganizationPolicyWalletAuthority, + type OrganizationPolicyWalletAuthority, + type OrganizationPolicyWalletAuthorityInput, +} from '@bitcode/pipeline-asset-pack/organization-policy-wallet-authority'; export type ReadRouteStepId = TerminalEnterpriseReadingStepId; @@ -25,6 +31,16 @@ export type ReadRouteSessionInput = TerminalEnterpriseReadingUxStateInput & { procurementApproved?: boolean; buyerAuthorized?: boolean; walletAuthorityPresent?: boolean; + walletId?: string | null; + actorId?: string | null; + organizationId?: string | null; + teamId?: string | null; + memberId?: string | null; + organizationRole?: OrganizationPolicyWalletAuthorityInput['organizationRole']; + organizationPermissionGrants?: string[] | null; + organizationPolicyId?: string | null; + organizationPolicyHash?: string | null; + spendLimitSats?: number | null; measuredBtd?: number | null; }; @@ -134,6 +150,7 @@ export type ReadRouteSession = { retainedTerminalDebugCompatible: true; }; procurementGovernance: ReadProcurementGovernance; + organizationPolicyWalletAuthority: OrganizationPolicyWalletAuthority; disclosure: { sourceSafetyClass: 'source_safe_read_route_metadata'; lowDetailDefault: true; @@ -328,6 +345,29 @@ export function writeReadRouteStage(params: URLSearchParams, stage: ReadRouteSte export function buildReadRouteSession(input: ReadRouteSessionInput = {}): ReadRouteSession { const enterpriseState = buildTerminalEnterpriseReadingUxState(input); const procurementGovernance = buildReadProcurementGovernance(input); + const organizationPolicyWalletAuthority = buildOrganizationPolicyWalletAuthority({ + route: '/read', + actorId: normalizedText(input.actorId), + organizationId: normalizedText(input.organizationId), + teamId: normalizedText(input.teamId), + memberId: normalizedText(input.memberId), + organizationRole: input.organizationRole || null, + organizationPermissionGrants: input.organizationPermissionGrants || null, + policyId: normalizedText(input.organizationPolicyId), + policyHash: normalizedText(input.organizationPolicyHash), + walletId: normalizedText(input.walletId) || (input.walletAuthorityPresent ? 'connected-reader-wallet' : null), + walletAuthorityPresent: input.walletAuthorityPresent, + quoteSats: procurementGovernance.quotePolicy.shareToFee.grossSats, + budgetEnvelopeSats: procurementGovernance.budgetPolicy.budgetEnvelopeSats, + approvalThresholdSats: procurementGovernance.budgetPolicy.approvalThresholdSats, + spendLimitSats: input.spendLimitSats || procurementGovernance.budgetPolicy.budgetEnvelopeSats, + procurementApproved: procurementGovernance.approval.procurementApproved, + buyerAuthorized: procurementGovernance.approval.buyerAuthorized, + settlementState: input.hasDeliveryReadback ? 'settled' : 'pending', + accountAdmitted: Boolean(input.actorId || input.repositoryFullName), + interfaceAdmitted: true, + targetAnchor: normalizedText(input.settlementQuoteId) || normalizedText(input.transactionId) || '/read', + }); const seed = JSON.stringify({ activeStepId: enterpriseState.activeStepId, transactionId: enterpriseState.routeState.transactionId, @@ -339,6 +379,7 @@ export function buildReadRouteSession(input: ReadRouteSessionInput = {}): ReadRo settlementQuoteId: normalizedText(input.settlementQuoteId), steps: enterpriseState.steps.map((step) => ({ id: step.id, state: step.state, blockers: step.blockers })), procurementGovernance, + organizationPolicyWalletAuthorityRoot: organizationPolicyWalletAuthority.roots.authorityRoot, }); return { @@ -375,6 +416,7 @@ export function buildReadRouteSession(input: ReadRouteSessionInput = {}): ReadRo retainedTerminalDebugCompatible: true, }, procurementGovernance, + organizationPolicyWalletAuthority, disclosure: { sourceSafetyClass: 'source_safe_read_route_metadata', lowDetailDefault: true, @@ -406,9 +448,13 @@ export function assertReadRouteSessionSourceSafe(session: ReadRouteSession) { hasDeliveryReadback: session.readObjects.deliveryUnlocked, }), ); + const organizationSafety = assertOrganizationPolicyWalletAuthoritySourceSafe( + session.organizationPolicyWalletAuthority, + ); const sourceSafe = enterpriseSafety.admitted && + organizationSafety.admitted && session.schema === 'bitcode.read.route-session' && session.route === '/read' && session.stageCount === 5 && @@ -425,6 +471,11 @@ export function assertReadRouteSessionSourceSafe(session: ReadRouteSession) { session.procurementGovernance.prePurchaseReview.unpaidAssetPackSourceVisible === false && session.procurementGovernance.prePurchaseReview.walletPrivateMaterialVisible === false && session.procurementGovernance.prePurchaseReview.settlementPrivatePayloadVisible === false && + session.organizationPolicyWalletAuthority.schema === 'bitcode.organization.policy-wallet-authority' && + session.organizationPolicyWalletAuthority.route === '/read' && + session.organizationPolicyWalletAuthority.disclosure.sourceSafeMetadataOnly === true && + session.organizationPolicyWalletAuthority.disclosure.protectedSourceVisible === false && + session.organizationPolicyWalletAuthority.disclosure.walletPrivateMaterialVisible === false && session.disclosure.sourceSafetyClass === 'source_safe_read_route_metadata' && session.disclosure.protectedSourceVisible === false && session.disclosure.unpaidAssetPackSourceVisible === false && diff --git a/uapi/components/base/bitcode/activity/pack-activity-model.ts b/uapi/components/base/bitcode/activity/pack-activity-model.ts index 25ed0c5e..0ef79e77 100644 --- a/uapi/components/base/bitcode/activity/pack-activity-model.ts +++ b/uapi/components/base/bitcode/activity/pack-activity-model.ts @@ -71,6 +71,17 @@ export interface PackActivityAccountingReadback { statementRoot: string | null; } +export interface PackActivityGovernanceReadback { + state: string | null; + route: string | null; + walletState: string | null; + spendState: string | null; + depositState: string | null; + requiredDeniedActionCount: number; + blockerCount: number; + authorityRoot: string | null; +} + export interface PackActivityRecord { id: string; type: PackActivityType; @@ -89,6 +100,7 @@ export interface PackActivityRecord { values: PackActivityValue[]; proofRoots: PackActivityProofRoot[]; accounting: PackActivityAccountingReadback | null; + governance: PackActivityGovernanceReadback | null; sourceSafety: PackActivitySourceSafety; metadata: Record; } @@ -130,6 +142,7 @@ export interface PackActivityDetailProjection { values: PackActivityValue[]; proofRoots: PackActivityProofRoot[]; accounting: PackActivityAccountingReadback | null; + governance: PackActivityGovernanceReadback | null; states: { settlement: string | null; compensation: string | null; @@ -520,6 +533,40 @@ function buildAccountingReadback(record: BitcodeActivityRecord): PackActivityAcc }; } +function buildGovernanceReadback(record: BitcodeActivityRecord): PackActivityGovernanceReadback | null { + const payload = asRecord(record.payload); + const statement = findFirstRecord( + payload, + (candidate) => + candidate.schema === 'bitcode.organization.policy-wallet-authority' || + candidate.statement === 'OrganizationPolicyWalletAuthority', + ); + const aggregate = asRecord(statement?.aggregate); + const walletAuthority = asRecord(statement?.walletAuthority); + const budgetApproval = asRecord(statement?.budgetApproval); + const depositApproval = asRecord(statement?.depositApproval); + const roots = asRecord(statement?.roots); + const hasGovernance = + Boolean(statement) || + Boolean(readString(payload, 'organizationAuthorityState', 'governanceState')) || + Boolean(findFirstString(payload, ['organizationAuthorityRoot', 'governanceAuthorityRoot'])); + + if (!hasGovernance) return null; + + return { + state: readString(aggregate, 'state') || readString(payload, 'organizationAuthorityState', 'governanceState'), + route: readString(statement, 'route') || readString(payload, 'governanceRoute'), + walletState: readString(walletAuthority, 'state') || readString(payload, 'walletAuthorityState'), + spendState: readString(budgetApproval, 'state') || readString(payload, 'spendAuthorityState'), + depositState: readString(depositApproval, 'state') || readString(payload, 'depositAuthorityState'), + requiredDeniedActionCount: findFirstNumber(aggregate, ['requiredDeniedActionCount']) || 0, + blockerCount: findFirstNumber(aggregate, ['blockerCount']) || 0, + authorityRoot: + readString(roots, 'authorityRoot') || + findFirstString(payload, ['organizationAuthorityRoot', 'governanceAuthorityRoot']), + }; +} + function collectProofRoots(source: unknown, roots = new Map(), depth = 0) { if (depth > 7 || source === null || source === undefined) return roots; @@ -596,6 +643,7 @@ export function normalizePackActivityRecord(record: BitcodeActivityRecord): Pack values: buildValues(record), proofRoots: [...collectProofRoots(record.payload).values()].slice(0, 24), accounting: buildAccountingReadback(record), + governance: buildGovernanceReadback(record), sourceSafety: SOURCE_SAFETY, metadata, }; @@ -657,6 +705,12 @@ function buildSearchText(record: PackActivityRecord) { record.accounting?.reconciliationState, record.accounting?.treasuryRouteState, record.accounting?.statementRoot, + record.governance?.state, + record.governance?.route, + record.governance?.walletState, + record.governance?.spendState, + record.governance?.depositState, + record.governance?.authorityRoot, ] .filter(Boolean) .join(' ') @@ -792,6 +846,7 @@ export function buildPackActivityDetailProjection( values: record.values, proofRoots: record.proofRoots, accounting: record.accounting, + governance: record.governance, states: { settlement: record.settlementState, compensation: record.compensationState, diff --git a/uapi/jest.config.cjs b/uapi/jest.config.cjs index 2d6e6ebd..32bfa8e1 100644 --- a/uapi/jest.config.cjs +++ b/uapi/jest.config.cjs @@ -56,6 +56,7 @@ module.exports = { '^@bitcode/pipeline-asset-pack/deposit-asset-pack-option-policy$': '/../packages/pipelines/asset-pack/src/deposit-asset-pack-option-policy.ts', '^@bitcode/pipeline-asset-pack/deposit-asset-pack-option-admission$': '/../packages/pipelines/asset-pack/src/deposit-asset-pack-option-admission.ts', '^@bitcode/pipeline-asset-pack/depositor-earning-supply-intelligence$': '/../packages/pipelines/asset-pack/src/depositor-earning-supply-intelligence.ts', + '^@bitcode/pipeline-asset-pack/organization-policy-wallet-authority$': '/../packages/pipelines/asset-pack/src/organization-policy-wallet-authority.ts', '^@bitcode/pipeline-asset-pack/src/(.+)$': '/../packages/pipelines/asset-pack/src/$1', '^@bitcode/([^/]+)/src/(.+)$': '/../packages/$1/src/$2', '^@bitcode/supabase/ssr/server$': '/tests/mocks/supabaseServerClient.ts', diff --git a/uapi/tests/depositPageClient.test.tsx b/uapi/tests/depositPageClient.test.tsx index c4a2a1ab..bfddf530 100644 --- a/uapi/tests/depositPageClient.test.tsx +++ b/uapi/tests/depositPageClient.test.tsx @@ -183,6 +183,7 @@ describe("DepositPageClient", () => { screen.getByTestId("deposit-route-step-review-options"), ).toHaveAttribute("aria-current", "step"); expect(screen.getByText("Source-safe deposit state")).toBeInTheDocument(); + expect(screen.getByText("Organization authority")).toBeInTheDocument(); expect( screen.getAllByText("DepositAssetPackOptionSynthesis").length, ).toBeGreaterThan(0); diff --git a/uapi/tests/depositRouteModel.test.ts b/uapi/tests/depositRouteModel.test.ts index 80657d48..707ce38f 100644 --- a/uapi/tests/depositRouteModel.test.ts +++ b/uapi/tests/depositRouteModel.test.ts @@ -50,9 +50,9 @@ describe('deposit-route-model', () => { depositOptionAdmission: 'DepositAssetPackOptionAdmissionReport', depositorEarningSupplyIntelligence: 'DepositorEarningSupplyIntelligence', reviewRequiredBeforeDepositAdmission: true, - sourceCriticalityDemandRoiPolicyOwnedByGate6: true, - sourceCriticalityDemandRoiPolicyDeferredToGate6: true, - admissionAndIndexingOwnedByGate7: true, + sourceCriticalityDemandRoiPolicyPresent: true, + sourceCriticalityDemandRoiPolicySourceSafe: true, + admissionAndIndexingPolicyPresent: true, retainedTerminalDebugCompatible: true, }); expect(session.synthesis.schema).toBe('bitcode.deposit.asset-pack-option-synthesis'); @@ -62,6 +62,8 @@ describe('deposit-route-model', () => { expect(session.policy.aggregatePolicy.compensationPolicy).toBe('future-reader-btc-source-to-shares-route-preview'); expect(session.earningSupplyIntelligence.schema).toBe('bitcode.deposit.earning-supply-intelligence'); expect(session.earningSupplyIntelligence.intelligence).toBe('DepositorEarningSupplyIntelligence'); + expect(session.organizationPolicyWalletAuthority.schema).toBe('bitcode.organization.policy-wallet-authority'); + expect(session.organizationPolicyWalletAuthority.route).toBe('/deposit'); expect(session.earningSupplyIntelligence.aggregate.valueLabel).toBe('estimate'); expect(session.earningSupplyIntelligence.earningStatements).toHaveLength(3); expect(session.earningSupplyIntelligence.supplyRecommendations).toHaveLength(3); @@ -127,7 +129,8 @@ describe('deposit-route-model', () => { ), ).toBe(true); expect(session.policy.evaluations.every((evaluation) => evaluation.policyDecision === 'blocked-before-admission')).toBe(true); - expect(session.pipelineOwnership.admissionAndIndexingOwnedByGate7).toBe(true); + expect(session.pipelineOwnership.admissionAndIndexingPolicyPresent).toBe(true); + expect(session.organizationPolicyWalletAuthority.depositApproval.state).toBe('critical-source-blocked'); expect(assertDepositRouteSessionSourceSafe(session).admitted).toBe(true); }); @@ -184,6 +187,14 @@ describe('deposit-route-model', () => { sourcePathHints: ['uapi/app/deposit/DepositPageClient.tsx'], sourceCriticalitySignals: [{ id: 'sub-critical', severity: 'sub-critical', weight: 0.85 }], depositorWalletId: 'wallet-depositor-1', + actorId: 'user-1', + organizationId: 'org-1', + organizationRole: 'admin', + organizationPermissionGrants: [ + 'deposit:synthesize_options', + 'deposit:approve_option', + 'deposit:submit', + ], optionsRequested: true, optionReviewDecisions: [ { @@ -200,6 +211,8 @@ describe('deposit-route-model', () => { expect(approved.admission.receipts[0].depositoryIndexProjection.state).toBe('indexed-for-finding-fits'); expect(approved.admission.receipts[0].storageProjection.state).toBe('projected-to-object-storage'); expect(approved.admission.receipts[0].packsActivitySync.state).toBe('synchronized-to-packs'); + expect(approved.organizationPolicyWalletAuthority.depositApproval.state).toBe('sub-critical-approved'); + expect(approved.organizationPolicyWalletAuthority.aggregate.state).toBe('allowed'); expect(assertDepositRouteSessionSourceSafe(approved).admitted).toBe(true); }); diff --git a/uapi/tests/packActivityModel.test.ts b/uapi/tests/packActivityModel.test.ts index 6fb9798a..ecc043dd 100644 --- a/uapi/tests/packActivityModel.test.ts +++ b/uapi/tests/packActivityModel.test.ts @@ -61,6 +61,28 @@ describe('pack-activity-model', () => { accountingRoot: 'btd-btc-accounting-root-abc', }, }, + organizationPolicyWalletAuthority: { + schema: 'bitcode.organization.policy-wallet-authority', + statement: 'OrganizationPolicyWalletAuthority', + route: '/read', + walletAuthority: { + state: 'verified', + }, + budgetApproval: { + state: 'within-limit', + }, + depositApproval: { + state: 'not-applicable', + }, + aggregate: { + state: 'allowed', + requiredDeniedActionCount: 0, + blockerCount: 0, + }, + roots: { + authorityRoot: 'organization-authority-root-abc', + }, + }, assetPackMeasurementRoot: 'measurement-root-abc', settlementReceiptRoot: 'settlement-root-def', protectedSource: 'protected source body', @@ -96,6 +118,13 @@ describe('pack-activity-model', () => { allocatedContributorSats: 3200, statementRoot: 'btd-btc-accounting-root-abc', }); + expect(record.governance).toMatchObject({ + state: 'allowed', + route: '/read', + walletState: 'verified', + spendState: 'within-limit', + authorityRoot: 'organization-authority-root-abc', + }); expect(assertPackActivitySourceSafe(record)).toBe(true); expect(JSON.stringify(record)).not.toContain('protected source body'); expect(JSON.stringify(record)).not.toContain('raw prompt text'); @@ -133,6 +162,7 @@ describe('pack-activity-model', () => { const detail = buildPackActivityDetailProjection(result.records[0]); expect(detail.states.settlement).toBe('quote_ready'); expect(detail.accounting?.statementRoot).toBe('btd-btc-accounting-root-abc'); + expect(detail.governance?.authorityRoot).toBe('organization-authority-root-abc'); expect(detail.proofRoots.length).toBeGreaterThan(0); expect(assertPackActivitySourceSafe(detail)).toBe(true); }); diff --git a/uapi/tests/packsPageClient.test.tsx b/uapi/tests/packsPageClient.test.tsx index cede33be..2a99b89c 100644 --- a/uapi/tests/packsPageClient.test.tsx +++ b/uapi/tests/packsPageClient.test.tsx @@ -67,6 +67,16 @@ describe("PacksPageClient", () => { allocatedContributorSats: 3200, statementRoot: "btd-btc-accounting-root-abc", }, + governance: { + state: "allowed", + route: "/read", + walletState: "verified", + spendState: "within-limit", + depositState: "not-applicable", + requiredDeniedActionCount: 0, + blockerCount: 0, + authorityRoot: "organization-authority-root-abc", + }, proofRoots: [ { id: "settlement-root", @@ -132,6 +142,16 @@ describe("PacksPageClient", () => { allocatedContributorSats: 3200, statementRoot: "btd-btc-accounting-root-abc", }, + governance: { + state: "allowed", + route: "/read", + walletState: "verified", + spendState: "within-limit", + depositState: "not-applicable", + requiredDeniedActionCount: 0, + blockerCount: 0, + authorityRoot: "organization-authority-root-abc", + }, proofRoots: [ { id: "settlement-root", @@ -184,7 +204,9 @@ describe("PacksPageClient", () => { ); expect(screen.getByText("Proof roots")).toBeInTheDocument(); expect(screen.getByText("Accounting")).toBeInTheDocument(); + expect(screen.getByText("Governance")).toBeInTheDocument(); expect(screen.getByText("btd-btc-accounting-root-abc")).toBeInTheDocument(); + expect(screen.getByText("organization-authority-root-abc")).toBeInTheDocument(); expect(screen.getByText("settlement-root-def")).toBeInTheDocument(); expect(screen.getAllByText("quote_ready").length).toBeGreaterThan(0); expect( diff --git a/uapi/tests/readPageClient.test.tsx b/uapi/tests/readPageClient.test.tsx index f7273e2e..311d3d57 100644 --- a/uapi/tests/readPageClient.test.tsx +++ b/uapi/tests/readPageClient.test.tsx @@ -172,6 +172,7 @@ describe("ReadPageClient", () => { "step", ); expect(screen.getByText("Source-safe read state")).toBeInTheDocument(); + expect(screen.getByText("Organization authority")).toBeInTheDocument(); expect( screen.getByText("ReadNeedComprehensionSynthesis"), ).toBeInTheDocument(); diff --git a/uapi/tests/readRouteModel.test.ts b/uapi/tests/readRouteModel.test.ts index d5486137..13c0bc01 100644 --- a/uapi/tests/readRouteModel.test.ts +++ b/uapi/tests/readRouteModel.test.ts @@ -36,6 +36,8 @@ describe('read-route-model', () => { expect(session.pipelineOwnership.previewSourceSafeBeforeSettlement).toBe(true); expect(session.pipelineOwnership.deliveryRequiresPaidReadRights).toBe(true); expect(session.procurementGovernance.schema).toBe('bitcode.read.procurement-governance'); + expect(session.organizationPolicyWalletAuthority.schema).toBe('bitcode.organization.policy-wallet-authority'); + expect(session.organizationPolicyWalletAuthority.route).toBe('/read'); expect(session.procurementGovernance.quotePolicy.pricingVersion).toBe('measurement-weight-volume'); expect(session.procurementGovernance.quotePolicy.shareToFee.deterministic).toBe(true); expect(session.disclosure.protectedSourceVisible).toBe(false); @@ -66,6 +68,11 @@ describe('read-route-model', () => { procurementApproved: true, buyerAuthorized: true, walletAuthorityPresent: true, + walletId: 'wallet-reader', + actorId: 'user-1', + organizationId: 'org-1', + organizationRole: 'admin', + organizationPermissionGrants: ['reading:request', 'settlement:pay_btc_fee'], }); expect(session.procurementGovernance.budgetPolicy.state).toBe('within-budget'); @@ -73,6 +80,10 @@ describe('read-route-model', () => { expect(session.procurementGovernance.quotePolicy.state).toBe('approved'); expect(session.procurementGovernance.settlement.readiness).toBe('ready-for-testnet-settlement'); expect(session.procurementGovernance.settlement.btcBtdSettlementReady).toBe(true); + expect( + session.organizationPolicyWalletAuthority.actionStatements.find((entry) => entry.action === 'pay_btc_fee')?.allowed, + ).toBe(true); + expect(session.organizationPolicyWalletAuthority.aggregate.state).toBe('allowed'); expect(session.procurementGovernance.prePurchaseReview.protectedSourceVisible).toBe(false); expect(session.procurementGovernance.prePurchaseReview.unpaidAssetPackSourceVisible).toBe(false); expect(assertReadRouteSessionSourceSafe(session).admitted).toBe(true);