Skip to content

Commit 0470dd6

Browse files
V48: Separate synthesis completion from settleDelivery
Synthesis deposit/read postprocess no longer authors settleDelivery or prefers settle-shaped summaries. kind is deposit_options / read_options / asset_pack_synthesis; settle_delivery only when settle Simple shippable exists. Finish completion stores synthesis summary/artifacts; optional settlePassThrough only after settle. API/host aligned. Docs: clarify useTools law — Plan/Refine and PCC SO never useTools; Try/Retry task SO must allow useTools.
1 parent 7c07e2f commit 0470dd6

12 files changed

Lines changed: 324 additions & 96 deletions

File tree

.docs/PROMPTING.md

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,21 @@ StructuredOutput) use:
155155

156156
After SO: host **read-in** of values for selected keys → ChunkThenSum / Stitch / task Try.
157157

158+
### Tools / `useTools` law (PTRR steps + PCC)
159+
160+
Three different layers — do not conflate them:
161+
162+
| Layer | Tools surface | Task SO `useTools` | Why |
163+
| --- | --- | --- | --- |
164+
| **PCC selection SO** (any step) | N/A (not the task) | **Never** — schema is only `{ selectedKeys }` | Key filter, not agent work |
165+
| **Plan** task Thinkings/SO | Default **empty** usable tools | **Never**`PlanStepOutputSchema` has no `useTools`; no tools postprocess | Strategy only |
166+
| **Refine** task Thinkings/SO | Default **empty** usable tools | **Never** — no tools postprocess | Final return, not execution |
167+
| **Try** task Thinkings/SO | Agent catalog (usable tools) | **Required capability** — step schema may include `useTools`; tools postprocess runs when selected | Execute the plan |
168+
| **Retry** task Thinkings/SO | Same as Try (+ prior usedTools results) | **Required capability** — same as Try | Re-attempt with tools |
169+
170+
**Correct slogan:** tools / `useTools` are disallowed on **Plan** and **Refine** only.
171+
**Incorrect slogan:** “SO never useTools” (that applies only to **PCC SO** and to **Plan/Refine task SO**, not Try/Retry).
172+
158173
### ChunkThenSum (CS) task Thinkings
159174

160175
After PCC value read-in, task Thinkings (Reason → Judge → StructuredOutput against the
@@ -173,6 +188,9 @@ without priors are non-canonical.)
173188
Empty `selectedContext` stays prepared-only (lean empty bag) — do not re-dump the envelope
174189
as fail-soft.
175190

191+
CS Reason/SO for **Try/Retry** may include `useTools` when the step schema allows it; for
192+
**Plan/Refine** omit `useTools` entirely.
193+
176194
---
177195

178196
## Naming (types)
@@ -235,4 +253,5 @@ Expect on **system**: Execution **once** + Pipeline + SDIVF + product + Phase +
235253
**Plan** + PCC + active Thinking (Reason | Judge | SO).
236254

237255
Expect on **user** (PCC selection): lean task + keys-only tree; **no** full hierarchy re-paste;
238-
SO = `{ selectedKeys }` only (no useTools).
256+
PCC SO = `{ selectedKeys }` only (no useTools). Plan/Refine task SO also omit useTools;
257+
Try/Retry task SO may include useTools.

.qa/BITCODE_V48_CANONICAL_PROMOTION_ACCEPTANCE.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -706,7 +706,7 @@ on VCS agent promptparts; if too heavy, thin **authoring**, not drop Agent from
706706
| Removed | Brittle keyword `trimHeavySystemProse`; temporary skip of Agent/Step nodes |
707707

708708
**PCC-specific adjustments (slight, not hierarchy amputation):** keys-only tree (no values);
709-
generation schemas (Reasoning / Judgment / selectedKeys); SO never useTools under PCC.
709+
generation schemas (Reasoning / Judgment / selectedKeys); **PCC SO** never useTools (not Plan/Try task SO — Try/Retry task SO may include useTools).
710710

711711
#### re-validation (2026-07-16, post hierarchy-walk restore)
712712

