Skip to content

Commit 1f4a3ee

Browse files
Close Gate 11 Finding Fits preview
Implements canonical ReadFitsFindingSynthesis tool telemetry for lexical and vector depository search posture, propagates accepted Need plus Finding Fits evidence into source-safe AssetPack previews, and exposes the deterministic Share-to-Fee quote through the postprocessed output. Adds Gate 11 specification, parity, QA, workflow, and package checks, with tests covering all qualifying fit deposits, canonical tool telemetry, preview storage, fee quotes, and protected-source non-disclosure before settlement.
1 parent ddaa805 commit 1f4a3ee

12 files changed

Lines changed: 491 additions & 31 deletions

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ jobs:
4747
node scripts/check-v28-metadevelopment-readiness.mjs --skip-branch-check
4848
node scripts/check-v28-gate9-depository-evidence.mjs
4949
node scripts/check-v28-gate10-read-need-comprehension.mjs
50+
node scripts/check-v28-gate11-read-fits-finding-preview.mjs
5051
node scripts/promote-bitcode-canon.mjs --version V28 --commit HEAD --dry-run
5152
5253
- name: Validate source casing and imports

BITCODE_SPEC_V28.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -850,6 +850,31 @@ Gate 11 owns `ReadFitsFindingSynthesis`: depository search, candidate fit
850850
ranking, fitting deposits as synthesis context, AssetPack measurement, source-
851851
safe preview, Share-to-Fee quote, and proof-rich Terminal stream visibility.
852852

853+
Gate 11 acceptance requires:
854+
855+
- discovery records all `fitDepositAssetIds` above the review and semantic
856+
thresholds, preserves the ranked candidate trace, and fails closed with
857+
`blocked_readiness` or `no_worthy_fit` instead of inventing source outside
858+
the depository;
859+
- lexical and vector depository search tool telemetry use canonical
860+
`ReadFitsFindingSynthesis.tool.*` ids and carry input read constraints,
861+
selected fit deposits, query root, ranking root, and embedding policy posture;
862+
- implementation and postprocess carry the Finding Fits result into a
863+
`bitcode.asset-pack.source-safe-preview` object with Need/Fit measurements,
864+
fit score band, candidate ids, proof roots, source-manifest root, preview
865+
root, access policy, settlement boundary, and unlock posture;
866+
- Share-to-Fee quote is deterministic:
867+
`sum(measurement.weight * measurement.volume * admitted_fit_quality)` over
868+
the accepted Need measurement vector and the admitted fit quality, with BTC
869+
sats, quote root, payer, and network-fee posture visible before settlement;
870+
- protected source, full patches, source-bearing manifest entries, and licensed
871+
read payloads stay withheld before settlement. Terminal may show only
872+
measurements, non-source metadata, roots, candidate ids, proof posture,
873+
ownership boundary, settlement boundary, and fee quote;
874+
- Terminal stream/history surfaces render the source-safe preview and fee quote
875+
without requiring Network-panel JSON inspection, while preserving expandable
876+
raw evidence for audit.
877+
853878
### Gate 12: Settlement, Rights, Delivery, And Reconciliation
854879

855880
Gate 12 owns BTC settlement, depositor/reader ownership boundaries, read-license

BITCODE_SPEC_V28_PARITY_MATRIX.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,18 @@ by a later V28 gate before `version/v28` can be promoted to `main`.
184184
| Full demonstration proof-suite alignment | Gate 13 | Refresh the older demonstration proof-member, theorem, public-projection, and V26-proven expectations so they match the active V27/V28 posture or are explicitly retired from V28 promotion proof. | `npm --prefix protocol-demonstration run test`, proof-member/theorem matrix counts, public projection spine assertions, and V26/V28 proven-generator assertions. | The complete demonstration suite is either green under the promoted V28 proof model or every intentionally retired legacy assertion is replaced by a narrower current-canon proof. |
185185
| Local and staging-testnet validation | Gate 13 | Local non-mocked OpenAI/Supabase/Vercel Sandbox validation plus staging-testnet readback evidence for complete Depositing -> Reading -> settlement -> PR delivery. | `check:v28-metadevelopment`, package tests, UAPI tests, build, demonstration tests, `qa:v28:pipeline-readback`, browser QA, SQL ledger/readback queries. | `version/v28` is promotion-ready only when local and staging-testnet evidence prove the full commercial product flow. |
186186

