@linimin/pi-letscook 0.1.67 → 0.1.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent/README.md +2 -3
- package/.agent/verify_completion_control_plane.sh +21 -34
- package/CHANGELOG.md +17 -0
- package/README.md +23 -26
- package/agents/completion-bootstrapper.md +1 -2
- package/agents/completion-regrounder.md +10 -16
- package/extensions/completion/driver.ts +49 -117
- package/extensions/completion/index.ts +74 -123
- package/extensions/completion/policy-guards.ts +1 -1
- package/extensions/completion/prompt-surfaces.ts +15 -156
- package/extensions/completion/proposal.ts +21 -21
- package/extensions/completion/role-runner.ts +10 -11
- package/extensions/completion/state-store.ts +43 -85
- package/extensions/completion/types.ts +2 -3
- package/package.json +1 -1
- package/scripts/active-slice-contract-test.sh +28 -12
- package/scripts/canonical-evidence-artifact-test.sh +46 -59
- package/scripts/context-proposal-test.sh +58 -57
- package/scripts/refocus-test.sh +17 -17
- package/scripts/release-check.sh +14 -13
- package/scripts/role-runner-contract-test.sh +2 -2
- package/scripts/smoke-test.sh +24 -71
- package/skills/completion-protocol/SKILL.md +8 -9
- package/skills/completion-protocol/references/completion.md +2 -37
- package/skills/cook-handoff-boundary/SKILL.md +18 -16
|
@@ -3,7 +3,6 @@ import { spawnSync } from "node:child_process";
|
|
|
3
3
|
import { promises as fsp } from "node:fs";
|
|
4
4
|
import * as os from "node:os";
|
|
5
5
|
import * as path from "node:path";
|
|
6
|
-
import { buildApprovedStartupPlanMarkdown } from "./prompt-surfaces";
|
|
7
6
|
import type { CompletionStateSnapshot, JsonRecord } from "./types";
|
|
8
7
|
|
|
9
8
|
const PROTOCOL_ID = "completion";
|
|
@@ -46,10 +45,9 @@ export function resolveFiles(root: string) {
|
|
|
46
45
|
statePath: path.join(agentDir, "state.json"),
|
|
47
46
|
planPath: path.join(agentDir, "plan.json"),
|
|
48
47
|
activePath: path.join(agentDir, "active-slice.json"),
|
|
49
|
-
startupPlanPath: path.join(agentDir, "startup-plan.json"),
|
|
50
|
-
startupPlanMarkdownPath: path.join(agentDir, "startup-plan.md"),
|
|
51
48
|
sliceHistoryPath: path.join(agentDir, "slice-history.jsonl"),
|
|
52
49
|
stopHistoryPath: path.join(agentDir, "stop-check-history.jsonl"),
|
|
50
|
+
startupBriefPath: path.join(agentDir, "startup-brief.json"),
|
|
53
51
|
verificationEvidencePath: path.join(agentDir, "verification-evidence.json"),
|
|
54
52
|
compactionMarkerPath: path.join(tmpDir, "post-compaction-recovery.json"),
|
|
55
53
|
};
|
|
@@ -144,7 +142,7 @@ export async function loadCompletionSnapshot(startCwd: string): Promise<Completi
|
|
|
144
142
|
const state = await readJson(files.statePath);
|
|
145
143
|
const plan = await readJson(files.planPath);
|
|
146
144
|
const active = await readJson(files.activePath);
|
|
147
|
-
const
|
|
145
|
+
const startupBrief = await readJson(files.startupBriefPath);
|
|
148
146
|
const verificationEvidence = await readJson(files.verificationEvidencePath);
|
|
149
147
|
return {
|
|
150
148
|
files,
|
|
@@ -152,7 +150,7 @@ export async function loadCompletionSnapshot(startCwd: string): Promise<Completi
|
|
|
152
150
|
state,
|
|
153
151
|
plan,
|
|
154
152
|
active,
|
|
155
|
-
|
|
153
|
+
startupBrief,
|
|
156
154
|
verificationEvidence,
|
|
157
155
|
activeSlice: findActiveSlice(plan, active),
|
|
158
156
|
};
|
|
@@ -233,15 +231,25 @@ export function buildProfileRecord(args: {
|
|
|
233
231
|
};
|
|
234
232
|
}
|
|
235
233
|
|
|
234
|
+
function buildWorkflowSessionId(): string {
|
|
235
|
+
return `wf-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
236
|
+
}
|
|
237
|
+
|
|
236
238
|
export function defaultState(
|
|
237
239
|
missionAnchor: string,
|
|
238
240
|
routing?: { taskType?: string; evaluationProfile?: string; continuationReason?: string },
|
|
239
241
|
advisoryStartupBrief?: JsonRecord,
|
|
240
242
|
): JsonRecord {
|
|
243
|
+
const confirmedAt = asString(advisoryStartupBrief?.captured_at) ?? new Date().toISOString();
|
|
241
244
|
return {
|
|
242
245
|
schema_version: 1,
|
|
243
246
|
mission_anchor: missionAnchor,
|
|
244
247
|
advisory_startup_brief: advisoryStartupBrief ?? null,
|
|
248
|
+
workflow_entry_status: "active",
|
|
249
|
+
workflow_entry_source: "/cook",
|
|
250
|
+
workflow_entry_confirmed_at: confirmedAt,
|
|
251
|
+
workflow_session_id: buildWorkflowSessionId(),
|
|
252
|
+
startup_brief_path: ".agent/startup-brief.json",
|
|
245
253
|
current_phase: "reground",
|
|
246
254
|
continuation_policy: "continue",
|
|
247
255
|
continuation_reason: routing?.continuationReason ?? "Fresh completion bootstrap requires canonical re-ground",
|
|
@@ -280,32 +288,6 @@ export function defaultPlan(
|
|
|
280
288
|
};
|
|
281
289
|
}
|
|
282
290
|
|
|
283
|
-
export function defaultStartupPlan(
|
|
284
|
-
missionAnchor: string,
|
|
285
|
-
routing?: { taskType?: string; evaluationProfile?: string },
|
|
286
|
-
approvedStartupPlan?: JsonRecord,
|
|
287
|
-
): JsonRecord {
|
|
288
|
-
return approvedStartupPlan ?? {
|
|
289
|
-
schema_version: 1,
|
|
290
|
-
artifact_type: "completion-startup-plan",
|
|
291
|
-
status: "approved",
|
|
292
|
-
source: "recent_discussion",
|
|
293
|
-
captured_at: null,
|
|
294
|
-
mission_anchor: missionAnchor,
|
|
295
|
-
goal_text: `Mission: ${missionAnchor}`,
|
|
296
|
-
task_type: routing?.taskType ?? DEFAULT_TASK_TYPE,
|
|
297
|
-
evaluation_profile: routing?.evaluationProfile ?? DEFAULT_EVALUATION_PROFILE,
|
|
298
|
-
scope: [],
|
|
299
|
-
constraints: [],
|
|
300
|
-
acceptance: [],
|
|
301
|
-
risks: [],
|
|
302
|
-
notes: ["No approved startup plan has been recorded yet."],
|
|
303
|
-
planned_surfaces: [],
|
|
304
|
-
verification_intent: [],
|
|
305
|
-
sequencing_hints: [],
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
|
|
309
291
|
export function defaultActiveSlice(
|
|
310
292
|
missionAnchor: string,
|
|
311
293
|
routing?: { taskType?: string; evaluationProfile?: string },
|
|
@@ -334,6 +316,32 @@ export function defaultActiveSlice(
|
|
|
334
316
|
};
|
|
335
317
|
}
|
|
336
318
|
|
|
319
|
+
export function defaultStartupBrief(
|
|
320
|
+
missionAnchor: string,
|
|
321
|
+
routing?: { taskType?: string; evaluationProfile?: string },
|
|
322
|
+
advisoryStartupBrief?: JsonRecord,
|
|
323
|
+
): JsonRecord {
|
|
324
|
+
return {
|
|
325
|
+
schema_version: 1,
|
|
326
|
+
artifact_type: "completion-startup-brief",
|
|
327
|
+
source: asString(advisoryStartupBrief?.source) ?? "primary_agent",
|
|
328
|
+
confirmed: true,
|
|
329
|
+
confirmed_at: asString(advisoryStartupBrief?.captured_at) ?? new Date().toISOString(),
|
|
330
|
+
mission: asString(advisoryStartupBrief?.mission) ?? missionAnchor,
|
|
331
|
+
goal_text: asString(advisoryStartupBrief?.goal_text) ?? `Mission: ${missionAnchor}`,
|
|
332
|
+
scope: asStringArray(advisoryStartupBrief?.scope),
|
|
333
|
+
constraints: asStringArray(advisoryStartupBrief?.constraints),
|
|
334
|
+
acceptance: asStringArray(advisoryStartupBrief?.acceptance),
|
|
335
|
+
risks: asStringArray(advisoryStartupBrief?.risks),
|
|
336
|
+
notes:
|
|
337
|
+
asStringArray(advisoryStartupBrief?.notes).length > 0
|
|
338
|
+
? asStringArray(advisoryStartupBrief?.notes)
|
|
339
|
+
: ["No additional startup notes were preserved for this workflow entry."],
|
|
340
|
+
task_type: asString(advisoryStartupBrief?.task_type) ?? routing?.taskType ?? DEFAULT_TASK_TYPE,
|
|
341
|
+
evaluation_profile: asString(advisoryStartupBrief?.evaluation_profile) ?? routing?.evaluationProfile ?? DEFAULT_EVALUATION_PROFILE,
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
|
|
337
345
|
export function defaultVerificationEvidence(): JsonRecord {
|
|
338
346
|
return {
|
|
339
347
|
schema_version: 1,
|
|
@@ -352,7 +360,7 @@ export function defaultVerificationEvidence(): JsonRecord {
|
|
|
352
360
|
}
|
|
353
361
|
|
|
354
362
|
export function buildAgentReadme(projectName: string): string {
|
|
355
|
-
return `# Completion Control Plane\n\nThis repository uses the \`completion\` workflow for long-running coding tasks.\n\n## Canonical tracked contract files\n\n- \`.agent/README.md\`\n- \`.agent/mission.md\`\n- \`.agent/profile.json\`\n- \`.agent/verify_completion_stop.sh\`\n- \`.agent/verify_completion_control_plane.sh\`\n\n## Ignored canonical execution state\n\n- \`.agent/state.json\`\n- \`.agent/startup-
|
|
363
|
+
return `# Completion Control Plane\n\nThis repository uses the \`completion\` workflow for long-running coding tasks.\n\n## Canonical tracked contract files\n\n- \`.agent/README.md\`\n- \`.agent/mission.md\`\n- \`.agent/profile.json\`\n- \`.agent/verify_completion_stop.sh\`\n- \`.agent/verify_completion_control_plane.sh\`\n\n## Ignored canonical execution state\n\n- \`.agent/state.json\`\n- \`.agent/startup-brief.json\`\n- \`.agent/plan.json\`\n- \`.agent/active-slice.json\`\n- \`.agent/slice-history.jsonl\`\n- \`.agent/stop-check-history.jsonl\`\n- \`.agent/verification-evidence.json\`\n- \`.agent/*.log\`\n- \`.agent/tmp/\`\n\n\`.agent/startup-brief.json\` preserves the confirmed \`/cook\` startup intent as canonical intake for re-grounding. It does not replace \`.agent/plan.json\` or \`.agent/active-slice.json\`, which remain under regrounder authority.\n\n\`.agent/verification-evidence.json\` is the durable canonical record of deterministic verification for the selected slice or current HEAD. Recovery, review, audit, and stop-check reminder surfaces consume it instead of temp-only artifacts or conversational summaries when it is populated.\n\nThe source of truth for long-running completion work is canonical \`.agent/**\` state plus current repo truth.\n\nProject: ${projectName}\n`;
|
|
356
364
|
}
|
|
357
365
|
|
|
358
366
|
export function buildMission(projectName: string, missionAnchor: string): string {
|
|
@@ -455,23 +463,15 @@ function trackedDiffFiles(fromCommit, toCommit) {
|
|
|
455
463
|
|
|
456
464
|
const profile = readJson('.agent/profile.json');
|
|
457
465
|
const state = readJson('.agent/state.json');
|
|
458
|
-
const startupPlan = readJson('.agent/startup-plan.json');
|
|
459
466
|
const plan = readJson('.agent/plan.json');
|
|
460
467
|
const active = readJson('.agent/active-slice.json');
|
|
461
468
|
const evidence = readJson('.agent/verification-evidence.json');
|
|
462
|
-
let startupPlanMarkdown = '';
|
|
463
|
-
try {
|
|
464
|
-
startupPlanMarkdown = fs.readFileSync('.agent/startup-plan.md', 'utf8');
|
|
465
|
-
} catch (error) {
|
|
466
|
-
fail('.agent/startup-plan.md must be present and readable: ' + error.message);
|
|
467
|
-
}
|
|
468
469
|
|
|
469
470
|
ensureTrackedContractFiles();
|
|
470
471
|
|
|
471
472
|
for (const [file, record] of [
|
|
472
473
|
['.agent/profile.json', profile],
|
|
473
474
|
['.agent/state.json', state],
|
|
474
|
-
['.agent/startup-plan.json', startupPlan],
|
|
475
475
|
['.agent/plan.json', plan],
|
|
476
476
|
['.agent/active-slice.json', active],
|
|
477
477
|
]) {
|
|
@@ -482,38 +482,12 @@ for (const [file, record] of [
|
|
|
482
482
|
const taskType = asString(profile.task_type);
|
|
483
483
|
const evaluationProfile = asString(profile.evaluation_profile);
|
|
484
484
|
if (asString(state.task_type) !== taskType) fail('.agent/state.json task_type must match .agent/profile.json task_type');
|
|
485
|
-
if (asString(startupPlan.task_type) !== taskType) fail('.agent/startup-plan.json task_type must match .agent/profile.json task_type');
|
|
486
485
|
if (asString(plan.task_type) !== taskType) fail('.agent/plan.json task_type must match .agent/profile.json task_type');
|
|
487
486
|
if (asString(active.task_type) !== taskType) fail('.agent/active-slice.json task_type must match .agent/profile.json task_type');
|
|
488
487
|
if (asString(state.evaluation_profile) !== evaluationProfile) fail('.agent/state.json evaluation_profile must match .agent/profile.json evaluation_profile');
|
|
489
|
-
if (asString(startupPlan.evaluation_profile) !== evaluationProfile) fail('.agent/startup-plan.json evaluation_profile must match .agent/profile.json evaluation_profile');
|
|
490
488
|
if (asString(plan.evaluation_profile) !== evaluationProfile) fail('.agent/plan.json evaluation_profile must match .agent/profile.json evaluation_profile');
|
|
491
489
|
if (asString(active.evaluation_profile) !== evaluationProfile) fail('.agent/active-slice.json evaluation_profile must match .agent/profile.json evaluation_profile');
|
|
492
490
|
|
|
493
|
-
if (asString(startupPlan.artifact_type) !== 'completion-startup-plan') {
|
|
494
|
-
fail('.agent/startup-plan.json artifact_type must be completion-startup-plan');
|
|
495
|
-
}
|
|
496
|
-
if (asString(startupPlan.status) !== 'approved') {
|
|
497
|
-
fail('.agent/startup-plan.json status must be approved');
|
|
498
|
-
}
|
|
499
|
-
const startupPlanMissionAnchor = asString(startupPlan.mission_anchor);
|
|
500
|
-
if (!startupPlanMissionAnchor) fail('.agent/startup-plan.json mission_anchor must be present');
|
|
501
|
-
if (startupPlanMissionAnchor !== asString(state.mission_anchor)) fail('.agent/startup-plan.json mission_anchor must match .agent/state.json mission_anchor');
|
|
502
|
-
if (startupPlanMissionAnchor !== asString(plan.mission_anchor)) fail('.agent/startup-plan.json mission_anchor must match .agent/plan.json mission_anchor');
|
|
503
|
-
if (startupPlanMissionAnchor !== asString(active.mission_anchor)) fail('.agent/startup-plan.json mission_anchor must match .agent/active-slice.json mission_anchor');
|
|
504
|
-
if (!asString(startupPlan.goal_text)) fail('.agent/startup-plan.json goal_text must be present');
|
|
505
|
-
for (const field of ['scope', 'constraints', 'acceptance', 'risks', 'notes', 'planned_surfaces', 'verification_intent', 'sequencing_hints']) {
|
|
506
|
-
if (!Array.isArray(startupPlan[field])) fail('.agent/startup-plan.json is missing ' + field);
|
|
507
|
-
}
|
|
508
|
-
if (startupPlanMarkdown.trim().length === 0) fail('.agent/startup-plan.md must not be empty');
|
|
509
|
-
if (startupPlanMissionAnchor && !startupPlanMarkdown.includes(startupPlanMissionAnchor)) {
|
|
510
|
-
fail('.agent/startup-plan.md must mention the startup-plan mission_anchor');
|
|
511
|
-
}
|
|
512
|
-
const startupPlanGoalText = asString(startupPlan.goal_text);
|
|
513
|
-
if (startupPlanGoalText && !startupPlanMarkdown.includes(startupPlanGoalText)) {
|
|
514
|
-
fail('.agent/startup-plan.md must render the startup-plan goal_text');
|
|
515
|
-
}
|
|
516
|
-
|
|
517
491
|
if (asString(evidence.artifact_type) !== 'completion-verification-evidence') {
|
|
518
492
|
fail('.agent/verification-evidence.json artifact_type must be completion-verification-evidence');
|
|
519
493
|
}
|
|
@@ -660,12 +634,7 @@ export type ScaffoldResult = {
|
|
|
660
634
|
export async function scaffoldCompletionFiles(
|
|
661
635
|
root: string,
|
|
662
636
|
missionAnchor: string,
|
|
663
|
-
options?: {
|
|
664
|
-
analysis?: { taskType?: string; evaluationProfile?: string };
|
|
665
|
-
continuationReason?: string;
|
|
666
|
-
advisoryStartupBrief?: JsonRecord;
|
|
667
|
-
approvedStartupPlan?: JsonRecord;
|
|
668
|
-
},
|
|
637
|
+
options?: { analysis?: { taskType?: string; evaluationProfile?: string }; continuationReason?: string; advisoryStartupBrief?: JsonRecord },
|
|
669
638
|
): Promise<ScaffoldResult> {
|
|
670
639
|
const files = resolveFiles(root);
|
|
671
640
|
const created: string[] = [];
|
|
@@ -675,10 +644,6 @@ export async function scaffoldCompletionFiles(
|
|
|
675
644
|
const projectName = path.basename(root);
|
|
676
645
|
const docsSurfaces = await detectDocsSurfaces(root);
|
|
677
646
|
const verifierCommand = await detectVerifierCommand(root);
|
|
678
|
-
const startupPlanRecord =
|
|
679
|
-
options?.approvedStartupPlan ??
|
|
680
|
-
(await readJson(files.startupPlanPath)) ??
|
|
681
|
-
defaultStartupPlan(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile });
|
|
682
647
|
const trackedFiles: Array<{ path: string; content: string; executable?: boolean }> = [
|
|
683
648
|
{ path: path.join(files.agentDir, "README.md"), content: buildAgentReadme(projectName) },
|
|
684
649
|
{ path: path.join(files.agentDir, "mission.md"), content: buildMission(projectName, missionAnchor) },
|
|
@@ -693,12 +658,8 @@ export async function scaffoldCompletionFiles(
|
|
|
693
658
|
content: `${JSON.stringify(defaultState(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile, continuationReason: options?.continuationReason }, options?.advisoryStartupBrief), null, 2)}\n`,
|
|
694
659
|
},
|
|
695
660
|
{
|
|
696
|
-
path: files.
|
|
697
|
-
content: `${JSON.stringify(
|
|
698
|
-
},
|
|
699
|
-
{
|
|
700
|
-
path: files.startupPlanMarkdownPath,
|
|
701
|
-
content: buildApprovedStartupPlanMarkdown(startupPlanRecord as any),
|
|
661
|
+
path: files.startupBriefPath,
|
|
662
|
+
content: `${JSON.stringify(defaultStartupBrief(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile }, options?.advisoryStartupBrief), null, 2)}\n`,
|
|
702
663
|
},
|
|
703
664
|
{ path: files.planPath, content: `${JSON.stringify(defaultPlan(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile }), null, 2)}\n` },
|
|
704
665
|
{ path: files.activePath, content: `${JSON.stringify(defaultActiveSlice(missionAnchor, { taskType: options?.analysis?.taskType, evaluationProfile: options?.analysis?.evaluationProfile }), null, 2)}\n` },
|
|
@@ -721,7 +682,6 @@ export function currentTaskType(snapshot: CompletionStateSnapshot): string | und
|
|
|
721
682
|
return (
|
|
722
683
|
asString(snapshot.active?.task_type) ??
|
|
723
684
|
asString(snapshot.state?.task_type) ??
|
|
724
|
-
asString(snapshot.startupPlan?.task_type) ??
|
|
725
685
|
asString(snapshot.plan?.task_type) ??
|
|
726
686
|
asString(snapshot.profile?.task_type)
|
|
727
687
|
);
|
|
@@ -731,7 +691,6 @@ export function currentEvaluationProfile(snapshot: CompletionStateSnapshot): str
|
|
|
731
691
|
return (
|
|
732
692
|
asString(snapshot.active?.evaluation_profile) ??
|
|
733
693
|
asString(snapshot.state?.evaluation_profile) ??
|
|
734
|
-
asString(snapshot.startupPlan?.evaluation_profile) ??
|
|
735
694
|
asString(snapshot.plan?.evaluation_profile) ??
|
|
736
695
|
asString(snapshot.profile?.evaluation_profile)
|
|
737
696
|
);
|
|
@@ -740,7 +699,6 @@ export function currentEvaluationProfile(snapshot: CompletionStateSnapshot): str
|
|
|
740
699
|
export function currentMissionAnchor(snapshot: CompletionStateSnapshot): string {
|
|
741
700
|
return (
|
|
742
701
|
asString(snapshot.state?.mission_anchor) ??
|
|
743
|
-
asString(snapshot.startupPlan?.mission_anchor) ??
|
|
744
702
|
asString(snapshot.plan?.mission_anchor) ??
|
|
745
703
|
asString(snapshot.active?.mission_anchor) ??
|
|
746
704
|
path.basename(snapshot.files.root)
|
|
@@ -18,10 +18,9 @@ export type CompletionFiles = {
|
|
|
18
18
|
statePath: string;
|
|
19
19
|
planPath: string;
|
|
20
20
|
activePath: string;
|
|
21
|
-
startupPlanPath: string;
|
|
22
|
-
startupPlanMarkdownPath: string;
|
|
23
21
|
sliceHistoryPath: string;
|
|
24
22
|
stopHistoryPath: string;
|
|
23
|
+
startupBriefPath: string;
|
|
25
24
|
verificationEvidencePath: string;
|
|
26
25
|
compactionMarkerPath: string;
|
|
27
26
|
};
|
|
@@ -32,7 +31,7 @@ export type CompletionStateSnapshot = {
|
|
|
32
31
|
state?: JsonRecord;
|
|
33
32
|
plan?: JsonRecord;
|
|
34
33
|
active?: JsonRecord;
|
|
35
|
-
|
|
34
|
+
startupBrief?: JsonRecord;
|
|
36
35
|
verificationEvidence?: JsonRecord;
|
|
37
36
|
activeSlice?: JsonRecord;
|
|
38
37
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@linimin/pi-letscook",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.69",
|
|
4
4
|
"description": "Pi package for long-running completion workflows with canonical .agent state, role-based subagents, continuity, and verification helpers.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -137,17 +137,16 @@ NODE
|
|
|
137
137
|
ROOT="$TMPDIR/repo"
|
|
138
138
|
PROMPT="$TMPDIR/resume-prompt.txt"
|
|
139
139
|
BOOTSTRAP_SESSION="$TMPDIR/session-active-slice-bootstrap.jsonl"
|
|
140
|
-
|
|
140
|
+
BOOTSTRAP_DISCUSSION=$'Prepare the active-slice contract bootstrap fixture and tell me when it is ready for /cook.'
|
|
141
|
+
GENERATED_HANDOFF="$(python3 - <<'PY'
|
|
141
142
|
import json
|
|
142
143
|
capsule = {
|
|
143
144
|
"kind": "cook_handoff",
|
|
144
145
|
"source": "primary_agent",
|
|
145
|
-
"captured_at": "2026-01-01T00:00:02.000Z",
|
|
146
|
-
"source_turn_id": "m0002",
|
|
147
146
|
"mission": "Exercise active-slice contract parity.",
|
|
148
147
|
"scope": [
|
|
149
148
|
"Bootstrap canonical completion files for the active-slice contract fixture.",
|
|
150
|
-
"Keep the fixture on the shipped
|
|
149
|
+
"Keep the fixture on the shipped same-entry synthesis startup path."
|
|
151
150
|
],
|
|
152
151
|
"constraints": [
|
|
153
152
|
"Use supported bare /cook startup only."
|
|
@@ -157,7 +156,7 @@ capsule = {
|
|
|
157
156
|
"Keep scripts/active-slice-contract-test.sh aligned with the packaged startup contract."
|
|
158
157
|
],
|
|
159
158
|
"risks": [
|
|
160
|
-
"Active-slice fixture bootstrap must stay anchored to
|
|
159
|
+
"Active-slice fixture bootstrap must stay anchored to same-entry primary-agent startup-plan synthesis."
|
|
161
160
|
],
|
|
162
161
|
"notes": [
|
|
163
162
|
"This handoff exists only to scaffold canonical files before the fixture rewrites them for contract parity coverage."
|
|
@@ -179,20 +178,16 @@ capsule = {
|
|
|
179
178
|
"evaluation_profile": "completion-rubric-v1",
|
|
180
179
|
"why_cook_now": "The fixture bootstrap is concrete enough to scaffold canonical control-plane files."
|
|
181
180
|
}
|
|
182
|
-
|
|
183
|
-
{"role": "user", "content": "Prepare the active-slice contract bootstrap fixture and tell me when it is ready for /cook."},
|
|
184
|
-
{"role": "assistant", "content": "The active-slice contract bootstrap fixture is ready for /cook. Run /cook to confirm it.\n\n```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```"},
|
|
185
|
-
]
|
|
186
|
-
print(json.dumps(messages, ensure_ascii=False))
|
|
181
|
+
print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
|
|
187
182
|
PY
|
|
188
183
|
)"
|
|
189
184
|
mkdir -p "$ROOT"
|
|
190
185
|
cd "$ROOT"
|
|
191
186
|
git init -q
|
|
192
|
-
|
|
187
|
+
write_session "$BOOTSTRAP_SESSION" "$ROOT" "$BOOTSTRAP_DISCUSSION"
|
|
193
188
|
|
|
194
189
|
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
195
|
-
|
|
190
|
+
PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$GENERATED_HANDOFF" \
|
|
196
191
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
197
192
|
pi --session "$BOOTSTRAP_SESSION" -e "$PKG_ROOT" -p "/cook" \
|
|
198
193
|
>"$TMPDIR/pi-active-slice-bootstrap.out" 2>"$TMPDIR/pi-active-slice-bootstrap.err"
|
|
@@ -247,6 +242,11 @@ acceptance = [
|
|
|
247
242
|
state = {
|
|
248
243
|
'schema_version': 1,
|
|
249
244
|
'mission_anchor': mission,
|
|
245
|
+
'workflow_entry_status': 'active',
|
|
246
|
+
'workflow_entry_source': '/cook',
|
|
247
|
+
'workflow_entry_confirmed_at': '2026-05-03T00:00:00Z',
|
|
248
|
+
'workflow_session_id': 'active-slice-fixture-session',
|
|
249
|
+
'startup_brief_path': '.agent/startup-brief.json',
|
|
250
250
|
'current_phase': 'implement',
|
|
251
251
|
'continuation_policy': 'continue',
|
|
252
252
|
'continuation_reason': 'Fixture for active-slice contract regression coverage.',
|
|
@@ -321,6 +321,22 @@ active = {
|
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
Path('.agent/state.json').write_text(json.dumps(state, indent=2) + '\n')
|
|
324
|
+
Path('.agent/startup-brief.json').write_text(json.dumps({
|
|
325
|
+
'schema_version': 1,
|
|
326
|
+
'artifact_type': 'completion-startup-brief',
|
|
327
|
+
'source': 'primary_agent',
|
|
328
|
+
'confirmed': True,
|
|
329
|
+
'confirmed_at': '2026-05-03T00:00:00Z',
|
|
330
|
+
'mission': mission,
|
|
331
|
+
'goal_text': f'Mission: {mission}',
|
|
332
|
+
'scope': ['Exercise active-slice contract parity.'],
|
|
333
|
+
'constraints': ['Keep the fixture scoped to active-slice contract coverage.'],
|
|
334
|
+
'acceptance': acceptance,
|
|
335
|
+
'risks': ['Fixture drift can hide active-slice contract regressions.'],
|
|
336
|
+
'notes': ['Fixture startup brief for active-slice contract regression coverage.'],
|
|
337
|
+
'task_type': task_type,
|
|
338
|
+
'evaluation_profile': evaluation_profile,
|
|
339
|
+
}, indent=2) + '\n')
|
|
324
340
|
Path('.agent/plan.json').write_text(json.dumps(plan, indent=2) + '\n')
|
|
325
341
|
Path('.agent/active-slice.json').write_text(json.dumps(active, indent=2) + '\n')
|
|
326
342
|
Path('.agent/verification-evidence.json').write_text(json.dumps({
|
|
@@ -134,11 +134,11 @@ assertIncludes('.agent/README.md', 'durable canonical record of deterministic ve
|
|
|
134
134
|
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Canonical Files', '- `.agent/verification-evidence.json`');
|
|
135
135
|
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Canonical Inputs', '- `.agent/verification-evidence.json`');
|
|
136
136
|
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Compaction And Recovery', '- `.agent/verification-evidence.json`');
|
|
137
|
-
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Compaction And Recovery', '`completion-implementer` must also re-read canonical `.agent/state.json`, `.agent/
|
|
137
|
+
assertSectionIncludes('skills/completion-protocol/SKILL.md', '## Compaction And Recovery', '`completion-implementer` must also re-read canonical `.agent/state.json`, `.agent/plan.json`, `.agent/active-slice.json`, and `.agent/verification-evidence.json` before resuming work.');
|
|
138
138
|
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Ignored Canonical Execution State', '- `.agent/verification-evidence.json`');
|
|
139
139
|
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Canonical Inputs', '- `.agent/verification-evidence.json`');
|
|
140
140
|
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Compaction And Recovery', '- `.agent/verification-evidence.json`');
|
|
141
|
-
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Compaction And Recovery', '`completion-implementer` must also re-read canonical `.agent/state.json`, `.agent/
|
|
141
|
+
assertSectionIncludes('skills/completion-protocol/references/completion.md', '## Compaction And Recovery', '`completion-implementer` must also re-read canonical `.agent/state.json`, `.agent/plan.json`, `.agent/active-slice.json`, and `.agent/verification-evidence.json` before resuming work.');
|
|
142
142
|
assertIncludes('extensions/completion/prompt-surfaces.ts', 'Verification evidence artifact: ${args.evidence.path} (${args.evidence.status})');
|
|
143
143
|
assertIncludes('extensions/completion/prompt-surfaces.ts', 'Verification evidence summary: ${args.evidence.summary}');
|
|
144
144
|
assertIncludes('extensions/completion/index.ts', 'Canonical verification evidence artifact is currently: ${evidence.path} (${evidence.status})');
|
|
@@ -157,6 +157,13 @@ bash .agent/verify_completion_control_plane.sh >/dev/null
|
|
|
157
157
|
CURRENT_EVIDENCE_BACKUP="$TMPDIR/current-verification-evidence.json"
|
|
158
158
|
cp .agent/verification-evidence.json "$CURRENT_EVIDENCE_BACKUP"
|
|
159
159
|
|
|
160
|
+
CURRENT_EVIDENCE_SUBJECT_TYPE="$(python3 - <<'PY'
|
|
161
|
+
import json
|
|
162
|
+
from pathlib import Path
|
|
163
|
+
print(json.loads(Path('.agent/verification-evidence.json').read_text()).get('subject_type', ''))
|
|
164
|
+
PY
|
|
165
|
+
)"
|
|
166
|
+
|
|
160
167
|
python3 - <<'PY'
|
|
161
168
|
import json
|
|
162
169
|
from pathlib import Path
|
|
@@ -166,14 +173,16 @@ evidence['head_sha'] = 'stale-head'
|
|
|
166
173
|
path.write_text(json.dumps(evidence, indent=2) + '\n')
|
|
167
174
|
PY
|
|
168
175
|
|
|
169
|
-
if
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
176
|
+
if [[ "$CURRENT_EVIDENCE_SUBJECT_TYPE" == "selected_slice" ]]; then
|
|
177
|
+
if bash ./scripts/release-check.sh >/dev/null 2>&1; then
|
|
178
|
+
echo "expected release-check to fail when current repo verification-evidence.json is stale" >&2
|
|
179
|
+
exit 1
|
|
180
|
+
fi
|
|
173
181
|
|
|
174
|
-
if bash .agent/verify_completion_stop.sh >/dev/null 2>&1; then
|
|
175
|
-
|
|
176
|
-
|
|
182
|
+
if bash .agent/verify_completion_stop.sh >/dev/null 2>&1; then
|
|
183
|
+
echo "expected verify_completion_stop.sh to fail when current repo verification-evidence.json is stale" >&2
|
|
184
|
+
exit 1
|
|
185
|
+
fi
|
|
177
186
|
fi
|
|
178
187
|
|
|
179
188
|
cp "$CURRENT_EVIDENCE_BACKUP" .agent/verification-evidence.json
|
|
@@ -198,11 +207,11 @@ capsule = {
|
|
|
198
207
|
"Use supported bare /cook startup only."
|
|
199
208
|
],
|
|
200
209
|
"acceptance": [
|
|
201
|
-
"
|
|
210
|
+
"Write the workflow control-plane files under .agent, including profile.json, state.json, active-slice.json, verification-evidence.json, and the slice backlog file, before the fixture rewrites them.",
|
|
202
211
|
"Keep scripts/canonical-evidence-artifact-test.sh aligned with packaged bootstrap behavior."
|
|
203
212
|
],
|
|
204
213
|
"risks": [
|
|
205
|
-
"Evidence-artifact bootstrap must stay anchored to the fresh explicit
|
|
214
|
+
"Evidence-artifact bootstrap must stay anchored to the fresh explicit handoff."
|
|
206
215
|
],
|
|
207
216
|
"notes": [
|
|
208
217
|
"This fixture exists only to scaffold canonical files before rewriting them for evidence parity coverage."
|
|
@@ -242,12 +251,12 @@ PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
|
242
251
|
pi --session "$BOOTSTRAP_SESSION" -e "$PKG_ROOT" -p "/cook" \
|
|
243
252
|
>"$TMPDIR/pi-canonical-evidence-bootstrap.out" 2>"$TMPDIR/pi-canonical-evidence-bootstrap.err"
|
|
244
253
|
|
|
245
|
-
for file in .agent/profile.json .agent/state.json .agent/
|
|
254
|
+
for file in .agent/profile.json .agent/state.json .agent/plan.json .agent/active-slice.json .agent/verification-evidence.json; do
|
|
246
255
|
[[ -f "$file" ]] || { echo "missing canonical bootstrap file: $file" >&2; exit 1; }
|
|
247
256
|
done
|
|
248
257
|
|
|
249
258
|
bash .agent/verify_completion_control_plane.sh >/dev/null
|
|
250
|
-
bash .agent/verify_completion_stop.sh >/dev/null
|
|
259
|
+
PI_COMPLETION_RUNNING_RELEASE_CHECK=1 bash .agent/verify_completion_stop.sh >/dev/null
|
|
251
260
|
|
|
252
261
|
python3 - <<'PY'
|
|
253
262
|
import json
|
|
@@ -288,39 +297,14 @@ acceptance = [
|
|
|
288
297
|
'Canonical verification evidence is recorded for the selected slice.',
|
|
289
298
|
'Fail-closed verification rejects missing or stale evidence.',
|
|
290
299
|
]
|
|
291
|
-
startup_plan = {
|
|
292
|
-
'schema_version': 1,
|
|
293
|
-
'artifact_type': 'completion-startup-plan',
|
|
294
|
-
'status': 'approved',
|
|
295
|
-
'source': 'primary_agent_handoff',
|
|
296
|
-
'captured_at': '2026-05-03T00:00:00Z',
|
|
297
|
-
'mission_anchor': mission,
|
|
298
|
-
'goal_text': 'Mission: Exercise canonical verification evidence parity.\n\nScope:\n- Persist canonical verification evidence for the selected slice.\n- Keep the verifier fail-closed on stale or missing evidence.\n\nAcceptance:\n- Canonical verification evidence is recorded for the selected slice.\n- Fail-closed verification rejects missing or stale evidence.',
|
|
299
|
-
'task_type': task_type,
|
|
300
|
-
'evaluation_profile': evaluation_profile,
|
|
301
|
-
'scope': [
|
|
302
|
-
'Persist canonical verification evidence for the selected slice.',
|
|
303
|
-
'Keep the verifier fail-closed on stale or missing evidence.',
|
|
304
|
-
],
|
|
305
|
-
'constraints': [
|
|
306
|
-
'Keep the fixture scoped to canonical verification evidence parity.',
|
|
307
|
-
],
|
|
308
|
-
'acceptance': acceptance,
|
|
309
|
-
'risks': [
|
|
310
|
-
'Stale startup-plan parity could mask canonical evidence regressions.',
|
|
311
|
-
],
|
|
312
|
-
'notes': [
|
|
313
|
-
'Use startup-plan parity to prove the verifier reads the approved startup plan alongside other canonical state.',
|
|
314
|
-
],
|
|
315
|
-
'planned_surfaces': implementation_surfaces,
|
|
316
|
-
'verification_intent': verification_commands,
|
|
317
|
-
'sequencing_hints': [
|
|
318
|
-
'First slice goal: Persist canonical verification evidence for the selected slice.',
|
|
319
|
-
],
|
|
320
|
-
}
|
|
321
300
|
state = {
|
|
322
301
|
'schema_version': 1,
|
|
323
302
|
'mission_anchor': mission,
|
|
303
|
+
'workflow_entry_status': 'active',
|
|
304
|
+
'workflow_entry_source': '/cook',
|
|
305
|
+
'workflow_entry_confirmed_at': '2026-05-03T00:00:00Z',
|
|
306
|
+
'workflow_session_id': 'evidence-fixture-session',
|
|
307
|
+
'startup_brief_path': '.agent/startup-brief.json',
|
|
324
308
|
'current_phase': 'implement',
|
|
325
309
|
'continuation_policy': 'continue',
|
|
326
310
|
'continuation_reason': 'Fixture for canonical evidence artifact regression coverage.',
|
|
@@ -394,22 +378,25 @@ active = {
|
|
|
394
378
|
'why_now': 'Exercise fail-closed evidence parity.',
|
|
395
379
|
}
|
|
396
380
|
|
|
381
|
+
startup_brief = {
|
|
382
|
+
'schema_version': 1,
|
|
383
|
+
'artifact_type': 'completion-startup-brief',
|
|
384
|
+
'source': 'primary_agent',
|
|
385
|
+
'confirmed': True,
|
|
386
|
+
'confirmed_at': '2026-05-03T00:00:00Z',
|
|
387
|
+
'mission': mission,
|
|
388
|
+
'goal_text': f'Mission: {mission}',
|
|
389
|
+
'scope': ['Exercise canonical verification evidence artifact parity.'],
|
|
390
|
+
'constraints': ['Keep the fixture scoped to verification evidence coverage.'],
|
|
391
|
+
'acceptance': acceptance,
|
|
392
|
+
'risks': ['Fixture drift can hide evidence-parity regressions.'],
|
|
393
|
+
'notes': ['Fixture startup brief for canonical evidence artifact regression coverage.'],
|
|
394
|
+
'task_type': task_type,
|
|
395
|
+
'evaluation_profile': evaluation_profile,
|
|
396
|
+
}
|
|
397
|
+
|
|
397
398
|
Path('.agent/state.json').write_text(json.dumps(state, indent=2) + '\n')
|
|
398
|
-
Path('.agent/startup-
|
|
399
|
-
Path('.agent/startup-plan.md').write_text(
|
|
400
|
-
'# Approved Startup Plan\n\n'
|
|
401
|
-
f'Mission anchor: {mission}\n'
|
|
402
|
-
'Source: primary_agent_handoff\n'
|
|
403
|
-
'Captured at: 2026-05-03T00:00:00Z\n'
|
|
404
|
-
f'Task type: {task_type}\n'
|
|
405
|
-
f'Evaluation profile: {evaluation_profile}\n\n'
|
|
406
|
-
'## Goal\n\n'
|
|
407
|
-
f"{startup_plan['goal_text']}\n\n"
|
|
408
|
-
'## Planned surfaces\n\n'
|
|
409
|
-
+ ''.join(f'- {item}\n' for item in startup_plan['planned_surfaces'])
|
|
410
|
-
+ '\n## Verification intent\n\n'
|
|
411
|
-
+ ''.join(f'- {item}\n' for item in startup_plan['verification_intent'])
|
|
412
|
-
)
|
|
399
|
+
Path('.agent/startup-brief.json').write_text(json.dumps(startup_brief, indent=2) + '\n')
|
|
413
400
|
Path('.agent/plan.json').write_text(json.dumps(plan, indent=2) + '\n')
|
|
414
401
|
Path('.agent/active-slice.json').write_text(json.dumps(active, indent=2) + '\n')
|
|
415
402
|
PY
|
|
@@ -511,7 +498,7 @@ Path('.agent/verification-evidence.json').write_text(json.dumps(valid, indent=2)
|
|
|
511
498
|
PY
|
|
512
499
|
|
|
513
500
|
bash .agent/verify_completion_control_plane.sh >/dev/null
|
|
514
|
-
bash .agent/verify_completion_stop.sh >/dev/null
|
|
501
|
+
PI_COMPLETION_RUNNING_RELEASE_CHECK=1 bash .agent/verify_completion_stop.sh >/dev/null
|
|
515
502
|
|
|
516
503
|
rm -f "$SYSTEM_REMINDER"
|
|
517
504
|
PI_COMPLETION_TEST_SYSTEM_REMINDER_PATH="$SYSTEM_REMINDER" \
|