@@ -1243,7 +1243,7 @@ Nested bulk under a **selected** key (e.g. `#pipeline:input` → depositoryAsset
12431243

12441244
1. **Hierarchy law restored** — full walk Execution→…→Failsafe→Thinking (never amputate Agent/Step).
12451245
2. **Dual system/user law** — system = ancestry; user = generation payload only.
1246-
3. **PCC lean user** — keys-only tree; lean task; SO never useTools.
1246+
3. **PCC lean user** — keys-only tree; lean task; **PCC SO** never useTools (`selectedKeys` only). Plan/Refine task SO also omit useTools; **Try/Retry task SO must allow useTools**.
12471247
4. **CS failsafe law attach** + **forPreparation PCC-only** (budget measure correct).
12481248
5. **CS prepared-only user**`selectedKeys`+`selectedContext` (+ prior Thinkings); no envelope dual-dump.
12491249
6. **CS sequential chunk loop** — slice + `priorChunkCompletions` → sum (parallel opt-in).

packages/agent-generics/TOOLS-IN-PTRR.md

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,9 +48,21 @@ Store tools.use / tools.used; publish agent-step work update
4848
Next PTRR step sees usedTools via results interpolation (not Plan's useTools)
4949
```
5050

51-
**Plan** = strategy only (empty tool surface by default; no tools postprocess).
52-
**Try/Retry** each select their own `useTools` and postprocess.
53-
**Refine** = final agent return (empty tool surface; no postprocess).
51+
**Plan** = strategy only (empty tool surface by default; `PlanStepOutputSchema` has
52+
**no** `useTools`; no tools postprocess).
53+
**Try/Retry** each select their own `useTools` on **task** StructuredOutput and
54+
postprocess — **fundamental** to those steps (not optional philosophy).
55+
**Refine** = final agent return (empty tool surface; no `useTools` postprocess).
56+
57+
**PCC StructuredOutput** (first failsafe on every step) is unrelated: it emits only
58+
`{ selectedKeys }` and **never** `useTools`, even under Try/Retry. Task SO after PCC
59+
read-in is where Try/Retry `useTools` appears.
60+
61+
| | Plan | Try | Retry | Refine | PCC SO (any step) |
62+
| --- | --- | --- | --- | --- | --- |
63+
| Usable tools | `[]` | agent catalog | agent catalog | `[]` | n/a |
64+
| Task SO may include `useTools` | **no** | **yes** | **yes** | **no** | n/a (`selectedKeys` only) |
65+
| Tools postprocess | no | yes if selected | yes if selected | no | no |
5466

5567
---
5668

packages/agent-generics/src/steps/step-schemas.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,20 @@
77
* is prompted to produce:
88
*
99
* - Plan → the canonical plan shape below (the execution strategy the
10-
* PLAN objective asks for), NOT the agent's output. Forcing the
11-
* agent schema onto Plan made every run's plan step fail
12-
* validation and burn stitch repairs before Try even started.
13-
* - Try → the agent's output schema (the main generation attempt).
10+
* PLAN objective asks for), NOT the agent's output. No `useTools`
11+
* field; no tools postprocess. Forcing the agent schema onto Plan
12+
* made every run's plan step fail validation and burn stitch repairs
13+
* before Try even started.
14+
* - Try → the agent's output schema (the main generation attempt). May
15+
* include `useTools`; tools postprocess runs when selected.
1416
* - Retry → the agent's output schema (re-attempt Try using prior errors /
1517
* usedTools; tools postprocess when selected).
1618
* - Refine → the agent's output schema (LAST step — final agent return;
17-
* same type as the agent; no tools postprocess).
19+
* same type as the agent; no tools postprocess / no useTools
20+
* execution).
21+
*
22+
* PCC selection SO (first failsafe) is never the step schema: always
23+
* `{ selectedKeys }` only — never useTools — on every PTRR step.
1824
*
1925
* Runtime order: Plan → Try → Retry → Refine.
2026
* `factoryPTRRAgent` resolves these defaults; each step
@@ -26,10 +32,12 @@ import { z } from 'zod';
2632
// Kept deliberately small and universally satisfiable across every PTRR
2733
// agent (comprehension, search, synthesis, measure, validation …); large
2834
// schemas inflate the structured-output hint and invite truncation.
35+
/** Plan task SO only — no useTools (tools are Try/Retry). */
2936
export const PlanStepOutputSchema = z.object({
3037
approach: z.string(),
3138
steps: z.array(z.string()),
3239
considerations: z.array(z.string()).optional()
40+
// intentionally no useTools
3341
}).describe('{ "approach": string, "steps": string[], "considerations"?: string[] }');
3442

3543
export type PlanStepOutput = z.infer<typeof PlanStepOutputSchema>;

packages/api/src/routes/asset-pack-pipeline.ts

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,17 +1041,30 @@ export const POST = traceRoute('/executions', async (request: NextRequest) => {
10411041
(execution as any).get?.('implementation', 'assetPackSynthesisArtifacts') ||
10421042
writtenAssets ||
10431043
undefined;
1044-
// Buyer-repo PR surface for completion: finish settleDelivery, else
1045-
// settle Simple shippable artifact, else deliveryMechanism projection.
1046-
// Pre-production: no shippables completion alias.
1047-
const settleDelivery =
1048-
(execution as any).get?.('finish/asset_pack_completion', 'settleDelivery') ||
1044+
// Buyer-repo PR: settle Simple shippable only (or settlePassThrough
1045+
// after settle on same EE). Synthesis Finish must not invent settleDelivery.
1046+
const settleShippable =
10491047
(execution as any).get?.('settle-asset-pack-pipeline', 'shippable') ||
1050-
(execution as any).get?.('finish/asset_pack_completion', 'deliveryMechanism') ||
10511048
undefined;
1049+
const settlePassThrough =
1050+
(execution as any).get?.('finish/asset_pack_completion', 'settlePassThrough') ||
1051+
undefined;
1052+
const settleDelivery =
1053+
settleShippable?.prUrl
1054+
? {
1055+
pullRequest: {
1056+
url: settleShippable.prUrl,
1057+
title: settleShippable.optionTitle || undefined,
1058+
},
1059+
summary:
1060+
(execution as any).get?.('finish/asset_pack_completion', 'summary') ||
1061+
undefined,
1062+
}
1063+
: settlePassThrough?.pullRequest?.url
1064+
? settlePassThrough
1065+
: undefined;
10521066
const deliveryMechanism =
10531067
(execution as any).get?.('finish/asset_pack_completion', 'deliveryMechanism') ||
1054-
settleDelivery ||
10551068
undefined;
10561069
const read =
10571070
(execution as any).get?.('finish/asset_pack_completion', 'read') ||
@@ -1107,9 +1120,8 @@ export const POST = traceRoute('/executions', async (request: NextRequest) => {
11071120
if (!assetPackCompletion.summary && assetPackCompletion.deliveryMechanism?.summary) {
11081121
assetPackCompletion.summary = assetPackCompletion.deliveryMechanism.summary;
11091122
}
1110-
if (!assetPackCompletion.summary && assetPackCompletion.settleDelivery?.summary) {
1111-
assetPackCompletion.summary = assetPackCompletion.settleDelivery.summary;
1112-
}
1123+
// Do not prefer settleDelivery.summary for synthesis completion —
1124+
// settle is a separate pipeline; summary lives on finish/summary + artifacts.
11131125
try {
11141126
const supa = getAdminSupabase();
11151127
const { data: tokenRows, error: tokenErr } = await (supa as any)

packages/asset-packs-pipelines/domain/src/__tests__/finish-completion.test.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
/**
33
* Finish AssetPack completion evidence (product SDIVF Finish phase).
44
* Buyer-repo PR URL is only present when settle Simple already stored a
5-
* shippable on the shared execution — Finish itself does not open PRs.
5+
* shippable on the shared execution — Finish itself does not open PRs and
6+
* does not author settleDelivery (settlement-exclusive surface).
67
*/
78
import { Execution } from '@bitcode/execution-generics';
89
import AssetPackCompletionAgent from '../agents/finish/asset-pack-completion-agent';
910

1011
describe('finish AssetPack completion evidence', () => {
11-
it('builds repository snapshot without inventing a Finish PR on settleDelivery', async () => {
12+
it('builds repository snapshot without inventing settleDelivery or a Finish PR', async () => {
1213
const exec = new Execution('pipeline:asset-pack');
1314
exec.store('pipeline', 'expressedRead', 'Read the deposited source and prepare Fit options.');
1415
exec.store('pipeline', 'writtenAssetType', 'read-satisfaction-asset-pack');
@@ -31,14 +32,17 @@ describe('finish AssetPack completion evidence', () => {
3132
branch: 'main',
3233
commit: '272b5b1586b28363b57676603a1990bb10df319c',
3334
});
34-
expect(result.settleDelivery?.pullRequest).toBeNull();
35+
expect(result.settlePassThrough).toBeUndefined();
36+
expect((result as any).settleDelivery).toBeUndefined();
37+
expect(result.summary).toContain('octocat/Spoon-Knife');
3538
expect(result.deliveryMechanism?.readiness).toMatchObject({
3639
status: 'pending-user-review',
3740
});
3841
expect(result.deliveryMechanism?.summary).toContain('octocat/Spoon-Knife');
42+
expect(result.assetPackSynthesisArtifacts?.summary).toContain('octocat/Spoon-Knife');
3943
});
4044

41-
it('passes through settle shippable PR on settleDelivery when settle already ran', async () => {
45+
it('passes through settle shippable PR only as settlePassThrough when settle already ran', async () => {
4246
const exec = new Execution('pipeline:asset-pack');
4347
exec.store('pipeline', 'expressedRead', 'Need: type-safe plain object check');
4448
exec.store('harness', 'sourceRevision', {
@@ -52,8 +56,9 @@ describe('finish AssetPack completion evidence', () => {
5256
});
5357

5458
const result = await AssetPackCompletionAgent({}, exec);
55-
expect(result.settleDelivery?.pullRequest).toMatchObject({
59+
expect(result.settlePassThrough?.pullRequest).toMatchObject({
5660
url: 'https://github.com/octocat/Spoon-Knife/pull/123',
5761
});
62+
expect((result as any).settleDelivery).toBeUndefined();
5863
});
5964
});

packages/asset-packs-pipelines/domain/src/__tests__/postprocess.test.ts

Lines changed: 81 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ describe('normalizeAssetPackOutput', () => {
7676
} as any);
7777

7878
expect(result.semanticKind).toBe('asset-pack-written-asset');
79-
expect(result.kind).toBe('shippable');
79+
// Pure synthesis: not settle_delivery (settle-pipeline exclusive).
80+
expect(result.kind).toBe('asset_pack_synthesis');
81+
expect(result.settleDelivery).toBeUndefined();
8082
expect(result.read).toBe('Read a review-ready written asset');
8183
expect(result.writtenAssetType).toBe('read-satisfaction-asset-pack');
8284
expect(result.deliveryMechanismTemplate).toBe('pull-request');
@@ -92,6 +94,55 @@ describe('normalizeAssetPackOutput', () => {
9294
});
9395
});
9496

97+
it('uses deposit_options kind when productPipeline is deposit synthesis', () => {
98+
const exec = new Execution('pipeline:synthesize_deposit_asset_packs');
99+
exec.store('execution', 'id', 'exec-deposit');
100+
exec.store('pipeline', 'productPipeline', 'synthesize-deposits-asset-packs-pipeline');
101+
exec.store('finish', 'selectionEnvelope', {
102+
schema: 'bitcode.deposit.synthesize-asset-packs.selection-envelope',
103+
options: [{ title: 'opt-a' }],
104+
});
105+
exec.store('implementation', 'assetPackSynthesisArtifacts', {
106+
summary: 'Deposit options ready for selection.',
107+
});
108+
109+
const result = buildAssetPackPostprocessedResult(exec, {
110+
success: true,
111+
summary: '',
112+
options: [{ title: 'opt-a' }],
113+
selectionEnvelope: {
114+
schema: 'bitcode.deposit.synthesize-asset-packs.selection-envelope',
115+
options: [{ title: 'opt-a' }],
116+
},
117+
} as any);
118+
119+
expect(result.kind).toBe('deposit_options');
120+
expect(result.settleDelivery).toBeUndefined();
121+
expect(result.selectionEnvelope?.options).toHaveLength(1);
122+
expect(result.summary).toBe('Deposit options ready for selection.');
123+
});
124+
125+
it('never prefers finish settleDelivery summary for synthesis (settle-exclusive surface)', () => {
126+
const exec = new Execution('pipeline:asset-pack');
127+
exec.store('implementation', 'assetPackSynthesisArtifacts', {
128+
summary: 'Authoritative synthesis summary.',
129+
});
130+
// Misnamed residual store must not win summary authority.
131+
exec.store('finish/asset_pack_completion', 'settleDelivery', {
132+
summary: 'Wrong settle-shaped summary from synthesis Finish.',
133+
pullRequest: null,
134+
});
135+
136+
const result = buildAssetPackPostprocessedResult(exec, {
137+
success: true,
138+
summary: '',
139+
} as any);
140+
141+
expect(result.summary).toBe('Authoritative synthesis summary.');
142+
expect(result.kind).not.toBe('settle_delivery');
143+
expect(result.settleDelivery).toBeUndefined();
144+
});
145+
95146
it('preserves implementation artifacts when postprocess runs from a sibling execution node', () => {
96147
const root = new Execution('pipeline:asset-pack');
97148
const implementation = root.child('phase:implementation');
@@ -118,32 +169,49 @@ describe('normalizeAssetPackOutput', () => {
118169
expect(result.assetPackSynthesisArtifacts?.proofEvidence).toEqual(['sibling-implementation-read']);
119170
});
120171

121-
it('uses pull-request delivery mechanisms as canonical shippable evidence for the written asset', () => {
172+
it('surfaces settleDelivery only when settle Simple shippable exists on the EE', () => {
122173
const exec = new Execution('pipeline:asset-pack');
123174
exec.store('execution', 'id', 'exec-2');
175+
exec.store('settle-asset-pack-pipeline', 'shippable', {
176+
prUrl: 'https://github.com/acme/repo/pull/26',
177+
optionTitle: 'AssetPack PR',
178+
});
124179

125180
const result = buildAssetPackPostprocessedResult(exec, {
126181
success: true,
127-
summary: 'Written asset delivered through PR.',
182+
summary: 'Settled delivery complete.',
128183
writtenAsset: {
129184
title: 'Read satisfaction summary',
130185
},
186+
semanticKind: 'asset-pack-written-asset',
187+
} as any);
188+
189+
expect(result.title).toBe('Read satisfaction summary');
190+
expect(result.kind).toBe('settle_delivery');
191+
expect(result.settleDelivery?.pullRequest).toMatchObject({
192+
url: 'https://github.com/acme/repo/pull/26',
193+
});
194+
});
195+
196+
it('does not invent settleDelivery from synthesis deliveryMechanism alone', () => {
197+
const exec = new Execution('pipeline:asset-pack');
198+
exec.store('execution', 'id', 'exec-2b');
199+
200+
const result = buildAssetPackPostprocessedResult(exec, {
201+
success: true,
202+
summary: 'Synthesis only — no settle.',
203+
writtenAsset: { title: 'Option set' },
131204
deliveryMechanism: {
132-
title: 'AssetPack PR',
205+
title: 'Not a settle PR',
133206
prUrl: 'https://github.com/acme/repo/pull/26',
134207
},
135208
semanticKind: 'asset-pack-written-asset',
136209
} as any);
137210

138-
expect(result.title).toBe('Read satisfaction summary');
139-
expect(result.deliveryMechanism).toEqual({
140-
title: 'AssetPack PR',
141-
prUrl: 'https://github.com/acme/repo/pull/26',
142-
});
143-
expect(result.shippable).toEqual({
144-
title: 'AssetPack PR',
145-
prUrl: 'https://github.com/acme/repo/pull/26',
146-
});
211+
expect(result.kind).toBe('asset_pack_synthesis');
212+
expect(result.settleDelivery).toBeUndefined();
213+
// deliveryMechanism may still carry readiness-shaped data from the input
214+
expect(result.deliveryMechanism?.prUrl).toBe('https://github.com/acme/repo/pull/26');
147215
});
148216

149217
it('derives and stores source-safe preview evidence from an accepted Need and Finding Fits result', () => {

0 commit comments

Comments
 (0)