187+
Gate 11 closure narrows the two Gate 11 carryforward rows to source-safe
188+
preview readiness: Finding Fits discovery must now produce canonical
189+
`ReadFitsFindingSynthesis.tool.lexical-depository-search` and
190+
`ReadFitsFindingSynthesis.tool.vector-depository-search` telemetry, all
191+
threshold-passing `fitDepositAssetIds`, query/ranking roots, and embedding
192+
policy posture. AssetPack postprocess must derive a source-safe preview and
193+
Share-to-Fee quote from the accepted Need and Finding Fits result, exposing only
194+
measurements, roots, score bands, candidate ids, proof posture, ownership
195+
boundary, settlement boundary, and BTC quote before settlement. Gate 12 remains
196+
responsible for paid unlock, rights transfer, ledger reconciliation, and PR
197+
delivery.
198+
187199
## V28 implementation matrix
188200

189201
| Area | Current source evidence | Judgment | Gate owner |

BITCODE_V28_QA.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2103,3 +2103,44 @@ Expected V28 behavior:
21032103
- a later background revalidation may make the BTC/BTD widget show its own loading posture, but it must not regress to the disconnected CTA while a known wallet exists;
21042104
- client telemetry must include `nav:chrome-identity`, `user-data:fetch-start`, `user-data:read` or `user-data:anonymous-read`, and any fetch failure;
21052105
- server telemetry must include `auxillaries-data:read-start` and `auxillaries-data:read-finish` or `auxillaries-data:read-failed`.
2106+
2107+
### Gate 11 Finding Fits And Source-Safe Preview QA
2108+
2109+
Gate 11 local closure proves that `ReadFitsFindingSynthesis` can search the
2110+
depository, preserve every qualifying fit deposit, derive a source-safe preview,
2111+
and expose a deterministic Share-to-Fee quote before Gate 12 settlement unlock.
2112+
2113+
Required local checks:
2114+
2115+
```bash
2116+
pnpm run check:v28-gate11
2117+
pnpm --filter @bitcode/pipeline-asset-pack exec jest --config jest.config.cjs --runTestsByPath \
2118+
src/__tests__/depository-search.test.ts \
2119+
src/__tests__/read-need.test.ts \
2120+
src/__tests__/postprocess.test.ts \
2121+
src/__tests__/depository-search-tool.test.ts \
2122+
--runInBand --forceExit
2123+
pnpm --filter @bitcode/pipeline-asset-pack typecheck
2124+
```
2125+
2126+
Expected evidence:
2127+
2128+
- Finding Fits discovery stores `depository/search.result`,
2129+
`depository/search.toolTelemetry`, `fit.result`, `fit.selectionTrace`, all
2130+
threshold-passing `fitDepositAssetIds`, `queryRoot`, `rankingRoot`, and the
2131+
OpenAI `text-embedding-3-small` embedding policy posture.
2132+
- Tool telemetry uses canonical
2133+
`ReadFitsFindingSynthesis.tool.lexical-depository-search` and
2134+
`ReadFitsFindingSynthesis.tool.vector-depository-search` ids. Vector
2135+
telemetry must at minimum expose the declared vector-store and embedding
2136+
policy posture until a later gate replaces local lexical fallback with live
2137+
vector RPC readback.
2138+
- AssetPack postprocess stores `asset-pack/preview.sourceSafe`,
2139+
`asset-pack/preview.feeQuote`, and `asset-pack/preview.previewRoot` whenever
2140+
an accepted Need and Finding Fits result are present.
2141+
- The source-safe preview exposes Need/Fit measurements, score band, fit
2142+
deposit ids, selected candidate ids, roots, proof posture, access policy,
2143+
ownership boundary, settlement boundary, unlock posture, and BTC quote.
2144+
- The preview must not expose protected source content, full patches,
2145+
source-bearing manifest entries, licensed read payloads, or PR source changes
2146+
before settlement. Gate 12 owns paid unlock, rights transfer, and delivery.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
"check:v28-metadevelopment": "node scripts/check-v28-metadevelopment-readiness.mjs",
4242
"check:v28-gate9": "node scripts/check-v28-gate9-depository-evidence.mjs",
4343
"check:v28-gate10": "node scripts/check-v28-gate10-read-need-comprehension.mjs",
44+
"check:v28-gate11": "node scripts/check-v28-gate11-read-fits-finding-preview.mjs",
4445
"check:spec-quality": "node scripts/run-bitcode-spec-quality.mjs --mode basic",
4546
"check:spec-quality:title": "node scripts/run-bitcode-spec-quality.mjs --mode strict-from-title",
4647
"check:spec-quality:v24": "node scripts/run-bitcode-spec-quality.mjs --mode strict-version --version V24",

