Skip to content

Commit 7890344

Browse files
V48: Never emit settleDelivery from synthesis
Asset-pack synthesis postprocess/Finish never surface settle_delivery, settleDelivery, settlePassThrough, or settle shippable PR — even if settle keys exist on the EE. Settlement remains settle-asset-pack-pipeline exclusive.
1 parent 0470dd6 commit 7890344

8 files changed

Lines changed: 63 additions & 159 deletions

File tree

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

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1041,31 +1041,12 @@ export const POST = traceRoute('/executions', async (request: NextRequest) => {
10411041
(execution as any).get?.('implementation', 'assetPackSynthesisArtifacts') ||
10421042
writtenAssets ||
10431043
undefined;
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 =
1047-
(execution as any).get?.('settle-asset-pack-pipeline', 'shippable') ||
1048-
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;
1044+
// Synthesis completion path: never project settleDelivery / settle PR.
1045+
// Buyer-repo settle surfaces come only from settle-asset-pack-pipeline runs.
10661046
const deliveryMechanism =
10671047
(execution as any).get?.('finish/asset_pack_completion', 'deliveryMechanism') ||
10681048
undefined;
1049+
const settleDelivery = undefined;
10691050
const read =
10701051
(execution as any).get?.('finish/asset_pack_completion', 'read') ||
10711052
(execution as any).get?.('pipeline', 'expressedRead') ||

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

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
// @ts-nocheck
22
/**
33
* Finish AssetPack completion evidence (product SDIVF Finish phase).
4-
* 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 and
6-
* does not author settleDelivery (settlement-exclusive surface).
4+
* Synthesis Finish never opens PRs and never surfaces settleDelivery /
5+
* settlePassThrough — even if settle keys exist on a shared EE.
76
*/
87
import { Execution } from '@bitcode/execution-generics';
98
import AssetPackCompletionAgent from '../agents/finish/asset-pack-completion-agent';
@@ -32,8 +31,9 @@ describe('finish AssetPack completion evidence', () => {
3231
branch: 'main',
3332
commit: '272b5b1586b28363b57676603a1990bb10df319c',
3433
});
35-
expect(result.settlePassThrough).toBeUndefined();
34+
expect((result as any).settlePassThrough).toBeUndefined();
3635
expect((result as any).settleDelivery).toBeUndefined();
36+
expect(result.deliveryMechanism?.pullRequest).toBeNull();
3737
expect(result.summary).toContain('octocat/Spoon-Knife');
3838
expect(result.deliveryMechanism?.readiness).toMatchObject({
3939
status: 'pending-user-review',
@@ -42,7 +42,7 @@ describe('finish AssetPack completion evidence', () => {
4242
expect(result.assetPackSynthesisArtifacts?.summary).toContain('octocat/Spoon-Knife');
4343
});
4444

45-
it('passes through settle shippable PR only as settlePassThrough when settle already ran', async () => {
45+
it('ignores settle shippable on the EE — synthesis never emits settle surfaces', async () => {
4646
const exec = new Execution('pipeline:asset-pack');
4747
exec.store('pipeline', 'expressedRead', 'Need: type-safe plain object check');
4848
exec.store('harness', 'sourceRevision', {
@@ -56,9 +56,8 @@ describe('finish AssetPack completion evidence', () => {
5656
});
5757

5858
const result = await AssetPackCompletionAgent({}, exec);
59-
expect(result.settlePassThrough?.pullRequest).toMatchObject({
60-
url: 'https://github.com/octocat/Spoon-Knife/pull/123',
61-
});
59+
expect((result as any).settlePassThrough).toBeUndefined();
6260
expect((result as any).settleDelivery).toBeUndefined();
61+
expect(result.deliveryMechanism?.pullRequest).toBeNull();
6362
});
6463
});

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

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,13 @@ describe('normalizeAssetPackOutput', () => {
4242
expect(typeof normalized.summary).toBe('string');
4343
expect(normalized.summary.length).toBeGreaterThan(0);
4444

45+
// Settle shippable on EE must not project into synthesis normalize.
4546
exec.store('settle-asset-pack-pipeline', 'shippable', {
4647
prUrl: 'https://github.com/acme/repo/pull/123',
4748
});
48-
const withSettle = normalizeAssetPackOutput(output, exec);
49-
expect(withSettle.shippable.prUrl).toContain('/pull/123');
49+
const withSettleKeysPresent = normalizeAssetPackOutput(output, exec);
50+
expect(withSettleKeysPresent.shippable?.prUrl).toBeUndefined();
51+
expect(withSettleKeysPresent.deliveryMechanism?.prUrl).toBeUndefined();
5052
});
5153

5254
it('builds asset-pack semantic mirrors into the postprocessed result', () => {
@@ -169,7 +171,7 @@ describe('normalizeAssetPackOutput', () => {
169171
expect(result.assetPackSynthesisArtifacts?.proofEvidence).toEqual(['sibling-implementation-read']);
170172
});
171173

172-
it('surfaces settleDelivery only when settle Simple shippable exists on the EE', () => {
174+
it('never emits settle_delivery / settleDelivery even when settle shippable exists on EE', () => {
173175
const exec = new Execution('pipeline:asset-pack');
174176
exec.store('execution', 'id', 'exec-2');
175177
exec.store('settle-asset-pack-pipeline', 'shippable', {
@@ -179,21 +181,21 @@ describe('normalizeAssetPackOutput', () => {
179181

180182
const result = buildAssetPackPostprocessedResult(exec, {
181183
success: true,
182-
summary: 'Settled delivery complete.',
184+
summary: 'Synthesis complete.',
183185
writtenAsset: {
184186
title: 'Read satisfaction summary',
185187
},
186188
semanticKind: 'asset-pack-written-asset',
187189
} as any);
188190

189191
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-
});
192+
expect(result.kind).toBe('asset_pack_synthesis');
193+
expect(result.kind).not.toBe('settle_delivery' as any);
194+
expect(result.settleDelivery).toBeUndefined();
195+
expect(result.shippable).toBeUndefined();
194196
});
195197

196-
it('does not invent settleDelivery from synthesis deliveryMechanism alone', () => {
198+
it('strips PR fields from deliveryMechanism on synthesis postprocess', () => {
197199
const exec = new Execution('pipeline:asset-pack');
198200
exec.store('execution', 'id', 'exec-2b');
199201

@@ -210,8 +212,8 @@ describe('normalizeAssetPackOutput', () => {
210212

211213
expect(result.kind).toBe('asset_pack_synthesis');
212214
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');
215+
expect(result.deliveryMechanism?.prUrl).toBeUndefined();
216+
expect((result.deliveryMechanism as any)?.pullRequest).toBeUndefined();
215217
});
216218

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

packages/asset-packs-pipelines/domain/src/agents/finish/asset-pack-completion-agent.ts

Lines changed: 7 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -52,30 +52,16 @@ const DeliveryMechanismSchema = z.object({
5252
.optional(),
5353
});
5454

55-
/**
56-
* Settle pass-through only — present when settle Simple already stored a
57-
* shippable on this EE. Synthesis Finish must not author this as a fake PR bag.
58-
*/
59-
const SettlePassThroughSchema = z.object({
60-
pullRequest: ShippableSchema.nullable().optional(),
61-
fileChanges: FileChangesSchema.nullable().optional(),
62-
summary: z.string().nullable().optional(),
63-
});
64-
6555
export const AssetPackCompletionOutputSchema = z.object({
6656
/**
6757
* Synthesis completion summary (markdown). Primary Finish evidence for SDIVF.
68-
* Not settleDelivery — settlement is settle-asset-pack-pipeline exclusive.
58+
* Settlement (settleDelivery / buyer PR) is exclusive to settle-asset-pack-pipeline
59+
* and is never authored or passed through by synthesis Finish.
6960
*/
7061
summary: z.string().optional(),
7162
assetPackSynthesisArtifacts: AssetPackSynthesisArtifactsSchema.optional(),
7263
writtenAssets: WrittenAssetsSchema.optional(),
7364
deliveryMechanism: DeliveryMechanismSchema.optional(),
74-
/**
75-
* Only when settle Simple already ran on this execution (cross-pipeline
76-
* handoff). Omitted on pure deposit/read synthesis Finish.
77-
*/
78-
settlePassThrough: SettlePassThroughSchema.optional(),
7965
read: z.string().optional(),
8066
writtenAssetType: z.string().optional(),
8167
processingStats: z.object({
@@ -125,7 +111,7 @@ const AssetPackCompletionAgent = factoryAgentWithSingleStep<any, AssetPackComple
125111
(execution as any).prompt?.setSpecificExecution(
126112
'specific_execution:output:shape',
127113
(
128-
'Output JSON with keys: summary, assetPackSynthesisArtifacts{fileChanges,summary,proofEvidence?,reviewNotes?}, writtenAssets{fileChanges,summary}, deliveryMechanism{summary,readiness}, processingStats{…}, repoSnapshot{org,repo,branch,commit}. Optional settlePassThrough only if settle Simple already stored a shippable PR on this execution. SDIVF Finish closes synthesis evidence; buyer-repo PR shipping is settle-asset-pack-pipeline only.'
114+
'Output JSON with keys: summary, assetPackSynthesisArtifacts{fileChanges,summary,proofEvidence?,reviewNotes?}, writtenAssets{fileChanges,summary}, deliveryMechanism{summary,readiness}, processingStats{…}, repoSnapshot{org,repo,branch,commit}. Never settleDelivery / settlePassThrough / buyer-repo PR — those are settle-asset-pack-pipeline only. SDIVF Finish closes synthesis evidence only.'
129115
) as unknown as PromptPart
130116
);
131117
} catch {}
@@ -225,25 +211,9 @@ const AssetPackCompletionAgent = factoryAgentWithSingleStep<any, AssetPackComple
225211
}
226212
const summary = lines.join('\n');
227213

228-
// PR shipping is settle-only. Pass through only when settle Simple already
229-
// stored a shippable on this EE — never author settleDelivery on synthesis Finish.
230-
let settlePassThrough: AssetPackCompletionOutput['settlePassThrough'] | undefined;
214+
// Settlement / buyer-repo PR is never part of synthesis Finish — even if
215+
// settle keys exist on a shared EE. That surface is settle-asset-pack-pipeline only.
231216
const dtype = resolveWrittenAssetTypeFromExecution(execution);
232-
try {
233-
const settleShippable =
234-
findStoredExecutionValue(execution, 'settle-asset-pack-pipeline', 'shippable') || null;
235-
if (settleShippable?.prUrl) {
236-
settlePassThrough = {
237-
pullRequest: {
238-
url: settleShippable.prUrl,
239-
title: settleShippable.optionTitle || read || 'AssetPack delivery',
240-
number: undefined,
241-
},
242-
fileChanges: undefined,
243-
summary,
244-
};
245-
}
246-
} catch {}
247217

248218
const writtenAssets = {
249219
fileChanges: undefined,
@@ -264,9 +234,9 @@ const AssetPackCompletionAgent = factoryAgentWithSingleStep<any, AssetPackComple
264234
: {
265235
...writtenAssets,
266236
};
267-
// Delivery readiness for review surfaces — not a buyer-repo PR unless settle ran.
237+
// Review readiness only — never pullRequest / settleDelivery.
268238
const deliveryMechanism = {
269-
pullRequest: settlePassThrough?.pullRequest ?? null,
239+
pullRequest: null,
270240
summary,
271241
readiness: deliveryReadiness,
272242
};
@@ -276,7 +246,6 @@ const AssetPackCompletionAgent = factoryAgentWithSingleStep<any, AssetPackComple
276246
assetPackSynthesisArtifacts,
277247
writtenAssets,
278248
deliveryMechanism,
279-
...(settlePassThrough ? { settlePassThrough } : {}),
280249
read: read || undefined,
281250
writtenAssetType: dtype || undefined,
282251
processingStats,
@@ -286,7 +255,6 @@ const AssetPackCompletionAgent = factoryAgentWithSingleStep<any, AssetPackComple
286255
const output: AssetPackCompletionOutput = validated;
287256

288257
try {
289-
// Synthesis evidence only — do not store settleDelivery from Finish.
290258
(execution as any).store?.('finish/asset_pack_completion', 'summary', summary as any);
291259
(execution as any).store?.('finish/asset_pack_completion', 'assetPackSynthesisArtifacts', assetPackSynthesisArtifacts as any);
292260
(execution as any).store?.('finish/asset_pack_completion', 'writtenAssets', writtenAssets as any);
@@ -295,13 +263,6 @@ const AssetPackCompletionAgent = factoryAgentWithSingleStep<any, AssetPackComple
295263
(execution as any).store?.('finish/asset_pack_completion', 'writtenAssetType', dtype || undefined);
296264
(execution as any).store?.('finish/asset_pack_completion', 'processingStats', processingStats as any);
297265
(execution as any).store?.('finish/asset_pack_completion', 'repoSnapshot', repoSnapshot as any);
298-
if (settlePassThrough) {
299-
(execution as any).store?.(
300-
'finish/asset_pack_completion',
301-
'settlePassThrough',
302-
settlePassThrough as any,
303-
);
304-
}
305266
} catch {}
306267

307268
return output;

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

Lines changed: 21 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -57,25 +57,9 @@ export function normalizeAssetPackOutput(output: AssetPackOutput, execution: Exe
5757
(execution as any).findUp?.('depository/search', 'result') ||
5858
(execution as any).get?.('depository/search', 'result');
5959

60-
// PR URLs come from settle Simple (ship-asset-pack-patch-pr), not from the
61-
// Deposit/Read SDIVF Finish phase. Only surface a PR when settle already
62-
// recorded a shippable (or the result object was produced by settle).
63-
// Never invent a PR from finish/* store keys alone.
64-
const settleShippable = findStoredExecutionValue(
65-
execution,
66-
'settle-asset-pack-pipeline',
67-
'shippable',
68-
) as { prUrl?: string } | null;
69-
const prUrl =
70-
settleShippable?.prUrl ||
71-
enhanced.writtenAsset?.prUrl ||
72-
deliveryMechanism?.prUrl ||
73-
enhanced.shippable?.prUrl ||
74-
null;
75-
if (prUrl) {
76-
enhanced.deliveryMechanism = { ...(deliveryMechanism || {}), prUrl } as any;
77-
enhanced.shippable = { ...(enhanced.shippable || enhanced.deliveryMechanism || {}), prUrl } as any;
78-
}
60+
// Asset-pack *synthesis* postprocess never projects settle/PR shippables.
61+
// Buyer-repo PR / settleDelivery live exclusively on settle-asset-pack-pipeline.
62+
// Do not read settle-asset-pack-pipeline.shippable or invent prUrl here.
7963

8064
// 2) Backfill artifacts from execution if missing
8165
const filesModified = enhanced.artifacts?.filesModified?.length
@@ -88,11 +72,10 @@ export function normalizeAssetPackOutput(output: AssetPackOutput, execution: Exe
8872
} as any;
8973
}
9074

91-
// 3) Ensure a human-readable summary exists
75+
// 3) Ensure a human-readable summary exists (no settle/PR narrative).
9276
if (!enhanced.summary || !enhanced.summary.trim()) {
9377
const parts: string[] = [];
9478
parts.push(enhanced.success ? 'AssetPack synthesis artifacts completed.' : 'AssetPack synthesis artifacts finished with issues.');
95-
if (prUrl) parts.push(`PR: ${prUrl}`);
9679
if (filesModified?.length) parts.push(`Files modified: ${filesModified.length}`);
9780
enhanced.summary = parts.join(' ');
9881
}
@@ -117,7 +100,8 @@ export function normalizeAssetPackOutput(output: AssetPackOutput, execution: Exe
117100
if (depositorySearch) {
118101
(enhanced as any).depositorySearch = depositorySearch;
119102
}
120-
const sourceSafePreview = ensureAssetPackSourceSafePreview(execution, enhanced, prUrl);
103+
// No settle PR target in synthesis postprocess.
104+
const sourceSafePreview = ensureAssetPackSourceSafePreview(execution, enhanced, null);
121105
if (sourceSafePreview) {
122106
const assetPackDisclosureReview = ensureAssetPackDisclosureReview(execution, sourceSafePreview);
123107
const assetPackPreviewBoundary = ensureAssetPackPreviewBoundary(
@@ -308,59 +292,39 @@ export function buildAssetPackPostprocessedResult(
308292
ensureReadingOperationalTelemetryRepairReadback(execution, normalized);
309293
const readingInterfaceProductParity = ensureReadingInterfaceProductParity(execution, normalized);
310294
const readingLocalStagingRehearsal = ensureReadingLocalStagingRehearsal(execution, normalized);
311-
const shippable = normalized.shippable || normalized.deliveryMechanism;
312-
// settleDelivery is settle-pipeline exclusive. Only surface when settle Simple
313-
// already recorded a shippable on this EE (cross-pipeline handoff), never invent
314-
// a settle-shaped bag from synthesis finish or deliveryMechanism alone.
315-
const settleShippable =
316-
findStoredExecutionValue(execution, 'settle-asset-pack-pipeline', 'shippable') as
317-
| { prUrl?: string; optionTitle?: string }
318-
| null;
319-
const settleDeliveryFromSettleOnly =
320-
settleShippable?.prUrl
321-
? {
322-
pullRequest: {
323-
url: settleShippable.prUrl,
324-
title: settleShippable.optionTitle || finalSummary || 'AssetPack delivery',
325-
},
326-
summary: finalSummary || normalized.summary || null,
327-
}
328-
: (normalized as any).settleDelivery?.pullRequest?.url
329-
? (normalized as any).settleDelivery
330-
: null;
331295

296+
// Synthesis postprocess never emits settle_delivery / settleDelivery / settle
297+
// shippables — even if settle keys exist on a shared EE. Settlement is a
298+
// different pipeline (ExecutionPipelineSimpleSettleAssetPack).
332299
const productPipeline = resolveSynthesisProductPipeline(execution);
333300
const selectionEnvelope =
334301
findStoredExecutionValue(execution, 'finish', 'selectionEnvelope') ||
335302
(normalized as any).selectionEnvelope ||
336303
null;
337-
const kind = resolveSynthesisPostprocessKind(productPipeline, !!settleDeliveryFromSettleOnly);
304+
const kind = resolveSynthesisPostprocessKind(productPipeline);
338305

339306
return {
340307
executionId,
341308
kind,
342309
semanticKind: 'asset-pack-written-asset',
343310
title:
344311
normalized.writtenAsset?.title ||
345-
normalized.shippable?.title ||
346-
normalized.deliveryMechanism?.title ||
347312
finalSummary ||
348313
normalized.summary ||
349314
(kind === 'deposit_options' || kind === 'read_options'
350315
? 'AssetPack options'
351316
: 'Written Asset'),
352317
repository,
353318
summary: finalSummary,
354-
shippable: settleDeliveryFromSettleOnly
355-
? shippable
356-
: kind === 'deposit_options' || kind === 'read_options'
357-
? undefined
358-
: shippable,
359-
// Only attach when settle actually produced a PR — never synthesis-authored.
360-
...(settleDeliveryFromSettleOnly
361-
? { settleDelivery: settleDeliveryFromSettleOnly as any }
362-
: {}),
363-
deliveryMechanism: normalized.deliveryMechanism || (settleDeliveryFromSettleOnly ? shippable : undefined),
319+
// No shippable / settleDelivery on synthesis results.
320+
deliveryMechanism: normalized.deliveryMechanism
321+
? {
322+
// Strip any PR projection that may have leaked onto deliveryMechanism.
323+
...normalized.deliveryMechanism,
324+
prUrl: undefined,
325+
pullRequest: undefined,
326+
}
327+
: undefined,
364328
...(selectionEnvelope ? { selectionEnvelope } : {}),
365329
...((normalized as any).options || (normalized as any).depositOptions
366330
? {
@@ -790,16 +754,12 @@ function resolveSynthesisProductPipeline(execution: Execution): string {
790754
}
791755

792756
/**
793-
* Postprocess kind for synthesis product runs.
794-
* - deposit_options / read_options: selection envelopes for UI
795-
* - asset_pack_synthesis: generic synthesis completion evidence
796-
* - settle_delivery: only when settle Simple already produced a shippable PR
757+
* Postprocess kind for synthesis product runs only.
758+
* Never settle_delivery — that kind is exclusive to settle-asset-pack-pipeline.
797759
*/
798760
function resolveSynthesisPostprocessKind(
799761
productPipeline: string,
800-
hasSettleDelivery: boolean,
801762
): AssetPackPostprocessed['kind'] {
802-
if (hasSettleDelivery) return 'settle_delivery';
803763
if (
804764
productPipeline.includes('deposit') ||
805765
productPipeline === 'deposit'

0 commit comments

Comments
 (0)