Skip to content

Commit 233afd1

Browse files
V48 Gate 3 (specification-implementation): deposit Implementation emits a measured patch via the code-edit tool
Each synthesized AssetPack is now a measured PATCH: the measured option fields plus a SOURCE-SAFE patch descriptor (fileChanges [path+op] + a natural-language patchSummary; never raw code). New AssetPackPatchWriteTool (ExecutionTool) records the descriptor (physical workspace fs-write is the delivery context, out of scope). The deposit synthesis agent reads the Discovery stores (codebase/depository/regurgitation comprehension) + the obfuscation comprehension, synthesizes the patch descriptor honoring obfuscations + exclusions, calls the tool per pack, and stores implementation:assetPacks (full measured-patch packs) + implementation:options (reviewable face; validateDepositSynthesisOptions reads the measured fields, ignores patch). Source-safety: no raw patch code in any schema/store/tool/telemetry — descriptor + measurements + summaries only. asset-pack 42/208 + typecheck green. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 9e6b27e commit 233afd1

3 files changed

Lines changed: 168 additions & 24 deletions

File tree

BITCODE_SPEC_V48_NOTES.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,16 @@ The five phases (same agents in both modes, lens-varied — decided 2026-06-25):
260260
/ references).
261261
- **Implementation**: synthesize the AssetPack patch(es) with their absolute
262262
measurements (read additionally computes the fit measurements and the BTD).
263+
Each candidate is a measured patch — the measured option fields plus a
264+
SOURCE-SAFE patch descriptor (`fileChanges` [path + change-op] and a
265+
natural-language `patchSummary`), recorded via the `AssetPackPatchWriteTool`
266+
(a formal `ExecutionTool`) which the synthesis agent reads from the Discovery
267+
stores (`discovery:codebaseComprehension` / `:depositorySearch` /
268+
`:inherentRegurgitation`) and the obfuscation comprehension. Pre-settlement the
269+
RAW patch content is never produced — only the descriptor + measurements are
270+
reviewable (stored at `implementation:assetPacks`; the reviewable face at
271+
`implementation:options`). Physical materialization of the raw content into the
272+
cloned workspace is the delivery/settlement context.
263273
- **Validation**: quality thresholds, coverage/corrections/fixes, and AssetPack
264274
smoke/sanity checks; the Discovery/Implementation/Validation loop iterates until
265275
complete or maxIterations.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/**
2+
* AssetPackPatchWriteTool — formal code-edit (patch) materialization tool (V48 Gate 3).
3+
*
4+
* Per spec, a completely synthesized AssetPack is a MEASURED PATCH:
5+
* patch + measurements + metadata. This formal ExecutionTool is the code-edit
6+
* primitive for the patch half of that artifact: it RECORDS the patch the
7+
* AssetPack contributes as a tool-tracked materialization that renders on the
8+
* SDIVF telemetry spine, exactly like AssetPackInventoryTool records the
9+
* exclusion-filtered source inventory.
10+
*
11+
* Source-safety (the hard constraint): this tool records the SOURCE-SAFE patch
12+
* DESCRIPTOR only — the set of file changes as (path + change op) — and NOTHING
13+
* ELSE. It never accepts, holds, or returns raw patch code, file contents, diffs,
14+
* or secrets. Because ExecutionTool persists both the call args and the return
15+
* value into the tool's child execution (which streams to execution_events),
16+
* keeping the descriptor path/op-only is what preserves the pre-settlement
17+
* source-safety invariant.
18+
*
19+
* It RECORDS, it does not fs-write: the returned `materialized: false` marks that
20+
* no physical workspace write happened here. Physical materialization of the
21+
* patch into a workspace is the delivery/sandbox context and is explicitly OUT
22+
* OF SCOPE. The descriptor recorded here is the artifact the depositor reviews
23+
* before admission.
24+
*/
25+
26+
import { ExecutionTool } from '@bitcode/agent-generics';
27+
28+
export type AssetPackPatchWriteArgs = {
29+
fileChanges: Array<{ path: string; op: 'create' | 'modify' | 'delete' }>;
30+
assetPackTitle?: string;
31+
};
32+
33+
export type AssetPackPatchWriteDescriptor = {
34+
materialized: boolean;
35+
fileChanges: Array<{ path: string; op: string }>;
36+
};
37+
38+
export class AssetPackPatchWriteTool extends ExecutionTool<
39+
(args: AssetPackPatchWriteArgs) => Promise<AssetPackPatchWriteDescriptor>
40+
> {
41+
use = async (args: AssetPackPatchWriteArgs): Promise<AssetPackPatchWriteDescriptor> => ({
42+
// Records, does not fs-write: physical workspace materialization is the
43+
// delivery context (out of scope). Returns ONLY the source-safe descriptor.
44+
materialized: false,
45+
fileChanges: (args.fileChanges || []).map((fc) => ({ path: fc.path, op: fc.op })),
46+
});
47+
}

