Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions BITCODE_SPEC_V28.md
Original file line number Diff line number Diff line change
Expand Up @@ -675,6 +675,14 @@ Acceptance criteria:
- policy templates cover owner-read, licensed-read, derivative use, redistribution, confidentiality, dispute, and takedown posture.
- Terminal copy avoids price-appreciation, dividend, copyright-transfer, or marketplace-royalty promises.

Implementation posture:

- Organization `$BTD` posture is a registry projection. Read models must collect member wallet bindings, then read ownership events and read-license rows from the BTD registry. Aggregate compatibility balances may remain contextual but must not admit organization, MCP, ChatGPT App, or read-license actions.
- MCP admission may require current owner-read or licensed-read evidence for one or more AssetPacks. Deprecated aggregate holding gates must fail closed and point callers to registry-derived read-access requirements.
- ChatGPT App write-capable connected-interface tools must require explicit user confirmation and typed read-access evidence carrying AssetPack id, wallet id, owner-read or licensed-read decision, policy hash, and reason.
- Access-policy templates must remain source-readable and test-covered for owner-read, licensed-read, derivative use, redistribution, confidentiality, dispute, and takedown posture.
- Active Terminal and Auxillaries copy must describe registry, range, ownership, license, and proof posture without implying price appreciation, dividends, copyright transfer, or marketplace royalties.

### Gate 7: Terminal Operations And Testnet Readiness

Purpose:
Expand Down
12 changes: 12 additions & 0 deletions internal-docs/BITCODE_CHATGPT_APP_INTERFACE.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,20 @@ It must not:
- own Exchange state,
- bypass Terminal/Exchange proof requirements,
- write unconfirmed connected-interface changes,
- write connected-interface changes without owner-read or licensed-read registry evidence for the relevant AssetPack,
- use generic work-board examples as Bitcode product semantics.

## Gate 6 Read-Access Admission

Write-capable ChatGPT App tools require two independent admission facts:

- `confirmed: true` from the user interaction.
- `readAccess` evidence with AssetPack id, wallet id, decision, access-policy hash, and reason.

The only admitted write decisions are `owner_read` and `licensed_read`. A balance,
organization total, or generic account role is not enough to write through a
connected interface.

## Requirements For SPEC Promotion

- tool names must be Bitcode-specific,
Expand Down
2 changes: 2 additions & 0 deletions internal-docs/BITCODE_CONNECTED_SERVICES.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ Examples:
- Source providers bind evidence and repository scope.
- Delivery providers receive AssetPacks or AssetPack partials.
- Every write-capable connected interface must fail closed without readiness and admission receipts.
- MCP and ChatGPT App writes must admit against owner-read or licensed-read registry evidence, not aggregate `$BTD` holding thresholds.
- Organization `$BTD` posture must read member wallet bindings through BTD registry ownership and read-license rows.
- Provider payloads must normalize toward Read, fit, AssetPack, settlement, proof, or delivery-mechanism semantics.

## Current Source Examples
Expand Down
102 changes: 102 additions & 0 deletions packages/btd/__tests__/btd.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,13 @@ import {
BtdFungibleMutationRejectedError,
BTD_MAX_MINTABLE_SUPPLY,
BITCODE_FEE_ASSET,
assertBtdAccessPolicyTemplateCoverage,
assertBtdMintableSupplyLimit,
buildBtdReadAccessProjectionFromRegistryRows,
calculateLlmBtcFeeEstimate,
calculateMeasuredBtdFromTokens,
evaluateBtdReadAccess,
listBtdAccessPolicyTemplates,
} from '../src';

describe('calculateLlmBtcFeeEstimate', () => {
Expand Down Expand Up @@ -63,3 +67,101 @@ describe('BtdFungibleMutationRejectedError', () => {
expect(err.code).toBe('BTD_IS_NON_FUNGIBLE');
});
});

