Skip to content

Commit e607b44

Browse files
Merge pull request #45 from engineeredsoftware/v31/gate-2-auxillaries-package-route-contracts
V31 Gate 2: Auxillaries Package Route Contracts
2 parents d7ae968 + fa2bb0c commit e607b44

19 files changed

Lines changed: 1463 additions & 27 deletions

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ jobs:
9696
node scripts/check-bitcode-canon-posture-drift.mjs --active-canon V30 --draft-target V31
9797
node scripts/check-v30-gate10-promotion-readiness.mjs --promotion-mode --skip-branch-check
9898
node scripts/check-v31-gate1-spec-roadmap-opening.mjs --skip-branch-check
99+
node scripts/check-v31-gate2-auxillaries-package-route-contracts.mjs --skip-branch-check
99100
else
100101
echo "Unexpected BITCODE_SPEC.txt pointer: $POINTER" >&2
101102
exit 1
@@ -122,6 +123,7 @@ jobs:
122123
pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btc-fee-operation.test.ts
123124
pnpm --filter @bitcode/btd test -- --runTestsByPath __tests__/btd.test.ts
124125
pnpm --filter @bitcode/api exec jest --config jest.config.cjs --runTestsByPath src/routes/__tests__/btd-crypto.test.ts --runInBand
126+
pnpm --filter @bitcode/api exec jest --config jest.config.cjs --runTestsByPath src/routes/__tests__/auxillaries-contract.test.ts --runInBand
125127
pnpm --dir packages/executions-mcp/src/mcp-server run test:mcp -- --runTestsByPath src/__tests__/unit/auth.test.ts --runInBand
126128
pnpm --dir packages/chatgptapp exec jest --runTestsByPath src/__tests__/tools.test.ts --runInBand
127129
pnpm --filter @bitcode/pipeline-hosts exec jest --config jest.config.cjs --runTestsByPath src/__tests__/asset-pack-harness.test.ts --runInBand
@@ -134,6 +136,7 @@ jobs:
134136
- name: Test staged Reading route and Terminal harness contracts
135137
run: |
136138
pnpm --dir uapi exec jest --runTestsByPath \
139+
tests/userDataRoute.test.ts \
137140
tests/api/readReviewRoute.test.ts \
138141
tests/api/pipelineHarnessRoute.test.ts \
139142
tests/terminalPipelineHarnessClient.test.ts \

BITCODE_SPEC_V31.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,7 @@ Gate 2 contract precision:
226226
- Auxillaries API routes may authenticate, parse requests, and persist explicit route writes, but profile/account readiness, connection readiness, interface admission, wallet/BTD pane state, organization authority, readiness diagnostics, and recovery run objects must be built by package-owned helpers.
227227
- JSON-safe output must redact provider tokens, API keys, wallet secrets, private prompts, protected source, and service credentials.
228228
- `uapi/app/auxillaries` components consume these contracts as product state and must not rederive hidden policy logic.
229+
- The package-owned V31 contract builder is `buildAuxillariesContractSnapshot`; its JSON-safe route payload compatibility builder is `buildAuxillaryDataPayload`, and every route/mock bridge must pass through these builders before UI consumption.
229230

230231
Gate 3 profile/account precision:
231232

BITCODE_SPEC_V31_DELTA.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,13 @@ Closure acceptance:
9393
- no commercial runtime code imports `protocol-demonstration/src/*`;
9494
- package and Auxillaries READMEs name ownership boundaries and accepted imports.
9595

96+
Gate 2 implementation centers:
97+
98+
- `packages/api/src/routes/auxillaries-contract.ts` owns `AuxillariesContractSnapshot`, `AuxillariesProfileState`, `AuxillariesConnectionReadiness`, `AuxillariesInterfaceAdmission`, `AuxillariesWalletBtdPaneState`, `OrganizationPolicyAuthority`, `AuxillariesReadinessDiagnostic`, `AuxillariesRecoveryRun`, JSON-safe serialization, parsing, validation, and proof-root derivation.
99+
- `packages/api/src/routes/auxillaries.ts` remains the route-orchestration owner and delegates live and mock Auxillaries data to the package contract builders before response serialization.
100+
- `packages/api/src/routes/__tests__/auxillaries-contract.test.ts` proves source-safe redaction, alias preservation, contract validation, diagnostic generation, and recovery-run roots.
101+
- `scripts/check-v31-gate2-auxillaries-package-route-contracts.mjs` proves route-package boundaries, documentation/spec parity, commercial-runtime demonstration separation, and workflow coverage.
102+
96103
### Gate 3: Profile And Account State
97104

98105
Gate 3 deepens Profile and account support.