packages/pipelines/asset-pack/src/agents/implementation/deposit-asset-pack-synthesis-agent.ts

Lines changed: 111 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,56 @@
22
* Deposit-mode AssetPack synthesis agent (V48 Gate 3).
33
*
44
* The deposit lens of the SynthesizeAssetPacks Implementation phase: synthesize
5-
* reviewable, MEASURED AssetPack candidate options from the DEPOSITOR's
6-
* repository source — bounded, source-safe slices of repository knowledge the
7-
* depositor reviews and uploads to the Depository as supply. Runs on the formal
8-
* PTRR machinery (factoryAgentWithPTRR → Plan/Try/Refine/Retry, each a Failsafe
9-
* × Thricified generation) so every call renders in the SDIVF telemetry.
5+
* reviewable AssetPacks from the DEPOSITOR's repository. Per spec, each AssetPack
6+
* is a completely synthesized artifact = a MEASURED PATCH (patch + measurements +
7+
* metadata): the existing measured option fields PLUS a source-safe patch
8+
* descriptor. The agent reasons over the Discovery comprehension stores (codebase
9+
* comprehension, depository-fit search, inherent regurgitation) and obfuscation
10+
* guidance — not raw source. Runs on the formal PTRR machinery
11+
* (factoryAgentWithPTRR → Plan/Try/Refine/Retry, each a Failsafe × Thricified
12+
* generation) so every call renders in the SDIVF telemetry. Each synthesized
13+
* patch is then recorded through the formal AssetPackPatchWriteTool code-edit
14+
* primitive (a tracked materialization, not an fs-write).
1015
*
11-
* Output is the candidate-options shape (options[] with per-pack measurements)
12-
* the /deposit review surface consumes; the surrounding pipeline (Setup clone,
13-
* Discovery exploration, Validation, Finish upload-for-review) wraps it.
16+
* Output is the measured-patch AssetPacks (options[]); the same array is stored as
17+
* both implementation:assetPacks and implementation:options. The /deposit review
18+
* surface consumes the measured option fields and ignores the patch field; the
19+
* surrounding pipeline (Setup clone, Discovery exploration, Validation, Finish
20+
* upload-for-review) wraps it.
1421
*
15-
* Source-safety: candidates are source-safe metadata (knowledge + capability),
16-
* never raw source. Protected-IP exclusions are honored absolutely.
22+
* Source-safety (hard constraint): NO raw patch code ever reaches telemetry or any
23+
* store. AssetPacks carry source-safe metadata (knowledge + capability) and a
24+
* source-safe patch DESCRIPTOR (file paths + change ops + a natural-language
25+
* patchSummary) — never raw source, code, diffs, or contents. Depositor
26+
* obfuscations and protected-IP exclusions are honored absolutely.
1727
*/
1828

1929
import { factoryAgentWithPTRR } from '@bitcode/agent-generics';
2030
import { Prompt } from '@bitcode/prompts/prompt';
2131
import type { PromptPart } from '@bitcode/prompts/parts/PromptPart';
2232
import { z } from 'zod';
2333
import { DEPOSIT_MEASUREMENT_CATALOG } from '../../asset-packs-synthesis';
34+
import { AssetPackPatchWriteTool } from './asset-pack-patch-write-tool';
2435

2536
const part = (content: string): PromptPart => content as PromptPart;
2637

2738
const DEPOSIT_OPTION_KINDS = ['capability-slice', 'implementation-pattern', 'proof-operations-slice'] as const;
2839