describe('BTD access policy templates', () => {
it('covers owner-read, licensed-read, policy, dispute, and takedown posture', () => {
const templates = assertBtdAccessPolicyTemplateCoverage(listBtdAccessPolicyTemplates());

expect(templates.map((template) => template.kind)).toEqual(
expect.arrayContaining([
'owner_read',
'licensed_read',
'derivative_use',
'redistribution',
'confidentiality',
'dispute',
'takedown',
]),
);
expect(templates.flatMap((template) => template.prohibitedClaims)).toEqual(
expect.arrayContaining([
'price appreciation',
'dividend',
'copyright transfer',
'marketplace royalty',
]),
);
});
});

describe('registry-derived read access projection', () => {
it('maps range, ownership, and read-license rows into owner-read decisions', () => {
const projection = buildBtdReadAccessProjectionFromRegistryRows({
assetPackId: 'asset-pack-1',
range: {
asset_pack_id: 'asset-pack-1',
range_start: 10,
range_end_exclusive: 15,
token_count: 5,
access_policy_id: 'policy-1',
access_policy_hash: 'policy-hash',
},
ownershipRows: [
{
to_wallet_id: 'wallet-owner',
asset_pack_id: 'asset-pack-1',
range_start: 10,
range_end_exclusive: 15,
access_policy_hash: 'policy-hash',
},
],
});

const decision = evaluateBtdReadAccess({
walletId: 'wallet-owner',
assetPackId: 'asset-pack-1',
accessPolicy: projection.accessPolicy,
ownershipClaims: projection.ownershipClaims,
licenses: projection.licenses,
at: '2026-05-19T00:00:00.000Z',
});

expect(projection.range.tokenCount).toBe(5);
expect(decision.decision).toBe('owner_read');
});

it('maps registry read-license rows into licensed-read decisions', () => {
const projection = buildBtdReadAccessProjectionFromRegistryRows({
assetPackId: 'asset-pack-1',
range: {
asset_pack_id: 'asset-pack-1',
range_start: 10,
range_end_exclusive: 15,
token_count: 5,
access_policy_id: 'policy-1',
access_policy_hash: 'policy-hash',
},
licenseRows: [
{
license_id: 'license-1',
wallet_id: 'wallet-reader',
asset_pack_id: 'asset-pack-1',
access_policy_hash: 'policy-hash',
valid_from: '2026-05-01T00:00:00.000Z',
expires_at: '2026-06-01T00:00:00.000Z',
},
],
});

const decision = evaluateBtdReadAccess({
walletId: 'wallet-reader',
assetPackId: 'asset-pack-1',
accessPolicy: projection.accessPolicy,
ownershipClaims: projection.ownershipClaims,
licenses: projection.licenses,
at: '2026-05-19T00:00:00.000Z',
});

expect(decision.decision).toBe('licensed_read');
});
});
2 changes: 1 addition & 1 deletion packages/btd/__tests__/v27-crypto-primitives.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1512,7 +1512,7 @@ describe('V27 Terminal journal and ledger/database reconciliation primitives', (
metaphysicalFacts: [
{
factId: 'public-private-fact',
factKind: 'read_fit_context',
factKind: 'need_fit_context',
canonicalRoot: 'root',
private: false,
},
Expand Down
15 changes: 15 additions & 0 deletions packages/btd/jest.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node',
rootDir: '.',
testMatch: ['<rootDir>/__tests__/**/*.test.ts'],
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
tsconfig: '<rootDir>/../../tsconfig.json',
diagnostics: false,
},
],
},
};
11 changes: 11 additions & 0 deletions packages/btd/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,19 @@
"private": true,
"main": "src/index.ts",
"types": "src/index.ts",
"scripts": {
"test": "jest --passWithNoTests",
"typecheck": "tsc --noEmit --pretty false"
},
"dependencies": {
"@bitcode/models": "workspace:*",
"@bitcode/supabase": "workspace:*"
},
"devDependencies": {
"@types/jest": "^29.5.12",
"@types/node": "^20.0.0",
"jest": "^29.7.0",
"ts-jest": "^29.1.1",
"typescript": "^5.0.0"
}
}
Loading
Loading