BITCODE_SPEC_V31_NOTES.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,9 @@ V31 owns deeper Auxillaries:
7474
## Gate 1 closure note
7575

7676
Gate 1 is closed only when the V31 draft family validates over V30, the roadmap is truthful, V31 workflows are greenable, contributor docs show the V31 gate workflow, and `check:v31-gate1` fails closed on stale posture or missing Auxillaries scope.
77+
78+
## Gate 2 closure note
79+
80+
Gate 2 is closed only when Auxillaries support-state contracts are package-owned and JSON-safe.
81+
Routes may still authenticate, read/write explicit storage rows, and return framework responses, but readiness and policy objects for Profile, Connects, Interfaces, Wallet, BTD, organization, diagnostics, and recovery must be built through `packages/api/src/routes/auxillaries-contract.ts`.
82+
The route payload can preserve existing UI fields for compatibility, but provider tokens, wallet secrets, service keys, database credentials, private prompts, and protected source must be redacted before any UI, telemetry, or proof-hook consumption.

BITCODE_SPEC_V31_PARITY_MATRIX.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -96,10 +96,10 @@ No `_legacy/` source is active source truth.
9696

9797
| Requirement | Source evidence | Current V31 judgment |
9898
| --- | --- | --- |
99-
| Package-owned Auxillaries contracts exist | `packages/api`, `packages/orm`, `packages/btd`, provider packages | pending |
100-
| Routes delegate readiness and policy derivation | Auxillaries API routes and focused route tests | pending |
101-
| JSON-safe serializers redact secrets and protected source | package tests and route tests | pending |
102-
| Commercial runtime avoids standalone demonstration imports | V31 Gate 2 checker | pending |
99+
| Package-owned Auxillaries contracts exist | `packages/api/src/routes/auxillaries-contract.ts` owns `AuxillariesContractSnapshot`, `AuxillariesProfileState`, `AuxillariesConnectionReadiness`, `AuxillariesInterfaceAdmission`, `AuxillariesWalletBtdPaneState`, `OrganizationPolicyAuthority`, `AuxillariesReadinessDiagnostic`, and `AuxillariesRecoveryRun` | drafted |
100+
| Routes delegate readiness and policy derivation | `packages/api/src/routes/auxillaries.ts` delegates live and mock data through `buildAuxillaryDataPayload` / `buildAuxillaryDataPayloadFromUnknown`; `uapi/app/api/auxillaries/data/route.ts` remains a thin interface binding | drafted |
101+
| JSON-safe serializers redact secrets and protected source | `packages/api/src/routes/__tests__/auxillaries-contract.test.ts` covers provider tokens, service-role keys, wallet secrets, private prompts, protected source, validation, diagnostics, and recovery-run roots | drafted |
102+
| Commercial runtime avoids standalone demonstration imports | `scripts/check-v31-gate2-auxillaries-package-route-contracts.mjs` scans tracked commercial runtime source and fails on `protocol-demonstration/src/*` imports | drafted |
103103

104104
## Gate 3 Parity
105105

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 1 spec and roadmap opening, which opens the V31 specification family, updates V30 active / V31 draft workflow posture, and refines the V31-V37 roadmap.
8+
- Current working gate: V31 Gate 2 Auxillaries package and route contracts, which makes Profile, Connects, Interfaces, Wallet, BTD, organization, readiness, and recovery support-state objects package-owned, JSON-safe, and route-consumable over the V30 Protocol/BTD substrate.
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
@@ -65,6 +65,7 @@
6565
"check:v30-gate9": "node scripts/check-v30-gate9-interface-integration-regression-proof.mjs",
6666
"check:v30-gate10": "node scripts/check-v30-gate10-promotion-readiness.mjs",
6767
"check:v31-gate1": "node scripts/check-v31-gate1-spec-roadmap-opening.mjs",
68+
"check:v31-gate2": "node scripts/check-v31-gate2-auxillaries-package-route-contracts.mjs",
6869
"check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic",
6970
"check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title",
7071
"check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24",

packages/api/README.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ status decisions, and framework-compatible response serialization. Route code
1414
must not duplicate BTD policy, mint admission, receipt derivation, settlement
1515
state construction, or JSON-safe conversion already exported by `@bitcode/btd`.
1616

