Skip to content

Commit 356785c

Browse files
V48 Gate 3 (spec-impl): Plan then write patchfile artifact
Split deposit Implementation into patch-plan, patchfile write (one AssetPackPatchArtifact path-op-json per pack as 7th field), then measurements. Wire sequential phase; Validation requires patchArtifact.
1 parent dfaa5af commit 356785c

18 files changed

Lines changed: 901 additions & 627 deletions

.specifications/BITCODE_SPEC_V48.md

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ keys for the same agent loader.
495495
| preprocess | deposit-only | Repository coords + steering; catalog may be empty until Host/Setup |
496496
| Setup | (1) **clone alone** → (2) **parallel** {initialize-lsp, initialize-mcps-tools, comprehend-obfuscations} → (3) **danger-wall alone** | Clone first; danger wall last admits obfuscations |
497497
| Discovery | **parallel** {comprehend-codebase, search-depository, inherent-regurgitation} | Measure is **inside** comprehend-codebase, not a separate agent |
498-
| Implementation | **sequential** (1) `implementation:deposit-implementation-agent-asset-packs-patchfile-synthesis` → (2) `implementation:deposit-implementation-agent-asset-packs-measurements-synthesis` | Same AssetPack(s): **patchfile first**, then **absolute measurements**; deposit = patch + `measurements.absolutes` + metadata only |
498+
| Implementation | **sequential** (1) `…-patch-plan` → (2) `…-patchfile` → (3) `…-measurements-synthesis` | Same AssetPack(s): **plan descriptors** **write one path-op-json patchfile artifact per pack****measure**; deposit = descriptor + patchArtifact + `measurements.absolutes` + metadata |
499499
| Validation | **one** agent: `validation:ready-to-finish-asset-packs-synthesis-deposit-pipeline` | A prior phases · B pack quality · C obfuscations vs patch. **Validate only** — never measure/repair; weak Implementation → **iterate** |
500500
| Finish | (1) store-artifacts → (2) ledgerize → (3) finish-synthesize-asset-packs-for-deposit-run | Persist · journal roots · selection envelope / cleanup |
501501
| postprocess | normalize | Presentation-safe result for route |
@@ -666,17 +666,18 @@ Stores: `discovery:depositorySearch`, `discovery:depositorySearchQueries`,
666666
`{ regurgitation: { summary, relevantKnowledge?, patterns?, references? } }`
667667
`discovery:inherentRegurgitation`.
668668

669-
#### Implementation (two sequential agents — same AssetPacks)
669+
#### Implementation (three sequential agents — same AssetPacks)
670670

671-
Deposit AssetPack = **patchfile + absolute measurements + metadata**.
671+
Deposit AssetPack = **patch descriptor + singular patchfile artifact + absolute measurements + metadata**.
672672
Neediness is **Read-pipeline only** and is never a deposit Implementation product field.
673673

674674
| Order | Registry key | Module | Objective |
675675
|---|---|---|---|
676-
| 1/2 | `implementation:deposit-implementation-agent-asset-packs-patchfile-synthesis` | `agents/implementation/deposit-implementation-agent-asset-packs-patchfile-synthesis.ts` (+ schema/prompts) | 2–4 options; LLM synthesizes **six fields only** (kind, title, summary, coveredSourcePaths, confidence, patch); host catalog/exclusion gates; `asset-pack-patch-write` |
677-
| 2/2 | `implementation:deposit-implementation-agent-asset-packs-measurements-synthesis` | `agents/implementation/deposit-implementation-agent-asset-packs-measurements-synthesis.ts` | For each pack: register `SourceStaticAnalysisTool`; `measureAssetPackAbsolutes` (quantity tool-authoritative + quality inference into catalog); build `measurements: { absolutes }` via allowlist constructor |
676+
| 1 | `implementation:deposit-implementation-agent-asset-packs-patch-plan` | `…/deposit-implementation-agent-asset-packs-patch-plan.ts` (+ schema/prompts) | 2–4 options; LLM **six fields only**; host catalog/exclusion gates; **no artifact write** |
677+
| 2 | `implementation:deposit-implementation-agent-asset-packs-patchfile` | `…/deposit-implementation-agent-asset-packs-patchfile.ts` | For each planned pack: **write one** `AssetPackPatchArtifact` (`path-op-json`, no bodies) via `buildAssetPackPatchArtifact`; attach `patchArtifact` (7th field); telemetry path+op record |
678+
| 3 | `implementation:deposit-implementation-agent-asset-packs-measurements-synthesis` | `…/deposit-implementation-agent-asset-packs-measurements-synthesis.ts` | Requires `patchArtifact`; static analysis + quality inference into catalog; `measurements: { absolutes }` |
678679

