Skip to content

Commit 7fcaafc

Browse files
V31 Gate 5: Wallet and BTD pane readiness
Introduce the BTD-owned Wallet/BTD support projection for no-custody signer posture, network readiness, source-safe read-right summaries, account treasury boundaries, and settlement blockers. Wire the projection through the Auxillaries API contract, user data hook, and Wallet pane so Terminal users can inspect BTD support without exposing protected source or Exchange market assumptions. Refresh V31 specs, roadmap, docs, gate workflow coverage, and targeted BTD/API/UI tests for the Gate 5 closure criteria.
1 parent 4b4165b commit 7fcaafc

22 files changed

Lines changed: 1059 additions & 58 deletions

.github/workflows/bitcode-gate-quality.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ jobs:
9999
node scripts/check-v31-gate2-auxillaries-package-route-contracts.mjs --skip-branch-check
100100
node scripts/check-v31-gate3-profile-account-state.mjs --skip-branch-check
101101
node scripts/check-v31-gate4-connects-provider-readiness.mjs --skip-branch-check
102+
node scripts/check-v31-gate5-wallet-btd-pane-readiness.mjs --skip-branch-check
102103
else
103104
echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2
104105
exit 1
@@ -139,6 +140,7 @@ jobs:
139140
run: |
140141
pnpm --dir uapi exec jest --runTestsByPath \
141142
tests/userDataRoute.test.ts \
143+
tests/auxillariesWalletPane.test.tsx \
142144
tests/api/auxillariesGithubConnectionRoute.test.ts \
143145
tests/api/vcsRoutes.test.ts \
144146
tests/auxillariesExternalsPane.test.tsx \

BITCODE_SPEC_V31.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,9 @@ Gate 5 Wallet/BTD precision:
252252
- Wallet panes consume no-custody wallet capability and signer posture from V30 BTD/wallet primitives.
253253
- BTD panes expose range/read-right/treasury/settlement readiness summaries without revealing protected AssetPack source.
254254
- Treasury and organization BTD posture remains distinct from Exchange market state.
255+
- `@bitcode/btd` owns the source-safe `BtdWalletBtdSupportProjection` used by Auxillaries to summarize wallet capability, signer readiness, network readiness, BTD read-right counts, range cell counts, account treasury posture, settlement blockers, and proof roots.
256+
- `AuxillariesWalletBtdPaneState` is the API-facing support object that carries that projection into `/api/auxillaries/data`; UI panes may render it but may not recalculate no-custody, read-right, or settlement law locally.
257+
- The Wallet pane may show account BTC fee posture, BTD range/read-right counts, roots, and blockers, but it must keep protected source visibility false before paid unlock and must identify that the support pane is not an Exchange market state surface.
255258

256259
Gate 6 policy precision:
257260

@@ -418,6 +421,10 @@ The pane support model must contain:
418421
- organization treasury posture kept distinct from Exchange market state;
419422
- explicit proof that no server component custodies private keys or displays wallet secrets.
420423

424+
Gate 5 binds this model through `BtdWalletBtdSupportProjection` in `@bitcode/btd` and `AuxillariesWalletBtdPaneState` in the package-owned Auxillaries route contract.
425+
The projection carries `walletCapabilityRoot` and `btdSupportRoot`, names signer capabilities such as message signing, PSBT signing, and rights transfer readiness, counts owner-read/licensed-read/pending/denied/unknown AssetPack read-right posture, sums range cells, and always marks `protectedSourceVisible: false` for pre-settlement support views.
426+
Its treasury summary is account-scoped, no-custody, and explicitly `not_exchange_market_state`.
427+
421428
No server component may custody the Reader private key.
422429
Server-side routes may prepare receipts, validate proofs, serialize quote/posture evidence, and persist registry rows only when explicitly requested.
423430
They must not claim signature, broadcast, finality, settlement unlock, or rights transfer without matching receipt and readback evidence.

BITCODE_SPEC_V31_DELTA.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,13 @@ Closure acceptance:
144144
- BTD pane state consumes range/read-right/treasury/settlement readiness without protected source;
145145
- treasury and organization BTD support remain distinct from Exchange market state.
146146

