Skip to content

Commit 21ffb23

Browse files
V48 (impl-only): Close settle dual-write and prefs dual-read
Host evidence, completion schema, and mocks emit settleDelivery with historical shippables dual-write. Header props use settleDelivery. Template prefs dual-read delivery_templates and shippable_templates. Migrate measure needinesses and tests to MeasurementKindCategory while keeping measurement aliases for remaining consumers. Typecheck green; focused tests pass.
1 parent d72efec commit 21ffb23

15 files changed

Lines changed: 82 additions & 63 deletions

File tree

apps/uapi/components/bitcode/pipeline/ExecutionsCompleteHeaderContent/ExecutionsCompleteHeaderContent.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ export type RepoSnapshot = { org: string; repo: string; branch: string; commit:
7878

7979
export type HeaderAssetPackCompletion = {
8080
summary?: string | null;
81+
settleDelivery?: HeaderSettleDelivery;
82+
/** Historical dual-write of settleDelivery. */
8183
shippables?: HeaderSettleDelivery;
8284
assetPackSynthesisArtifacts?: HeaderSettleDelivery;
8385
writtenAssets?: HeaderSettleDelivery;
@@ -105,13 +107,13 @@ const formatWrittenAssetType = (type?: string | null) => {
105107
};
106108

107109
export function CompleteHeaderContent({
108-
shippables,
110+
settleDelivery,
109111
processingStats,
110112
repoSnapshot,
111113
postprocessed,
112114
executionType,
113115
}: {
114-
shippables?: HeaderSettleDelivery;
116+
settleDelivery?: HeaderSettleDelivery;
115117
processingStats?: HeaderProcessingStats;
116118
repoSnapshot?: RepoSnapshot;
117119
postprocessed?: any;
@@ -123,7 +125,7 @@ export function CompleteHeaderContent({
123125
// - processingStats and repoSnapshot are sourced from server-computed asset_pack_completion objects
124126
// emitted by both pipelines. The UI renders only server-provided values.
125127
const [showFileDetails, setShowFileDetails] = React.useState(false);
126-
const settleDeliverySurface = shippables || {};
128+
const settleDeliverySurface = settleDelivery || {};
127129
const tldr: React.ReactNode[] = [];
128130
if (settleDeliverySurface?.pullRequest) {
129131
const pr = settleDeliverySurface.pullRequest;
@@ -347,7 +349,7 @@ export function getHeaderSettleDelivery(
347349
): HeaderSettleDelivery | null {
348350
// Prefer settleDelivery; dual-read historical shippables.
349351
return (
350-
(assetPackCompletion as any)?.settleDelivery ||
352+
assetPackCompletion?.settleDelivery ||
351353
assetPackCompletion?.shippables ||
352354
assetPackCompletion?.deliveryMechanism ||
353355
null

apps/uapi/components/bitcode/pipeline/ExecutionsPageHeader/ExecutionsPageHeader.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ interface ExecutionPageHeaderProps {
242242
templates?: DeliveryTemplateSets;
243243
onTemplateSelect?: (templateId: string, templateCategory: keyof DeliveryTemplateSets) => void;
244244
/** Settle delivery (buyer PR after rights). Bitcode-owned meaning lives in AssetPack evidence first. */
245-
shippables?: {
245+
settleDelivery?: {
246246
pullRequest?: DeliveryMechanismSurface | null; // Singular PR delivery mechanism.
247247
fileChanges?: FileChanges | null;
248248
summary?: string | null;
@@ -339,7 +339,7 @@ const childVariants = {
339339
*/
340340
export default function ExecutionsPageHeader({
341341
executionStatus: mode,
342-
shippables,
342+
settleDelivery,
343343
processingStats,
344344
repoSnapshot,
345345
onSelectDeliveryTemplateDefinitionOfNeed,
@@ -491,7 +491,7 @@ export default function ExecutionsPageHeader({
491491
};
492492
}, [entranceSpeedFactor]);
493493

494-
const effectiveSettleDelivery = shippables ?? {};
494+
const effectiveSettleDelivery = settleDelivery ?? {};
495495
const effectiveMode = mode;
496496
const iterationConfidence = typeof processingStats?.confidence === 'number' ? processingStats?.confidence : undefined;
497497
const awaitingInstruction = processingStats?.awaitingInstruction ?? (typeof iterationConfidence === 'number' ? iterationConfidence < INSTRUCTION_WAIT_THRESHOLD : false);
@@ -806,7 +806,7 @@ export default function ExecutionsPageHeader({
806806

807807
{effectiveMode === "executed" && effectiveSettleDelivery && (renderDocInsideHeader !== false) && (
808808
<CompleteHeaderContent
809-
shippables={effectiveSettleDelivery as any}
809+
settleDelivery={effectiveSettleDelivery as any}
810810
processingStats={processingStats as any}
811811
repoSnapshot={repoSnapshot as any}
812812
executionType={executionType}

apps/uapi/hooks/useTemplatePreferences.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@ import { useCallback, useEffect, useState } from 'react';
22

33
interface UserTemplatePreferencesApiResponse {
44
shippable_templates?: Record<string, string[]>;
5+
delivery_templates?: Record<string, string[]>;
56
evidence_document_templates?: Record<string, string[]>;
67
}
78

89
export interface UserTemplatePreferences {
910
shippable_templates: Record<string, string[]>;
11+
delivery_templates: Record<string, string[]>;
1012
evidence_document_templates: Record<string, string[]>;
1113
}
1214

@@ -22,7 +24,8 @@ interface UseTemplatePreferencesHook {
2224

2325
/**
2426
* Client-side hook that fetches the current user's saved template
25-
* preferences (Shippable & Evidence Document) from `/api/auxillaries/template-preferences`.
27+
* preferences (delivery templates & evidence documents) from
28+
* `/api/auxillaries/template-preferences`.
2629
*
2730
* It automatically fetches once on mount but also returns a `reload`
2831
* function should the caller read to refresh the data (e.g. after a
@@ -41,6 +44,7 @@ export const useTemplatePreferences = (): UseTemplatePreferencesHook => {
4144
if (res.status === 401 || res.status === 404) {
4245
setPreferences({
4346
shippable_templates: {},
47+
delivery_templates: {},
4448
evidence_document_templates: {},
4549
});
4650
return;
@@ -61,12 +65,14 @@ export const useTemplatePreferences = (): UseTemplatePreferencesHook => {
6165
const data = (await res.json()) as UserTemplatePreferencesApiResponse;
6266

6367
setPreferences({
64-
shippable_templates: data.shippable_templates ?? {},
68+
shippable_templates: data.delivery_templates ?? data.shippable_templates ?? {},
69+
delivery_templates: data.delivery_templates ?? data.shippable_templates ?? {},
6570
evidence_document_templates: data.evidence_document_templates ?? {},
6671
});
6772
} catch (err) {
6873
setPreferences({
6974
shippable_templates: {},
75+
delivery_templates: {},
7076
evidence_document_templates: {},
7177
});
7278
setError(err instanceof Error ? err.message : String(err));

apps/uapi/mocking/engines/StreamingPipelineEngine.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,8 @@ export class StreamingPipelineEngine {
654654
paths: ['src/mock.ts', 'README.md']
655655
}
656656
};
657-
const shippables = {
657+
// Settle delivery surface; dual-write historical shippables for reread.
658+
const settleDelivery = {
658659
pullRequest: {
659660
url: 'https://github.com/mock/repo/pull/123',
660661
number: 123,
@@ -667,14 +668,15 @@ export class StreamingPipelineEngine {
667668
return {
668669
summary: writtenAssets.summary,
669670
display: 'Mock Asset Pack',
670-
shippables,
671+
settleDelivery,
672+
shippables: settleDelivery,
671673
assetPackSynthesisArtifacts: {
672-
...shippables,
674+
...settleDelivery,
673675
proofEvidence: ['mock AssetPack evidence captured for reread'],
674676
reviewNotes: ['mock Read-satisfaction artifacts synthesized'],
675677
},
676678
writtenAssets,
677-
deliveryMechanism: shippables,
679+
deliveryMechanism: settleDelivery,
678680
semanticKind: 'asset-pack-written-asset',
679681
read: 'Mock retained corridor read',
680682
writtenAssetType: 'code-change',

apps/uapi/mocking/generators/MockDataGenerators.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,8 @@ class CompletionDataGenerator extends BaseDataGenerator {
477477
paths: ['src/main.ts', 'README.md', 'package.json'].slice(0, Math.floor(Math.random() * 3) + 1)
478478
} : null
479479
};
480-
const shippables = {
480+
// Settle delivery surface (buyer PR after rights); dual-write historical key.
481+
const settleDelivery = {
481482
pullRequest: hasPR ? {
482483
url: 'https://github.com/mock/repo/pull/123',
483484
number: 123,
@@ -491,14 +492,15 @@ class CompletionDataGenerator extends BaseDataGenerator {
491492
return {
492493
summary: writtenAssets.summary || this.generateRealisticText(25),
493494
display: 'Mock Asset Pack',
494-
shippables,
495+
settleDelivery,
496+
shippables: settleDelivery,
495497
assetPackSynthesisArtifacts: {
496-
...shippables,
498+
...settleDelivery,
497499
proofEvidence: ['mock AssetPack evidence captured for reread'],
498500
reviewNotes: ['mock Read-satisfaction artifacts synthesized'],
499501
},
500502
writtenAssets,
501-
deliveryMechanism: shippables,
503+
deliveryMechanism: settleDelivery,
502504
semanticKind: 'asset-pack-written-asset',
503505
read: this.generateRealisticText(10),
504506
writtenAssetType: this.pickRandom(['code-change', 'code-change-review', 'design-document']),

packages/agent-generics/src/__tests__/measure-agent.test.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
// @ts-nocheck
22
import {
33
factoryMeasureAgent,
4-
factoryMeasureAgentAbsolutes,
5-
MeasureAgentOutputSchema,
4+
factoryAbsolutesMeasureAgent,
5+
MeasurementOutputSchema,
66
MeasurementReadingSchema,
77
} from '../index';
88

@@ -27,8 +27,8 @@ describe('measure-agent base hierarchy', () => {
2727
expect(agent.measurementSpecs[0].measurementKind).toBe('function-count');
2828
});
2929

30-
it('factoryMeasureAgentAbsolutes bases measure-agent with the absolute category', () => {
31-
const agent = factoryMeasureAgentAbsolutes({
30+
it('factoryAbsolutesMeasureAgent bases measure-agent with the absolute category', () => {
31+
const agent = factoryAbsolutesMeasureAgent({
3232
name: 'test-measure-absolutes',
3333
subject: 'a synthesized source-safe AssetPack patch',
3434
measurements: SIZES,
@@ -41,7 +41,7 @@ describe('measure-agent base hierarchy', () => {
4141

4242
it('rejects an empty measurement catalog', () => {
4343
expect(() =>
44-
factoryMeasureAgentAbsolutes({
44+
factoryAbsolutesMeasureAgent({
4545
name: 'empty',
4646
subject: 'nothing',
4747
measurements: [],
@@ -50,7 +50,7 @@ describe('measure-agent base hierarchy', () => {
5050
});
5151

5252
it('output schema accepts readings (magnitude optional) and rejects out-of-range volume', () => {
53-
const ok = MeasureAgentOutputSchema.safeParse({
53+
const ok = MeasurementOutputSchema.safeParse({
5454
measurements: [
5555
{ measurementKind: 'function-count', magnitude: 12, volume: 0.6, rationale: 'twelve functions' },
5656
{ measurementKind: 'correctness-estimate', volume: 0.8, rationale: 'coherent' },

packages/agent-generics/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,7 @@ export {
103103
MeasurementReadingSchema,
104104
MeasurementOutputSchema,
105105
MeasureAgentOutputSchema,
106+
type MeasurementKindCategory,
106107
type MeasurementCategory,
107108
type MeasurementSpec,
108109
type MeasurementReading,

packages/api/src/routes/auxillaries-contract.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,7 @@ export function buildAuxillariesPreferencePosture(input: {
884884
const modelRecord = asRecord(toAuxillariesJsonSafe(input.modelPreferences ?? null));
885885
const templateRecord = asRecord(toAuxillariesJsonSafe(input.templatePreferences ?? null));
886886
const shippableTemplates =
887+
asRecord(templateRecord?.delivery_templates) ??
887888
asRecord(templateRecord?.shippable_templates) ??
888889
asRecord(templateRecord?.deliverable_templates);
889890
const evidenceDocumentTemplates =

packages/api/src/routes/auxillaries.ts

Lines changed: 16 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818

1919
const EMPTY_TEMPLATE_PREFERENCES = {
2020
shippable_templates: {},
21+
delivery_templates: {},
2122
evidence_document_templates: {},
2223
auto_save_templates: false,
2324
};
@@ -361,6 +362,7 @@ export function buildGetAuxillaryDataRoute(options: AuxillaryRouteBuilderOptions
361362
const templatePreferences = templatePreferencesResult.data
362363
? {
363364
shippable_templates: templatePreferencesResult.data.deliverable_templates || {},
365+
delivery_templates: templatePreferencesResult.data.deliverable_templates || {},
364366
evidence_document_templates: templatePreferencesResult.data.ai_document_templates || {},
365367
auto_save_templates: Boolean(templatePreferencesResult.data.auto_save_templates),
366368
}
@@ -546,6 +548,7 @@ export function buildGetAuxillaryTemplatePreferencesRoute(options: AuxillaryRout
546548

547549
return createJsonResponse({
548550
shippable_templates: data.deliverable_templates || {},
551+
delivery_templates: data.deliverable_templates || {},
549552
evidence_document_templates: data.ai_document_templates || {},
550553
});
551554
});
@@ -574,34 +577,25 @@ export function buildPostAuxillaryTemplatePreferencesRoute(options: AuxillaryRou
574577
return createJsonResponse({ error: 'Invalid JSON' }, 400);
575578
}
576579

577-
const payload =
578-
body && typeof body === 'object'
579-
? {
580-
shippable_templates:
581-
typeof (body as Record<string, unknown>).shippable_templates === 'object' &&
582-
(body as Record<string, unknown>).shippable_templates !== null
583-
? (body as Record<string, unknown>).shippable_templates
584-
: null,
585-
evidence_document_templates:
586-
typeof (body as Record<string, unknown>).evidence_document_templates === 'object' &&
587-
(body as Record<string, unknown>).evidence_document_templates !== null
588-
? (body as Record<string, unknown>).evidence_document_templates
589-
: null,
590-
}
591-
: {
592-
shippable_templates: null,
593-
evidence_document_templates: null,
594-
};
595-
596-
if (!payload.shippable_templates || !payload.evidence_document_templates) {
580+
const asObject = (value: unknown) =>
581+
typeof value === 'object' && value !== null ? value : null;
582+
const bodyRecord =
583+
body && typeof body === 'object' ? (body as Record<string, unknown>) : null;
584+
// Prefer delivery_templates; dual-read historical shippable_templates.
585+
const deliveryTemplates =
586+
asObject(bodyRecord?.delivery_templates) ||
587+
asObject(bodyRecord?.shippable_templates);
588+
const evidenceDocumentTemplates = asObject(bodyRecord?.evidence_document_templates);
589+
590+
if (!deliveryTemplates || !evidenceDocumentTemplates) {
597591
return createJsonResponse({ error: 'Invalid template preferences format' }, 400);
598592
}
599593

600594
const { error: upsertError } = await supabaseAdmin.from('user_template_preferences').upsert(
601595
{
602596
user_id: user.id,
603-
deliverable_templates: payload.shippable_templates,
604-
ai_document_templates: payload.evidence_document_templates,
597+
deliverable_templates: deliveryTemplates,
598+
ai_document_templates: evidenceDocumentTemplates,
605599
updated_at: new Date().toISOString(),
606600
},
607601
{ onConflict: 'user_id' },

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

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

55+
const SettleDeliverySurfaceSchema = z.object({
56+
pullRequest: ShippableSchema.nullable().optional(),
57+
fileChanges: FileChangesSchema.nullable().optional(),
58+
summary: z.string().nullable().optional(),
59+
});
60+
5561
export const AssetPackCompletionOutputSchema = z.object({
56-
shippables: z.object({
57-
pullRequest: ShippableSchema.nullable().optional(),
58-
fileChanges: FileChangesSchema.nullable().optional(),
59-
summary: z.string().nullable().optional(),
60-
}),
62+
/** Canonical settle delivery surface (buyer PR after rights). */
63+
settleDelivery: SettleDeliverySurfaceSchema.optional(),
64+
/** Historical dual-write of settleDelivery for reread clients. */
65+
shippables: SettleDeliverySurfaceSchema,
6166
assetPackSynthesisArtifacts: AssetPackSynthesisArtifactsSchema.optional(),
6267
writtenAssets: WrittenAssetsSchema.optional(),
6368
deliveryMechanism: DeliveryMechanismSchema.optional(),
@@ -256,8 +261,9 @@ const AssetPackCompletionAgent = factoryAgentWithSingleStep<any, AssetPackComple
256261
readiness: deliveryReadiness,
257262
};
258263

259-
// Validate and finalize output (schema still names shippables; dual-store settleDelivery).
264+
// Validate and finalize output dual-write settleDelivery + shippables.
260265
const validated = AssetPackCompletionOutputSchema.parse({
266+
settleDelivery: shippables,
261267
shippables,
262268
assetPackSynthesisArtifacts,
263269
writtenAssets,

0 commit comments

Comments
 (0)