679-
**Agent 1/2 LLM output (allowlist — no other keys):**
680+
**Agent 1 (patch-plan) LLM output (allowlist — no other keys):**
680681

681682
```
682683
{
@@ -694,23 +695,20 @@ Neediness is **Read-pipeline only** and is never a deposit Implementation produc
694695
}
695696
```
696697

697-
**Agent 2/2 host output (per pack):** same six fields +
698-
`measurements: { absolutes: AbsoluteReading[] }` (catalog-complete; magnitude+volume) +
699-
optional legacy dual-write `absolutes[]`. **No other measurement keys.**
698+
**Agent 2 (patchfile write) host output (per pack):** same six fields +
699+
`patchArtifact: { artifactId, assetPackId, format:'path-op-json', files[{path,op}], envelopeJson, … }`
700+
**exactly one** formal artifact per pack; files ≡ `patch.fileChanges`.
700701

701-
**Host salvage (patchfile agent only):** if model Refine empties usable options, host may build
702-
continuity packs with `salvaged: true`. Salvage is **never presentable**, never selectable,
703-
and Validation **must iterate** (not Finish). Prefer model-grounded packs; salvage is fail-open
704-
for pipeline continuity only.
702+
**Agent 3 (measurements) host output (per pack):** agent-2 pack +
703+
`measurements: { absolutes: AbsoluteReading[] }` (catalog-complete; magnitude+volume).
705704

706-
**Stores (after agent 2/2):**
707-
`implementation:options` / `implementation:assetPacks` (measured packs),
708-
`implementation:patchedOptions` (pre-measure snapshot),
709-
`implementation:measured` (bool), `implementation:presentable` (bool),
710-
`implementation:salvaged` / `salvageCount`, `implementation:measurementReports`,
711-
`implementation:summary`, `implementation:assetPack`.
705+
**Host salvage (patch-plan only):** continuity packs with `salvaged: true` may be written as
706+
artifacts but are **never presentable**; Validation **must iterate**.
712707

713-
**Compat shim:** `deposit-asset-pack-synthesis-agent.ts` re-exports patchfile agent 1/2 only.
708+
**Stores (after measurements):**
709+
`implementation:options` / `assetPacks` (measured), `implementation:patchedPlans`,
710+
`implementation:patchArtifacts`, `implementation:patchfileWritten`,
711+
`implementation:measured`, `implementation:presentable`, salvage flags, measurementReports.
714712

715713
#### Validation (single agent — validate only)
716714