147+
Gate 5 implementation centers:
148+
149+
- `packages/btd/src/auxillaries-support.ts` owns `BtdWalletBtdSupportProjection`, deriving no-custody wallet capability, signer posture, network readiness, BTD range/read-right counts, account treasury posture, settlement blockers, and source-safe roots;
150+
- `packages/api/src/routes/auxillaries-contract.ts` maps that BTD package projection into `AuxillariesWalletBtdPaneState` so `/api/auxillaries/data` returns one package-owned Wallet/BTD support object;
151+
- `uapi/app/auxillaries/components/AuxillariesWalletPane.tsx` renders signer, network, range, read-right, settlement, treasury-boundary, and proof-root readouts from `walletBtdPaneState` rather than locally rederiving BTD law;
152+
- focused BTD, API, route, and pane tests prove no-custody posture, range/read-right summary, protected-source non-disclosure, and explicit non-Exchange treasury classification.
153+
147154
### Gate 6: Organization Team Role Policy Authority
148155

149156
Gate 6 deepens organization and policy authority.

BITCODE_SPEC_V31_NOTES.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,14 @@ Route hydration must include template preference and notification readback where
9191
## Gate 4 closure note
9292

9393
Gate 4 is closed only when Connects provider state is a source-safe readiness contract rather than a raw OAuth/VCS status blob.
94+
That source-safe provider connection posture remains closed after later V31 gates advance the roadmap.
9495
Provider readiness must name provider id/name, installation state, credential posture, token presence class, scopes class, last readback status, blocker, repair action, and proof root without exposing raw provider credentials.
9596
VCS and GitHub Auxillaries routes may use credentials internally to validate or repair a connection, but responses, UI metadata, telemetry, and recovery proof hooks must carry only classified posture and before/after readiness roots.
9697
The Externals pane can display compact provider proof detail, but it must consume `connectionReadiness` and `recoveryRuns` from the package-owned Auxillaries contract instead of locally deciding provider law.
98+
99+
## Gate 5 closure note
100+
101+
Gate 5 is closed only when Wallet/BTD support is package-owned and source-safe.
102+
`@bitcode/btd` must derive no-custody wallet capability, signer posture, network readiness, BTD range/read-right counts, account treasury posture, settlement blockers, and support roots.
103+
`packages/api` may map that projection into `AuxillariesWalletBtdPaneState`, but UI and routes must not rederive BTD read-access, settlement, rights-transfer, or no-custody law locally.
104+
The Wallet pane must consume `walletBtdPaneState` from `/api/auxillaries/data`, render signer/network/range/read-right/settlement/treasury readiness, keep protected source invisible before paid unlock, and state that account treasury support is not Exchange market state.

BITCODE_SPEC_V31_PARITY_MATRIX.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ No `_legacy/` source is active source truth.
121121

122122
| Requirement | Source evidence | Current V31 judgment |
123123
| --- | --- | --- |
124-
| Wallet panes consume no-custody signer posture | BTD wallet primitives and pane tests | pending |
125-
| BTD panes consume range/read-right/treasury summaries | BTD access and treasury tests | pending |
126-
| Settlement-readiness state remains distinct from Exchange market state | package and UI tests | pending |
124+
| Wallet panes consume no-custody signer posture | `packages/btd/src/auxillaries-support.ts`, `packages/api/src/routes/auxillaries-contract.ts`, and `uapi/tests/auxillariesWalletPane.test.tsx` project no-custody capability, signer readiness, signer actions, roots, and UI readout | drafted |
125+
| BTD panes consume range/read-right/treasury summaries | `BtdWalletBtdSupportProjection`, `AuxillariesWalletBtdPaneState`, `packages/btd/__tests__/btd.test.ts`, and `packages/api/src/routes/__tests__/auxillaries-contract.test.ts` cover range counts, read-right counts, BTC fee treasury, and protected-source invisibility | drafted |
126+
| Settlement-readiness state remains distinct from Exchange market state | Wallet pane and package tests assert account-scoped treasury posture, settlement blockers, and `not_exchange_market_state` classification | drafted |
127127

128128
## Gate 6 Parity
129129