packages/pipelines/asset-pack/src/__tests__/depository-search.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,36 @@ describe('AssetPack depository search', () => {
292292
expect(findStored(exec, 'fit', 'resultState')).toBe('worthy_fit');
293293
expect(findStored(exec, 'depository/search', 'result')?.resultState).toBe('worthy_fit');
294294
expect(findStored(exec, 'depository/search', 'embeddingPolicy')?.dimensions).toBe(1536);
295+
expect(findStored(exec, 'depository/search', 'toolTelemetry')).toEqual([
296+
expect.objectContaining({
297+
tool: 'ReadFitsFindingSynthesis.tool.lexical-depository-search',
298+
phase: 'ReadFitsFindingSynthesis.discovery',
299+
agent: 'ReadFitsFindingSynthesis.discovery.finding-fits',
300+
step: 'ReadFitsFindingSynthesis.discovery.finding-fits.try',
301+
output: expect.objectContaining({
302+
resultState: 'worthy_fit',
303+
fitDepositAssetIds: ['asset_repository-revision-deposit-engineeredsoftware-engi'],
304+
queryRoot: expect.stringMatching(/^sha256:/),
305+
rankingRoot: expect.stringMatching(/^sha256:/),
306+
}),
307+
}),
308+
expect.objectContaining({
309+
tool: 'ReadFitsFindingSynthesis.tool.vector-depository-search',
310+
output: expect.objectContaining({
311+
resultState: 'embedding_policy_declared',
312+
vectorStore: expect.objectContaining({
313+
table: 'deliverable_vectors',
314+
rpc: 'match_deliverable_vectors',
315+
}),
316+
}),
317+
}),
318+
]);
319+
expect(findStored(exec, 'tools', 'lexical-depository-search')?.tool).toBe(
320+
'ReadFitsFindingSynthesis.tool.lexical-depository-search'
321+
);
322+
expect(findStored(exec, 'tools', 'vector-depository-search')?.tool).toBe(
323+
'ReadFitsFindingSynthesis.tool.vector-depository-search'
324+
);
295325
expect(output.fitResult.resultState).toBe('worthy_fit');
296326
expect(output.fitResult.fitDepositAssetIds).toEqual([
297327
'asset_repository-revision-deposit-engineeredsoftware-engi',

packages/pipelines/asset-pack/src/__tests__/postprocess.test.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// @ts-nocheck
22
import { buildAssetPackPostprocessedResult, normalizeAssetPackOutput } from '../postprocess';
33
import { Execution } from '@bitcode/execution-generics';
4+
import { acceptReadNeed, synthesizeReadNeedForPipelineInput } from '../read-need';
45

56
describe('normalizeAssetPackOutput', () => {
67
it('backfills prUrl, filesModified, and summary from execution', () => {
@@ -138,4 +139,94 @@ describe('normalizeAssetPackOutput', () => {
138139
prUrl: 'https://github.com/acme/repo/pull/26',
139140
});
140141
});
142+
143+
it('derives and stores source-safe preview evidence from an accepted Need and Finding Fits result', () => {
144+
const exec = new Execution('pipeline:asset-pack');
145+
const acceptedNeed = acceptReadNeed(synthesizeReadNeedForPipelineInput({
146+
read: {
147+
id: 'read-1',
148+
prompt: 'Find deposited source evidence for a source-safe Terminal AssetPack preview.',
149+
},
150+
sourceRevision: {
151+
repositoryFullName: 'engineeredsoftware/ENGI',
152+
branch: 'main',
153+
commit: '31bbc0c5227b6b3aed5d107fd8507d35ec22970a',
154+
},
155+
}));
156+
const fitResult = {
157+
schema: 'bitcode.asset-pack.fit-result',
158+
resultState: 'worthy_fit',
159+
resultReasons: ['Selected 1 proof-bearing fit deposit for this Read.'],
160+
fitDepositAssetIds: ['fit-deposit-1'],
161+
selectedCandidateAssetIds: ['fit-deposit-1'],
162+
queryRoot: 'sha256:query',
163+
rankingRoot: 'sha256:ranking',
164+
searchedAssetCount: 1,
165+
embeddingPolicy: {
166+
provider: 'openai',
167+
model: 'text-embedding-3-small',
168+
dimensions: 1536,
169+
},
170+
selectionTrace: {
171+
selectedCandidates: [
172+
{
173+
assetId: 'fit-deposit-1',
174+
scores: { finalScore: 0.84 },
175+
proofEvidence: { proofRoot: 'sha256:proof' },
176+
},
177+
],
178+
fitDeposits: [],
179+
blockedCandidates: [],
180+
candidateRanking: [],
181+
rejectedCandidateCount: 0,
182+
},
183+
};
184+
185+
exec.store('read/need', 'accepted', acceptedNeed);
186+
exec.store('fit', 'result', fitResult);
187+
188+
const normalized = normalizeAssetPackOutput({
189+
success: true,
190+
summary: 'Measured AssetPack preview ready.',
191+
deliveryMechanism: {
192+
prUrl: 'https://github.com/engineeredsoftware/ENGI/pull/28',
193+
},
194+
} as any, exec);
195+
const result = buildAssetPackPostprocessedResult(exec, normalized);
196+
197+
expect(normalized.sourceSafePreview).toMatchObject({
198+
schema: 'bitcode.asset-pack.source-safe-preview',
199+
need: {
200+
needId: acceptedNeed.needId,
201+
reviewState: 'accepted',
202+
},
203+
fit: {
204+
resultState: 'worthy_fit',
205+
fitDepositAssetIds: ['fit-deposit-1'],
206+
scoreBand: 'high',
207+
},
208+
disclosurePolicy: {
209+
protectedSourceDisclosure: 'forbidden_before_settlement',
210+
},
211+
settlementBoundary: {
212+
payer: 'reader',
213+
payee: 'depositor',
214+
serverCustody: false,
215+
},
216+
unlock: {
217+
state: 'pending_settlement',
218+
sourceAvailable: false,
219+
},
220+
});
221+
expect(normalized.sourceSafePreview.delivery.pullRequestTarget).toBe(
222+
'https://github.com/engineeredsoftware/ENGI/pull/28'
223+
);
224+
expect(normalized.feeQuote.quoteRoot).toMatch(/^sha256:/);
225+
expect(result.sourceSafePreview?.roots.previewRoot).toMatch(/^sha256:/);
226+
expect(result.feeQuote?.finalityState).toBe('preview_not_paid');
227+
expect(exec.get('asset-pack/preview', 'sourceSafe')?.previewId).toBe(
228+
normalized.sourceSafePreview.previewId
229+
);
230+
expect(JSON.stringify(normalized.sourceSafePreview)).not.toContain('diff --git');
231+
});
141232
});

packages/pipelines/asset-pack/src/depository-search.ts

Lines changed: 65 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,11 @@ const DEFAULT_THRESHOLDS: DepositorySearchThresholds = {
269269
maxSelectedCandidates: 3,
270270
};
271271

272+
export const READ_FITS_FINDING_SYNTHESIS_TOOL_IDS = {
273+
lexicalDepositorySearch: 'ReadFitsFindingSynthesis.tool.lexical-depository-search',
274+
vectorDepositorySearch: 'ReadFitsFindingSynthesis.tool.vector-depository-search',
275+
} as const;
276+
272277
const STOP_WORDS = new Set([
273278
'the',
274279
'and',
@@ -1280,42 +1285,67 @@ function storeDepositorySearchToolResult(
12801285
): void {
12811286
if (!execution?.store) return;
12821287
const { read, assets, result, providerIds } = input;
1283-
execution.store('tools', 'result', {
1284-
tool: 'bitcode.depository.search',
1285-
ok: true,
1286-
input: {
1287-
read: {
1288-
id: read.id || null,
1289-
repositoryFullName: read.repositoryFullName || null,
1290-
sourceBranch: read.sourceBranch || null,
1291-
sourceCommit: read.sourceCommit || null,
1292-
targetArtifactKinds: read.targetArtifactKinds,
1293-
closureCriteriaCount: read.closureCriteria.length,
1294-
failureModeCount: read.failureModes.length,
1295-
},
1296-
assetCount: assets.length,
1297-
providerIds,
1288+
const toolInput = {
1289+
read: {
1290+
id: read.id || null,
1291+
repositoryFullName: read.repositoryFullName || null,
1292+
sourceBranch: read.sourceBranch || null,
1293+
sourceCommit: read.sourceCommit || null,
1294+
targetArtifactKinds: read.targetArtifactKinds,
1295+
closureCriteriaCount: read.closureCriteria.length,
1296+
failureModeCount: read.failureModes.length,
12981297
},
1298+
assetCount: assets.length,
1299+
providerIds,
1300+
};
1301+
const toolOutput = {
1302+
schema: result.schema,
1303+
resultState: result.resultState,
1304+
resultReasons: result.resultReasons,
1305+
searchedAssetCount: result.searchedAssetCount,
1306+
fitDepositAssetIds: result.fitDepositAssetIds,
1307+
fitDepositCount: result.fitDeposits.length,
1308+
selectedCandidateAssetIds: result.selectedCandidateAssetIds,
1309+
selectedCandidateCount: result.selectedCandidates.length,
1310+
blockedCandidateCount: result.blockedCandidates.length,
1311+
rejectedCandidateCount: result.rejectedCandidates.length,
1312+
queryRoot: result.queryRoot,
1313+
rankingRoot: result.rankingRoot,
1314+
embeddingPolicy: result.embeddingPolicy,
1315+
};
1316+
const lexicalTelemetry = {
1317+
tool: READ_FITS_FINDING_SYNTHESIS_TOOL_IDS.lexicalDepositorySearch,
1318+
ok: true,
1319+
input: toolInput,
1320+
output: toolOutput,
1321+
phase: 'ReadFitsFindingSynthesis.discovery',
1322+
agent: 'ReadFitsFindingSynthesis.discovery.finding-fits',
1323+
step: 'ReadFitsFindingSynthesis.discovery.finding-fits.try',
1324+
generation: 'tools_execution',
1325+
};
1326+
const vectorTelemetry = {
1327+
tool: READ_FITS_FINDING_SYNTHESIS_TOOL_IDS.vectorDepositorySearch,
1328+
ok: true,
1329+
input: toolInput,
12991330
output: {
1300-
schema: result.schema,
1301-
resultState: result.resultState,
1302-
resultReasons: result.resultReasons,
1303-
searchedAssetCount: result.searchedAssetCount,
1304-
fitDepositAssetIds: result.fitDepositAssetIds,
1305-
fitDepositCount: result.fitDeposits.length,
1331+
resultState: 'embedding_policy_declared',
13061332
selectedCandidateAssetIds: result.selectedCandidateAssetIds,
1307-
selectedCandidateCount: result.selectedCandidates.length,
1308-
blockedCandidateCount: result.blockedCandidates.length,
1309-
rejectedCandidateCount: result.rejectedCandidates.length,
1333+
fitDepositAssetIds: result.fitDepositAssetIds,
13101334
queryRoot: result.queryRoot,
13111335
rankingRoot: result.rankingRoot,
13121336
embeddingPolicy: result.embeddingPolicy,
1337+
vectorStore: result.embeddingPolicy.vectorStore,
13131338
},
1314-
phase: 'setup',
1315-
agent: 'setup:depository-search',
1316-
step: 'try',
1339+
phase: 'ReadFitsFindingSynthesis.discovery',
1340+
agent: 'ReadFitsFindingSynthesis.discovery.finding-fits',
1341+
step: 'ReadFitsFindingSynthesis.discovery.finding-fits.try',
13171342
generation: 'tools_execution',
1318-
});
1343+
};
1344+
1345+
execution.store('tools', 'result', lexicalTelemetry);
1346+
execution.store('tools', 'lexical-depository-search', lexicalTelemetry);
1347+
execution.store('tools', 'vector-depository-search', vectorTelemetry);
1348+
execution.store('depository/search', 'toolTelemetry', [lexicalTelemetry, vectorTelemetry]);
13191349
}
13201350

13211351
function buildBlockedReadFitsFindingResult(input: {
@@ -1406,12 +1436,17 @@ export async function runDepositorySearchForPipelineInput(
14061436
if (execution?.store) {
14071437
storeEvidence(execution);
14081438
storeEvidence(execution.parent as { store?: (namespace: string, key: string, value: unknown) => void });
1409-
storeDepositorySearchToolResult(execution, {
1439+
const toolEvidence = {
14101440
read,
14111441
assets,
14121442
result,
14131443
providerIds: providers.map((provider) => provider.id),
1414-
});
1444+
};
1445+
storeDepositorySearchToolResult(execution, toolEvidence);
1446+
storeDepositorySearchToolResult(
1447+
execution.parent as { store?: (namespace: string, key: string, value: unknown) => void },
1448+
toolEvidence
1449+
);
14151450
}
14161451

14171452
return result;

0 commit comments

Comments
 (0)