.specifications/BITCODE_SPEC_V48_PARITY_MATRIX.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,7 @@ AssetPack = **patch + measurements + metadata**.
189189
| preprocess | deposit-only | Coords + steering; catalog may be empty until Setup clone |
190190
| Setup | (1) clone alone → (2) **parallel** {initialize-lsp, initialize-mcps-tools, comprehend-obfuscations} → (3) danger-wall alone | Clone first; danger wall last admits obfuscations |
191191
| Discovery | **parallel** {comprehend-codebase, search-depository, inherent-regurgitation} | Measure is **inside** comprehend-codebase (tools/objectives), not a separate agent |
192-
| Implementation | sequential `…-patchfile-synthesis` then `…-measurements-synthesis` | Patchfile (6 fields) then measure into `measurements.absolutes` only; kinds: capability-slice \| implementation-pattern \| proof-operations-slice |
192+
| Implementation | sequential `…-patch-plan` `…-patchfile``…-measurements` | Plan (6 fields) → write one path-op-json AssetPackPatchArtifact per pack → measure absolutes; kinds: capability-slice \| implementation-pattern \| proof-operations-slice |
193193
| Validation | **one** agent: ready-to-finish-asset-packs-synthesis-deposit-pipeline | A prior phases/tools · B pack quality · C obfuscations vs patch |
194194
| Finish | (1) store-artifacts → (2) ledgerize → (3) finish-synthesize-asset-packs-for-deposit-run | Store (Supabase + patch artifacts) · on-chain ledger · envelope/cleanup last |
195195
| postprocess | normalize | Presentation-safe result |
Lines changed: 54 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,14 @@
11
// @ts-nocheck
2-
// Deposit Implementation agents 1/2 + 2/2 — boundary-mocked PTRR for patchfile;
3-
// host measure path for absolutes.
4-
//
5-
// Product law:
6-
// deposit AP = patchfile + absolutes + metadata
7-
// neediness is Read-only
8-
// salvage is never presentable
2+
// Deposit Implementation: patch-plan → patchfile write → measurements.
93
jest.mock('@bitcode/generic-llms', () => require('./support/generic-llms-mock').makeGenericLLMsMock());
104

115
import { Execution } from '@bitcode/execution-generics';
12-
import { AgentExecution } from '@bitcode/agent-generics';
13-
import runDepositImplementationAgentAssetPacksPatchfileSynthesis from '../agents/implementation/deposit-implementation-agent-asset-packs-patchfile-synthesis';
14-
import runDepositImplementationAgentAssetPacksMeasurementsSynthesis from '../agents/implementation/deposit-implementation-agent-asset-packs-measurements-synthesis';
15-
import { isDepositPresentablePack } from '../agents/implementation/deposit-implementation-pack-types';
6+
import runPatchPlan from '../agents/implementation/deposit-implementation-agent-asset-packs-patch-plan';
7+
import runPatchfile from '../agents/implementation/deposit-implementation-agent-asset-packs-patchfile';
8+
import runMeasurements from '../agents/implementation/deposit-implementation-agent-asset-packs-measurements-synthesis';
9+
import { isDepositPresentablePack, hasPatchArtifact } from '../agents/implementation/deposit-implementation-pack-types';
1610
import { setBoundaryLLMOutput, resetBoundaryLLMOutput } from './support/generic-llms-mock';
1711