17+
For Auxillaries route contracts, this package owns the route-facing support
18+
objects in `src/routes/auxillaries-contract.ts`. Route handlers may authenticate,
19+
read or write explicit storage rows, and choose response status, but
20+
Profile/Connects/Interfaces/Wallet/BTD/organization readiness and policy
21+
objects must be built through `buildAuxillariesContractSnapshot` and
22+
`buildAuxillaryDataPayload`. Those builders emit JSON-safe
23+
`AuxillariesProfileState`, `AuxillariesConnectionReadiness`,
24+
`AuxillariesInterfaceAdmission`, `AuxillariesWalletBtdPaneState`,
25+
`OrganizationPolicyAuthority`, `AuxillariesReadinessDiagnostic`, and
26+
`AuxillariesRecoveryRun` values. They redact provider tokens, API keys, wallet
27+
secrets, private prompts, protected source, service keys, and database
28+
credentials before UI, telemetry, or proof-hook consumption.
29+
1730
In V26 fourth-gate this package is where merged-world Bitcode becomes concrete:
1831
- `/conversations` continuity
1932
- `/executions` compatibility and pipeline-run APIs
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
import {
2+
AUXILLARIES_CONTRACT_VERSION,
3+
assertAuxillariesJsonSafe,
4+
buildAuxillaryDataPayload,
5+
buildAuxillariesRecoveryRun,
6+
normalizeAuxillaryPane,
7+
parseAuxillariesContractSnapshot,
8+
toAuxillariesJsonSafe,
9+
validateAuxillariesContractSnapshot,
10+
} from '../auxillaries-contract';
11+
12+
describe('Auxillaries package route contracts', () => {
13+
it('builds package-owned Auxillaries state with source-safe route payload compatibility', () => {
14+
const payload = buildAuxillaryDataPayload({
15+
profile: {
16+
id: 'user-1',
17+
username: 'operator',
18+
display_name: 'Operator',
19+
company_name: 'Bitcode',
20+
role: 'admin',
21+
wallet_binding: {
22+
address: 'tb1pauxcontract',
23+
provider: 'leather',
24+
status: 'verified',
25+
boundAt: '2026-05-21T00:00:00.000Z',
26+
},
27+
protectedSource: 'never visible to support UI',
28+
settings: {
29+
service_role_key: 'service-role-secret',
30+
},
31+
},
32+
githubConnection: {
33+
provider: 'github',
34+
login: 'bitcode',
35+
installationId: 123,
36+
access_token: 'ghp_secret',
37+
rawPrompt: 'private prompt body',
38+
},
39+
walletConnectionStatus: {
40+
connected: true,
41+
valid: true,
42+
provider: 'leather',
43+
address: 'tb1pauxcontract',
44+
verificationState: 'verified',
45+
metadata: {
46+
private_key: 'wallet-secret',
47+
connectedAt: '2026-05-21T00:00:00.000Z',
48+
},
49+
},
50+
repositoryConnectionStatus: {
51+
connected: true,
52+
valid: true,
53+
provider: 'github',
54+
username: 'bitcode',
55+
metadata: {
56+
token: 'provider-token',
57+
},
58+
},
59+
repositories: [
60+
{
61+
fullName: 'bitcode/core',
62+
owner: {
63+
username: 'bitcode',
64+
type: 'organization',
65+
},
66+
protected_source: 'repository source',
67+
},
68+
],
69+
repositoryInventorySource: 'stored_repository_inventory',
70+
btdBalance: 128,
71+
btcFeeBalance: 0.04,
72+
recentBtdAssetPacks: [
73+
{
74+
assetPackId: 'asset-pack-1',
75+
rangeStart: 1,
76+
rangeEndExclusive: 3,
77+
},
78+
],
79+
modelPreferences: {
80+
preferred_model: 'gpt-4.1',
81+
},
82+
onboardedSteps: ['btd', 'connects', 'profile', 'interfaces'],
83+
});
84+
85+
expect(payload.isOnboardingComplete).toBe(true);
86+
expect(payload.onboardedPanes).toEqual(['wallet', 'externals', 'profile', 'interfaces']);
87+
expect(payload.organizations).toEqual(['bitcode']);
88+
expect(payload.profileState.kind).toBe('AuxillariesProfileState');
89+
expect(payload.connectionReadiness[0]).toMatchObject({
90+
provider: 'github',
91+
connected: true,
92+
valid: true,
93+
credentialPosture: 'present_source_safe',
94+
});
95+
expect(payload.walletBtdPaneState.signerPosture).toMatchObject({
96+
ready: true,
97+
state: 'verified',
98+
});
99+
expect(payload.organizationAuthority.policyDecision).toBe('allowed');
100+
expect(payload.auxillariesContract.contractVersion).toBe(AUXILLARIES_CONTRACT_VERSION);
101+
expect(validateAuxillariesContractSnapshot(payload.auxillariesContract)).toEqual({
102+
valid: true,
103+
errors: [],
104+
});
105+
expect(parseAuxillariesContractSnapshot(payload.auxillariesContract).contractRoot)
106+
.toBe(payload.auxillariesContract.contractRoot);
107+
expect(JSON.stringify(payload)).not.toContain('ghp_secret');
108+
expect(JSON.stringify(payload)).not.toContain('service-role-secret');
109+
expect(JSON.stringify(payload)).not.toContain('wallet-secret');
110+
expect(JSON.stringify(payload)).not.toContain('repository source');
111+
expect(JSON.stringify(payload)).not.toContain('private prompt body');
112+
expect(assertAuxillariesJsonSafe(payload)).toBeUndefined();
113+
});
114+
115+
it('emits pane diagnostics for incomplete profile, missing provider, and missing wallet state', () => {
116+
const payload = buildAuxillaryDataPayload({
117+
profile: null,
118+
githubConnection: null,
119+
walletConnectionStatus: null,
120+
repositoryConnectionStatus: null,
121+
repositories: [],
122+
repositoryInventorySource: null,
123+
btdBalance: 0,
124+
btcFeeBalance: null,
125+
recentBtdAssetPacks: [],
126+
modelPreferences: null,
127+
onboardedSteps: [],
128+
});
129+
130+
const blockerIds = payload.readinessDiagnostics.map((diagnostic) => diagnostic.blockerId);
131+
expect(payload.profileState.accountReadiness).toBe('blocked');
132+
expect(payload.connectionReadiness[0].requiredRepairAction).toBe('connect_provider');
133+
expect(payload.walletBtdPaneState.signerPosture.requiredAction).toBe('connect_wallet');
134+
expect(blockerIds).toEqual(expect.arrayContaining([
135+
'profile.missing',
136+
'profile.identity_missing',
137+
'connects.github.connect_provider',
138+
'wallet.binding_missing',
139+
]));
140+
expect(payload.auxillariesContract.contractRoot).toMatch(/^[0-9a-f]{64}$/);
141+
});
142+
143+
it('normalizes pane aliases and redacts known secret or protected-source keys', () => {
144+
const safe = toAuxillariesJsonSafe({
145+
access_token: 'secret-token',
146+
privatePrompt: 'reasoning prompt',
147+
protectedSource: 'asset pack source',
148+
repositoryInventorySource: 'stored_repository_inventory',
149+
}) as Record<string, unknown>;
150+
151+
expect(normalizeAuxillaryPane('connects')).toBe('externals');
152+
expect(normalizeAuxillaryPane('btd')).toBe('wallet');
153+
expect(safe.access_token).toBe('[redacted]');
154+
expect(safe.privatePrompt).toBe('[protected-source-redacted]');
155+
expect(safe.protectedSource).toBe('[protected-source-redacted]');
156+
expect(safe.repositoryInventorySource).toBe('stored_repository_inventory');
157+
expect(() => assertAuxillariesJsonSafe(safe)).not.toThrow();
158+
});
159+
160+
it('parses contract snapshots and rejects malformed route contract objects', () => {
161+
const recoveryRun = buildAuxillariesRecoveryRun({
162+
targetPane: 'externals',
163+
repairAction: 'reauthorize_provider',
164+
beforeReadinessRoot: 'before-root',
165+
afterReadinessRoot: 'after-root',
166+
executionId: 'execution-1',
167+
outcome: 'succeeded',
168+
});
169+
const payload = buildAuxillaryDataPayload({
170+
profile: { id: 'user-2', username: 'reviewer' },
171+
githubConnection: { provider: 'github' },
172+
walletConnectionStatus: null,
173+
repositoryConnectionStatus: { connected: false, valid: false, provider: 'github' },
174+
repositories: [],
175+
repositoryInventorySource: null,
176+
btdBalance: 0,
177+
btcFeeBalance: null,
178+
recentBtdAssetPacks: [],
179+
modelPreferences: null,
180+
onboardedSteps: ['profile'],
181+
});
182+
const snapshot = {
183+
...payload.auxillariesContract,
184+
recoveryRuns: [recoveryRun],
185+
};
186+
187+
expect(parseAuxillariesContractSnapshot(snapshot).recoveryRuns[0].recoveryRoot)
188+
.toMatch(/^[0-9a-f]{64}$/);
189+
expect(validateAuxillariesContractSnapshot({ kind: 'wrong' })).toMatchObject({
190+
valid: false,
191+
});
192+
expect(() => parseAuxillariesContractSnapshot({ kind: 'wrong' })).toThrow(
193+
/Invalid Auxillaries contract snapshot/,
194+
);
195+
});
196+
});

0 commit comments

Comments
 (0)