SPECIFICATIONS_ROADMAP.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
- Current active canonical pointer: `BITCODE_SPEC.txt` -> `V30`
66
- Current active canon: `BITCODE_SPEC_V30.md`
77
- Current draft target: `BITCODE_SPEC_V31.md`
8-
- Current working gate: V31 Gate 4 Connects provider readiness and recovery, which deepens source-safe provider connection posture with provider id/name, installation state, token presence class, scopes class, last readback status, blocker, repair action, readiness roots, and before/after recovery evidence over the V30 Protocol/BTD substrate.
8+
- Current working gate: V31 Gate 5 Wallet and BTD pane readiness, which connects Auxillaries Wallet/BTD UI to package-owned V30 wallet, signer, network, BTD range, read-right, treasury, no-custody, and settlement-readiness projections without protected source leakage or Exchange market inference.
99
- Purpose: concise running index of Bitcode/ENGI specification history, current work, and planned work.
1010

1111
This roadmap is not an active system specification.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
"check:v31-gate2": "node scripts/check-v31-gate2-auxillaries-package-route-contracts.mjs",
6969
"check:v31-gate3": "node scripts/check-v31-gate3-profile-account-state.mjs",
7070
"check:v31-gate4": "node scripts/check-v31-gate4-connects-provider-readiness.mjs",
71+
"check:v31-gate5": "node scripts/check-v31-gate5-wallet-btd-pane-readiness.mjs",
7172
"check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic",
7273
"check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title",
7374
"check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24",

packages/api/README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,15 @@ and a readiness root. Routes may validate credentials privately, but API
4141
responses, UI metadata, telemetry, and recovery proof hooks must only serialize
4242
classified readiness and `AuxillariesRecoveryRun` before/after roots.
4343

44+
Wallet/BTD support state is package-owned through `@bitcode/btd` and mapped
45+
here as `AuxillariesWalletBtdPaneState`. Route payloads may include wallet
46+
binding facts, BTD holding counts, recent AssetPack ids/ranges, and BTC fee
47+
posture, but the no-custody signer posture, network readiness, range/read-right
48+
summary, account treasury boundary, settlement blockers, and support roots must
49+
come from the BTD projection. API responses must keep protected AssetPack source
50+
hidden, keep wallet private material out of JSON, and mark the Wallet/BTD
51+
treasury support state as separate from Exchange market state.
52+
4453
In V26 fourth-gate this package is where merged-world Bitcode becomes concrete:
4554
- `/conversations` continuity
4655
- `/executions` compatibility and pipeline-run APIs