18-
const VALID_OPS = new Set(['create', 'modify', 'delete']);
19-
2012
const MOCK_OPTIONS = [
2113
{
2214
kind: 'capability-slice',
@@ -28,9 +20,9 @@ const MOCK_OPTIONS = [
2820
patch: {
2921
fileChanges: [
3022
{ path: 'src/auth/session.ts', op: 'modify' },
31-
{ path: 'src/auth/refresh.ts', op: 'create' },
23+
{ path: 'src/auth/token.ts', op: 'modify' },
3224
],
33-
patchSummary: 'Encodes the session lifecycle knowledge and its refresh entry points.',
25+
patchSummary: 'Encodes the session lifecycle knowledge.',
3426
},
3527
},
3628
{
@@ -47,107 +39,86 @@ const MOCK_OPTIONS = [
4739
},
4840
];
4941

42+
const PATHS = ['src/auth/session.ts', 'src/auth/token.ts', 'src/net/retry.ts'];
5043
const INPUT = {
51-
inventory: {
52-
paths: ['src/auth/session.ts', 'src/auth/token.ts', 'src/auth/refresh.ts', 'src/net/retry.ts'],
53-
samples: [],
54-
},
44+
inventory: { paths: PATHS, samples: [] },
5545
impermissibleSources: ['src/protected'],
5646
};
5747

5848
function seedCatalog(exec) {
5949
exec.store('deposit', 'sourceCheckoutCatalog', {
60-
paths: INPUT.inventory.paths,
50+
paths: PATHS,
6151
samples: [],
62-
sources: INPUT.inventory.paths.map((path) => ({
63-
path,
64-
content: `// ${path}\nexport function f() {}\n`,
65-
})),
52+
sources: PATHS.map((path) => ({ path, content: `// ${path}\nexport function f() {}\n` })),
6653
});
6754
}
6855

69-
async function runFullImplementation(input, exec) {
56+
async function runFull(input, exec) {
7057
seedCatalog(exec);
71-
const patched = await runDepositImplementationAgentAssetPacksPatchfileSynthesis(input, exec);
72-
return runDepositImplementationAgentAssetPacksMeasurementsSynthesis(patched, exec);
58+
const planned = await runPatchPlan(input, exec);
59+
const written = await runPatchfile(planned, exec);
60+
return runMeasurements(written, exec);
7361
}
7462

75-
describe('deposit-implementation-agent-asset-packs-patchfile-synthesis', () => {
63+
describe('patch-plan agent', () => {
7664
beforeEach(() => setBoundaryLLMOutput({ options: MOCK_OPTIONS }));
7765
afterEach(() => resetBoundaryLLMOutput());
7866

79-
it('synthesizes patchfile+metadata only (no measurements) for each AssetPack', async () => {
67+
it('emits six-field descriptors without patchArtifact', async () => {
8068
const exec = new Execution('implementation-node');
8169
seedCatalog(exec);
82-
const out = await runDepositImplementationAgentAssetPacksPatchfileSynthesis(INPUT, exec);
83-
70+
const out = await runPatchPlan(INPUT, exec);
8471
expect(out.success).toBe(true);
85-
expect(out.semanticKind).toBe('asset-pack-patchfile-synthesized');
86-
expect(out.measured).toBe(false);
87-
expect(out.salvaged).toBe(false);
88-
expect(out.presentable).toBeUndefined();
89-
expect(Array.isArray(out.options)).toBe(true);
90-
expect(out.options.length).toBe(2);
91-
92-
for (const option of out.options) {
93-
expect(option.measurements).toBeUndefined();
94-
expect(option.absolutes).toBeUndefined();
95-
expect(option.salvaged).toBeUndefined();
96-
expect(Array.isArray(option.patch.fileChanges)).toBe(true);
97-
for (const change of option.patch.fileChanges) {
98-
expect(VALID_OPS.has(change.op) || typeof change.op === 'string').toBe(true);
99-
}
72+
expect(out.semanticKind).toBe('asset-pack-patch-plan');
73+
expect(out.patchfileWritten).toBe(false);
74+
for (const o of out.options) {
75+
expect(o.patchArtifact).toBeUndefined();
76+
expect(o.measurements).toBeUndefined();
77+
expect(o.patch.fileChanges.length).toBeGreaterThan(0);
10078
}
101-
expect(exec.get('implementation', 'measured')).toBe(false);
102-
expect(exec.get('implementation', 'presentable')).toBe(false);
10379
}, 120000);
80+
});
81+
82+
describe('patchfile write agent', () => {
83+
beforeEach(() => setBoundaryLLMOutput({ options: MOCK_OPTIONS }));
84+
afterEach(() => resetBoundaryLLMOutput());
10485

105-
it('records each patchfile through AssetPackPatchWriteTool', async () => {
106-
const exec = new AgentExecution('implementation-node');
86+
it('writes one AssetPackPatchArtifact per planned pack (7th field)', async () => {
87+
const exec = new Execution('implementation-node');
10788
seedCatalog(exec);
108-
await runDepositImplementationAgentAssetPacksPatchfileSynthesis(INPUT, exec);
109-
expect(exec.tools.getTool('asset-pack-patch-write')).toBeDefined();
89+
const planned = await runPatchPlan(INPUT, exec);
90+
const written = await runPatchfile(planned, exec);
91+
expect(written.success).toBe(true);
92+
expect(written.patchfileWritten).toBe(true);
93+
expect(written.patchArtifacts).toHaveLength(2);
94+
const ids = new Set();
95+
for (const o of written.options) {
96+
expect(hasPatchArtifact(o)).toBe(true);
97+
expect(o.patchArtifact.format).toMatch(/path-op-json|json/i);
98+
expect(o.patchArtifact.files.length).toBe(o.patch.fileChanges.length);
99+
expect(o.patchArtifact.envelopeJson).toContain(o.patchArtifact.artifactId);
100+
ids.add(o.patchArtifact.artifactId);
101+
}
102+
expect(ids.size).toBe(2);
103+
expect(exec.get('implementation', 'patchfileWritten')).toBe(true);
110104
}, 120000);
111105
});
112106

113-
describe('deposit-implementation-agent-asset-packs-measurements-synthesis', () => {
107+
describe('full Implementation: plan → write → measure', () => {
114108
beforeEach(() => setBoundaryLLMOutput({ options: MOCK_OPTIONS }));
115109
afterEach(() => resetBoundaryLLMOutput());
116110

117-
it('measures each patchfile and attaches measurements.absolutes only', async () => {
111+
it('yields presentable packs with artifact + absolutes only', async () => {
118112
const exec = new Execution('implementation-node');
119-
const out = await runFullImplementation(INPUT, exec);
120-
113+
const out = await runFull(INPUT, exec);
121114
expect(out.success).toBe(true);
122115
expect(out.measured).toBe(true);
123116
expect(out.presentable).toBe(true);
124-
expect(out.salvaged).toBe(false);
125-
expect(out.summary).toMatch(/presentable deposit AssetPack/);
126-
127-
for (const option of out.options) {
128-
expect(Array.isArray(option.measurements?.absolutes)).toBe(true);
129-
expect(option.measurements.absolutes.length).toBeGreaterThan(0);
130-
expect(option.measurements).not.toHaveProperty('needinesses');
131-
expect(option.needinessSignal).toBeUndefined();
132-
expect(isDepositPresentablePack(option)).toBe(true);
133-
for (const row of option.measurements.absolutes) {
134-
expect(row.volume).toBeGreaterThanOrEqual(0);
135-
expect(row.volume).toBeLessThanOrEqual(1);
136-
expect(typeof row.magnitude).toBe('number');
137-
}
117+
for (const o of out.options) {
118+
expect(hasPatchArtifact(o)).toBe(true);
119+
expect(Object.keys(o.measurements)).toEqual(['absolutes']);
120+
expect(isDepositPresentablePack(o)).toBe(true);
138121
}
139-
140-
expect(exec.get('implementation', 'measured')).toBe(true);
141-
expect(exec.get('implementation', 'presentable')).toBe(true);
142-
const reports = exec.get('implementation', 'measurementReports');
143-
expect(reports).toHaveLength(2);
144-
expect(reports.every((r) => r.ok && r.depositShapeOk)).toBe(true);
145-
}, 120000);
146-
147-
it('returns success on plain Execution without tool registry', async () => {
148-
const exec = new Execution('implementation-node');
149-
const out = await runFullImplementation(INPUT, exec);
150-
expect(out.success).toBe(true);
151-
expect(out.options.length).toBe(2);
122+
expect(out.measurementReports.every((r) => r.hasPatchArtifact && r.ok)).toBe(true);
152123
}, 120000);
153124
});

0 commit comments

Comments
 (0)