40+
// The SOURCE-SAFE patch descriptor: which files the AssetPack creates/modifies as
41+
// code edits (path + change op), plus a source-safe natural-language summary of
42+
// the synthesized knowledge. NEVER raw code, file contents, or diffs.
43+
const patchSchema = z.object({
44+
fileChanges: z
45+
.array(
46+
z.object({
47+
path: z.string(),
48+
op: z.enum(['create', 'modify', 'delete']),
49+
}),
50+
)
51+
.min(1),
52+
patchSummary: z.string(),
53+
});
54+
2955
const candidateSchema = z.object({
3056
kind: z.string().min(1),
3157
title: z.string().min(8).max(160),
@@ -34,6 +60,9 @@ const candidateSchema = z.object({
3460
measurements: z.record(z.string(), z.coerce.number().min(0).max(1)),
3561
measurementRationale: z.string().min(20).max(700),
3662
confidence: z.coerce.number().min(0).max(1),
63+
// Each AssetPack is a MEASURED PATCH: the measured option fields above PLUS the
64+
// source-safe patch descriptor below (patch + measurements + metadata).
65+
patch: patchSchema,
3766
});
3867

3968
const candidateSetSchema = z.object({
@@ -46,40 +75,58 @@ const DEPOSIT_IDENTITY = part(
4675
'You are SynthesizeAssetPacks in DEPOSIT mode. A depositor supplies their ' +
4776
'repository knowledge as AssetPacks — bounded, source-safe slices the ' +
4877
'Depository holds as supply, where future readers find Need-fitting packs. ' +
49-
'Synthesize 2-4 DISTINCT, measured AssetPack candidate options from the ' +
50-
'explored repository the depositor can review and admit. Describe knowledge ' +
51-
'and capability — never quote raw source, secrets, or file contents. Honor ' +
52-
'protected-IP exclusions absolutely.',
78+
'Each AssetPack is a completely synthesized artifact = a MEASURED PATCH ' +
79+
'(patch + measurements + metadata). Synthesize 2-4 DISTINCT, measured ' +
80+
'AssetPack patches from the explored repository the depositor can review and ' +
81+
'admit, reasoning over the Discovery comprehension (codebase comprehension, ' +
82+
'depository-fit search, inherent regurgitation) and obfuscation guidance you ' +
83+
'are given. Describe knowledge and capability and the SHAPE of the patch — ' +
84+
'never quote raw source, code, secrets, or file contents. Honor the depositor ' +
85+
'obfuscations and protected-IP exclusions absolutely.',
5386
);
5487

5588
const DEPOSIT_REQUIREMENTS = part(
5689
[
57-
'Each candidate is a distinct, commercially-legible knowledge slice:',
90+
'Ground every candidate in the provided Discovery comprehension — the codebase',
91+
'comprehension, the depository-fit search, and the inherent regurgitation — and',
92+
'honor the obfuscation guidance and protected-IP exclusions absolutely.',
93+
'Each candidate is a distinct, commercially-legible knowledge slice — a MEASURED',
94+
'PATCH (measured option fields + a source-safe patch descriptor):',
5895
`- kind: one of ${DEPOSIT_OPTION_KINDS.join(', ')}.`,
5996
'- title + source-safe summary (knowledge/capability, never raw text).',
6097
'- coveredSourcePaths: chosen ONLY from the provided inventory paths, exactly as written.',
6198
'- measurements: an object with EXACTLY these 0..1 keys, each an honest volume:',
6299
...DEPOSIT_MEASUREMENT_CATALOG.map((spec) => ` ${spec.measurementKind}: ${spec.guidance}`),
63100
'- measurementRationale justifying every measurement; confidence 0..1.',
101+
'- patch: the SOURCE-SAFE patch DESCRIPTOR for this AssetPack — the code edits it',
102+
' contributes, derived from your Discovery comprehension:',
103+
' - fileChanges: a non-empty list of { path, op } where op is create | modify | delete,',
104+
' naming which files the AssetPack creates/modifies/deletes (paths from the inventory,',
105+
' honoring obfuscations + exclusions). Provide ONLY path + op — NEVER code, diffs, or contents.',
106+
' - patchSummary: a source-safe natural-language summary of the synthesized knowledge the',
107+
' patch encodes (what it does and why it is legible to a buyer) — NEVER raw source or code.',
64108
'Return ONLY {"options":[ ... ]} — the top-level key MUST be "options".',
65109
].join('\n'),
66110
);
67111

68112
const DEPOSIT_PLAN = part(
69-
'Plan: from the explored repository inventory + depositor steering, identify the ' +
70-
'distinct, buyer-legible AssetPack slices the repository supports.',
113+
'Plan: from the explored repository inventory, the Discovery comprehension, and ' +
114+
'depositor steering, identify the distinct, buyer-legible AssetPack patches the ' +
115+
'repository supports.',
71116
);
72117
const DEPOSIT_TRY = part(
73-
'Try: synthesize each candidate option with kind, title, source-safe summary, ' +
74-
'covered source paths, honest measurements, and a measurement rationale.',
118+
'Try: synthesize each candidate as a measured patch — kind, title, source-safe ' +
119+
'summary, covered source paths, honest measurements, a measurement rationale, ' +
120+
'and the source-safe patch descriptor (fileChanges path+op + patchSummary).',
75121
);
76122
const DEPOSIT_REFINE = part(
77-
'Refine: ensure each option is distinct, source-safe, exclusion-honoring, and ' +
78-
'legible to a future buyer; verify measurements are honest 0..1 volumes.',
123+
'Refine: ensure each option is distinct, source-safe, obfuscation- and ' +
124+
'exclusion-honoring, and legible to a future buyer; verify the patch descriptor ' +
125+
'names only inventory paths (no code/contents) and measurements are honest 0..1 volumes.',
79126
);
80127
const DEPOSIT_RETRY = part(
81-
'Retry: complete any missing option as a minimal valid source-safe candidate ' +
82-
'rather than failing the synthesis.',
128+
'Retry: complete any missing option as a minimal valid source-safe measured patch ' +
129+
'(at least one fileChange + a patchSummary) rather than failing the synthesis.',
83130
);
84131

85132
function createDepositSynthesisPrompt(): Prompt {
@@ -131,6 +178,14 @@ export default async function runDepositAssetPackSynthesisAgent(input: any, exec
131178
const inventory = input?.inventory ?? findValue(execution, 'deposit', 'inventory');
132179
const demandContext = input?.demandContext ?? findValue(execution, 'deposit', 'demandContext') ?? [];
133180

181+
// Read the Discovery + obfuscation comprehension stores: each AssetPack is a
182+
// measured PATCH synthesized FROM this comprehension (not from raw source).
183+
const codebaseComprehension = findValue(execution, 'discovery', 'codebaseComprehension');
184+
const depositorySearch = findValue(execution, 'discovery', 'depositorySearch');
185+
const inherentRegurgitation = findValue(execution, 'discovery', 'inherentRegurgitation');
186+
const obfuscationGuidance =
187+
input?.obfuscationGuidance ?? findValue(execution, 'setup', 'inputComprehension');
188+
134189
const result = await DepositAssetPackSynthesisAgent(
135190
{
136191
...input,
@@ -141,24 +196,56 @@ export default async function runDepositAssetPackSynthesisAgent(input: any, exec
141196
inventory,
142197
inventoryPaths: inventory?.paths,
143198
excerpts: inventory?.samples,
199+
obfuscationGuidance,
144200
discovery: {
145201
context: execution?.get?.('discovery', 'context'),
146202
plan: execution?.get?.('discovery', 'plan'),
203+
codebase: codebaseComprehension,
204+
depository: depositorySearch,
205+
regurgitation: inherentRegurgitation,
147206
},
148207
},
149208
execution,
150209
);
151210

152211
const options = Array.isArray((result as any)?.options) ? (result as any).options : [];
212+
213+
// Record each AssetPack's patch through the formal code-edit tool. The tool is a
214+
// tracked materialization: it RECORDS the SOURCE-SAFE descriptor (path + op) and
215+
// returns it — it does not fs-write (physical workspace materialization is the
216+
// delivery context). Both the tool args and result are path/op-only, so the
217+
// tool's telemetry stays source-safe.
218+
try {
219+
(execution as any)?.tools?.registerTool?.('asset-pack-patch-write', new AssetPackPatchWriteTool());
220+
} catch {}
221+
for (const option of options) {
222+
const fileChanges = (option as any)?.patch?.fileChanges;
223+
if (!Array.isArray(fileChanges)) continue;
224+
try {
225+
const tool = (execution as any)?.tools?.getTool?.('asset-pack-patch-write');
226+
if (tool) {
227+
const descriptor = await tool.execute({
228+
fileChanges,
229+
assetPackTitle: (option as any)?.title,
230+
});
231+
(option as any).patch.fileChanges = descriptor.fileChanges;
232+
}
233+
} catch {}
234+
}
235+
153236
const output = {
154237
success: true,
155238
semanticKind: 'asset-pack-written-asset' as const,
156239
options,
157-
summary: `Synthesized ${options.length} measured deposit AssetPack option(s).`,
240+
summary: `Synthesized ${options.length} measured deposit AssetPack patch(es).`,
158241
assetPack: { repository },
159242
};
160243

161244
try {
245+
// Full measured-patch AssetPacks (each option = measured fields + source-safe patch).
246+
execution.store('implementation', 'assetPacks', options);
247+
// Reviewable options — the SAME array; the route's validateDepositSynthesisOptions
248+
// reads only the measured fields and ignores the extra patch field.
162249
execution.store('implementation', 'options', options);
163250
execution.store('implementation', 'assetPack', output.assetPack);
164251
execution.store('implementation', 'summary', output.summary);

0 commit comments

Comments
 (0)