packages/api/src/routes/__tests__/auxillaries-contract.test.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ describe('Auxillaries package route contracts', () => {
4545
address: 'tb1pauxcontract',
4646
verificationState: 'verified',
4747
metadata: {
48+
network: 'testnet',
4849
private_key: 'wallet-secret',
4950
connectedAt: '2026-05-21T00:00:00.000Z',
5051
},
@@ -80,6 +81,8 @@ describe('Auxillaries package route contracts', () => {
8081
assetPackId: 'asset-pack-1',
8182
rangeStart: 1,
8283
rangeEndExclusive: 3,
84+
readRightState: 'owner_read',
85+
sourceSafePreviewRoot: 'source-safe-preview-root',
8386
},
8487
],
8588
modelPreferences: {
@@ -149,6 +152,39 @@ describe('Auxillaries package route contracts', () => {
149152
expect(payload.walletBtdPaneState.signerPosture).toMatchObject({
150153
ready: true,
151154
state: 'verified',
155+
canSignPsbt: true,
156+
serverCustody: false,
157+
});
158+
expect(payload.walletBtdPaneState.walletCapability).toMatchObject({
159+
network: 'testnet',
160+
noCustody: true,
161+
serverCustody: false,
162+
capabilities: expect.arrayContaining(['message_sign', 'psbt_sign', 'rights_transfer']),
163+
});
164+
expect(payload.walletBtdPaneState.networkReadiness).toMatchObject({
165+
state: 'ready',
166+
network: 'testnet',
167+
blocker: null,
168+
});
169+
expect(payload.walletBtdPaneState.btdReadRightSummary).toMatchObject({
170+
aggregateBtd: 128,
171+
assetPackCount: 1,
172+
rangeCount: 1,
173+
totalRangeCells: 2,
174+
ownerReadCount: 1,
175+
protectedSourceVisible: false,
176+
sourceSafePreviewRoots: ['source-safe-preview-root'],
177+
});
178+
expect(payload.walletBtdPaneState.treasurySummary).toMatchObject({
179+
feeAsset: 'BTC',
180+
noCustody: true,
181+
treasuryScope: 'account',
182+
organizationTreasurySeparated: true,
183+
exchangeMarketState: 'not_exchange_market_state',
184+
});
185+
expect(payload.walletBtdPaneState).toMatchObject({
186+
settlementReadiness: 'ready',
187+
settlementBlockers: [],
152188
});
153189
expect(payload.organizationAuthority.policyDecision).toBe('allowed');
154190
expect(payload.auxillariesContract.contractVersion).toBe(AUXILLARIES_CONTRACT_VERSION);
@@ -163,6 +199,7 @@ describe('Auxillaries package route contracts', () => {
163199
expect(JSON.stringify(payload)).not.toContain('wallet-secret');
164200
expect(JSON.stringify(payload)).not.toContain('repository source');
165201
expect(JSON.stringify(payload)).not.toContain('private prompt body');
202+
expect(JSON.stringify(payload.walletBtdPaneState)).not.toContain('asset pack source');
166203
expect(JSON.stringify(payload.connectionReadiness[0].metadata)).not.toContain('provider-token');
167204
expect(assertAuxillariesJsonSafe(payload)).toBeUndefined();
168205
});

packages/api/src/routes/auxillaries-contract.ts

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { createHash } from 'crypto';
2+
import { buildBtdWalletBtdSupportProjection } from '@bitcode/btd';
23

34
export const AUXILLARY_FLOW_STEPS = ['wallet', 'externals', 'profile', 'interfaces'] as const;
45
export const AUXILLARIES_CONTRACT_VERSION = 'v31-draft-auxillaries-contracts' as const;
@@ -85,6 +86,9 @@ export interface AuxillaryBtdAssetPackSummary {
8586
label?: string;
8687
rangeStart?: number;
8788
rangeEndExclusive?: number;
89+
readRightState?: 'owner_read' | 'licensed_read' | 'pending_settlement' | 'denied' | 'unknown';
90+
accessPolicyHash?: string | null;
91+
sourceSafePreviewRoot?: string | null;
8892
acquiredAt?: string | null;
8993
}
9094

@@ -234,24 +238,50 @@ export interface AuxillariesWalletBtdPaneState {
234238
provider: string | null;
235239
address: string | null;
236240
verificationState: string | null;
241+
network: string | null;
237242
noCustody: true;
243+
serverCustody: false;
244+
capabilities: Array<'message_sign' | 'psbt_sign' | 'rights_transfer'>;
245+
walletCapabilityRoot: string;
238246
};
239247
signerPosture: {
240248
ready: boolean;
241249
state: 'verified' | 'manual' | 'pending' | 'missing' | 'invalid';
242250
requiredAction: 'none' | 'connect_wallet' | 'verify_wallet_signature' | 'repair_wallet_binding';
251+
canSignPsbt: boolean;
252+
canSignRightsTransfer: boolean;
253+
serverCustody: false;
254+
};
255+
networkReadiness: {
256+
state: AuxillariesReadinessState;
257+
network: string | null;
258+
requiredAction: 'none' | 'connect_wallet' | 'verify_network' | 'repair_wallet_binding';
259+
blocker: string | null;
243260
};
244261
btdReadRightSummary: {
245262
aggregateBtd: number;
246263
assetPackCount: number;
247264
recentAssetPackIds: string[];
265+
rangeCount: number;
266+
totalRangeCells: number;
267+
ownerReadCount: number;
268+
licensedReadCount: number;
269+
pendingSettlementCount: number;
270+
deniedCount: number;
271+
unknownCount: number;
272+
protectedSourceVisible: false;
273+
sourceSafePreviewRoots: string[];
248274
};
249275
treasurySummary: {
250276
btcFeeBalance: number | null;
251277
feeAsset: 'BTC';
252278
noCustody: true;
279+
treasuryScope: 'account';
280+
organizationTreasurySeparated: true;
281+
exchangeMarketState: 'not_exchange_market_state';
253282
};
254283
settlementReadiness: AuxillariesReadinessState;
284+
settlementBlockers: string[];
255285
sourceSafetyClass: AuxillariesSourceSafetyClass;
256286
btdSupportRoot: string;
257287
}
@@ -1118,61 +1148,40 @@ export function buildAuxillariesWalletBtdPaneState(input: {
11181148
const verificationState = readString(walletStatus?.verificationState) ?? binding?.status ?? null;
11191149
const connected = readBoolean(walletStatus?.connected) ?? Boolean(address);
11201150
const valid = readBoolean(walletStatus?.valid) ?? verificationState === 'verified';
1121-
const signerState: AuxillariesWalletBtdPaneState['signerPosture']['state'] = !address
1122-
? 'missing'
1123-
: valid || verificationState === 'verified'
1124-
? 'verified'
1125-
: verificationState === 'pending'
1126-
? 'pending'
1127-
: verificationState === 'manual'
1128-
? 'manual'
1129-
: connected
1130-
? 'invalid'
1131-
: 'missing';
1132-
const recentAssetPacks = Array.isArray(input.recentBtdAssetPacks) ? input.recentBtdAssetPacks : [];
1133-
const aggregateBtd = typeof input.btdBalance === 'number' && Number.isFinite(input.btdBalance)
1134-
? input.btdBalance
1135-
: 0;
1136-
const withoutRoot = {
1137-
kind: 'AuxillariesWalletBtdPaneState' as const,
1138-
walletCapability: {
1139-
hasBinding: Boolean(address),
1140-
provider,
1151+
const walletMetadata = asRecord(walletStatus?.metadata);
1152+
const projection = buildBtdWalletBtdSupportProjection({
1153+
wallet: {
11411154
address,
1155+
provider,
11421156
verificationState,
1143-
noCustody: true as const,
1144-
},
1145-
signerPosture: {
1146-
ready: signerState === 'verified',
1147-
state: signerState,
1148-
requiredAction:
1149-
signerState === 'verified'
1150-
? 'none' as const
1151-
: signerState === 'missing'
1152-
? 'connect_wallet' as const
1153-
: signerState === 'manual' || signerState === 'pending'
1154-
? 'verify_wallet_signature' as const
1155-
: 'repair_wallet_binding' as const,
1157+
connected,
1158+
valid,
1159+
network:
1160+
readString(walletStatus?.network) ??
1161+
readString(walletMetadata?.network) ??
1162+
null,
11561163
},
1157-
btdReadRightSummary: {
1158-
aggregateBtd,
1159-
assetPackCount: recentAssetPacks.length,
1160-
recentAssetPackIds: recentAssetPacks.map((assetPack) => assetPack.assetPackId).filter(Boolean),
1161-
},
1162-
treasurySummary: {
1163-
btcFeeBalance: typeof input.btcFeeBalance === 'number' && Number.isFinite(input.btcFeeBalance)
1164-
? input.btcFeeBalance
1165-
: null,
1166-
feeAsset: 'BTC' as const,
1167-
noCustody: true as const,
1168-
},
1169-
settlementReadiness: signerState === 'verified' ? 'ready' as const : 'degraded' as const,
1164+
aggregateBtd: input.btdBalance,
1165+
btcFeeBalance: input.btcFeeBalance,
1166+
recentAssetPacks: Array.isArray(input.recentBtdAssetPacks)
1167+
? input.recentBtdAssetPacks
1168+
: [],
1169+
});
1170+
const withoutRoot: Omit<AuxillariesWalletBtdPaneState, 'btdSupportRoot'> = {
1171+
kind: 'AuxillariesWalletBtdPaneState' as const,
1172+
walletCapability: projection.walletCapability,
1173+
signerPosture: projection.signerPosture,
1174+
networkReadiness: projection.networkReadiness,
1175+
btdReadRightSummary: projection.btdReadRightSummary,
1176+
treasurySummary: projection.treasurySummary,
1177+
settlementReadiness: projection.settlementReadiness,
1178+
settlementBlockers: projection.settlementBlockers,
11701179
sourceSafetyClass: 'source_safe' as AuxillariesSourceSafetyClass,
11711180
};
11721181

11731182
return {
11741183
...withoutRoot,
1175-
btdSupportRoot: stableProofRoot('auxillaries-wallet-btd-pane-state', withoutRoot),
1184+
btdSupportRoot: projection.btdSupportRoot,
11761185
};
11771186
}
11781187

0 commit comments

Comments
 (0)