@linimin/pi-letscook 0.1.68 → 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 +9 -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 +69 -136
- package/extensions/completion/index.ts +94 -81
- package/extensions/completion/policy-guards.ts +1 -1
- package/extensions/completion/prompt-surfaces.ts +17 -158
- package/extensions/completion/proposal.ts +26 -61
- package/extensions/completion/role-runner.ts +10 -15
- 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 +21 -0
- package/scripts/canonical-evidence-artifact-test.sh +57 -65
- package/scripts/context-proposal-test.sh +1430 -310
- package/scripts/refocus-test.sh +459 -185
- package/scripts/release-check.sh +14 -15
- package/scripts/role-runner-contract-test.sh +2 -2
- package/scripts/smoke-test.sh +36 -78
- package/skills/completion-protocol/SKILL.md +8 -9
- package/skills/completion-protocol/references/completion.md +2 -37
- package/skills/cook-handoff-boundary/SKILL.md +19 -18
|
@@ -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,
|
|
@@ -242,6 +242,11 @@ acceptance = [
|
|
|
242
242
|
state = {
|
|
243
243
|
'schema_version': 1,
|
|
244
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',
|
|
245
250
|
'current_phase': 'implement',
|
|
246
251
|
'continuation_policy': 'continue',
|
|
247
252
|
'continuation_reason': 'Fixture for active-slice contract regression coverage.',
|
|
@@ -316,6 +321,22 @@ active = {
|
|
|
316
321
|
}
|
|
317
322
|
|
|
318
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')
|
|
319
340
|
Path('.agent/plan.json').write_text(json.dumps(plan, indent=2) + '\n')
|
|
320
341
|
Path('.agent/active-slice.json').write_text(json.dumps(active, indent=2) + '\n')
|
|
321
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
|
|
@@ -182,26 +191,27 @@ bash .agent/verify_completion_control_plane.sh >/dev/null
|
|
|
182
191
|
ROOT="$TMPDIR/repo"
|
|
183
192
|
SYSTEM_REMINDER="$TMPDIR/system-reminder.txt"
|
|
184
193
|
BOOTSTRAP_SESSION="$TMPDIR/session-canonical-evidence-bootstrap.jsonl"
|
|
185
|
-
|
|
186
|
-
GENERATED_HANDOFF="$(python3 - <<'PY'
|
|
194
|
+
BOOTSTRAP_MESSAGES="$(python3 - <<'PY'
|
|
187
195
|
import json
|
|
188
196
|
capsule = {
|
|
189
197
|
"kind": "cook_handoff",
|
|
190
198
|
"source": "primary_agent",
|
|
199
|
+
"captured_at": "2026-01-01T00:00:02.000Z",
|
|
200
|
+
"source_turn_id": "m0002",
|
|
191
201
|
"mission": "Exercise canonical evidence fixture bootstrap.",
|
|
192
202
|
"scope": [
|
|
193
203
|
"Materialize canonical completion files for the evidence artifact fixture.",
|
|
194
|
-
"Keep the verification-evidence bootstrap on the supported
|
|
204
|
+
"Keep the verification-evidence bootstrap on the supported explicit-handoff startup path."
|
|
195
205
|
],
|
|
196
206
|
"constraints": [
|
|
197
207
|
"Use supported bare /cook startup only."
|
|
198
208
|
],
|
|
199
209
|
"acceptance": [
|
|
200
|
-
"
|
|
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.",
|
|
201
211
|
"Keep scripts/canonical-evidence-artifact-test.sh aligned with packaged bootstrap behavior."
|
|
202
212
|
],
|
|
203
213
|
"risks": [
|
|
204
|
-
"Evidence-artifact bootstrap must stay anchored to
|
|
214
|
+
"Evidence-artifact bootstrap must stay anchored to the fresh explicit handoff."
|
|
205
215
|
],
|
|
206
216
|
"notes": [
|
|
207
217
|
"This fixture exists only to scaffold canonical files before rewriting them for evidence parity coverage."
|
|
@@ -223,26 +233,30 @@ capsule = {
|
|
|
223
233
|
"evaluation_profile": "completion-rubric-v1",
|
|
224
234
|
"why_cook_now": "The fixture bootstrap is concrete enough to create canonical control-plane files."
|
|
225
235
|
}
|
|
226
|
-
|
|
236
|
+
messages = [
|
|
237
|
+
{"role": "user", "content": "Prepare the canonical evidence bootstrap fixture and tell me when it is ready for /cook."},
|
|
238
|
+
{"role": "assistant", "content": "The canonical evidence 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```"},
|
|
239
|
+
]
|
|
240
|
+
print(json.dumps(messages, ensure_ascii=False))
|
|
227
241
|
PY
|
|
228
242
|
)"
|
|
229
243
|
mkdir -p "$ROOT"
|
|
230
244
|
cd "$ROOT"
|
|
231
245
|
git init -q
|
|
232
|
-
|
|
246
|
+
write_session_messages "$BOOTSTRAP_SESSION" "$ROOT" "$BOOTSTRAP_MESSAGES"
|
|
233
247
|
|
|
234
248
|
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
235
|
-
|
|
249
|
+
PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
|
|
236
250
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
237
251
|
pi --session "$BOOTSTRAP_SESSION" -e "$PKG_ROOT" -p "/cook" \
|
|
238
252
|
>"$TMPDIR/pi-canonical-evidence-bootstrap.out" 2>"$TMPDIR/pi-canonical-evidence-bootstrap.err"
|
|
239
253
|
|
|
240
|
-
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
|
|
241
255
|
[[ -f "$file" ]] || { echo "missing canonical bootstrap file: $file" >&2; exit 1; }
|
|
242
256
|
done
|
|
243
257
|
|
|
244
258
|
bash .agent/verify_completion_control_plane.sh >/dev/null
|
|
245
|
-
bash .agent/verify_completion_stop.sh >/dev/null
|
|
259
|
+
PI_COMPLETION_RUNNING_RELEASE_CHECK=1 bash .agent/verify_completion_stop.sh >/dev/null
|
|
246
260
|
|
|
247
261
|
python3 - <<'PY'
|
|
248
262
|
import json
|
|
@@ -283,39 +297,14 @@ acceptance = [
|
|
|
283
297
|
'Canonical verification evidence is recorded for the selected slice.',
|
|
284
298
|
'Fail-closed verification rejects missing or stale evidence.',
|
|
285
299
|
]
|
|
286
|
-
startup_plan = {
|
|
287
|
-
'schema_version': 1,
|
|
288
|
-
'artifact_type': 'completion-startup-plan',
|
|
289
|
-
'status': 'approved',
|
|
290
|
-
'source': 'deferred_primary_agent_handoff',
|
|
291
|
-
'captured_at': '2026-05-03T00:00:00Z',
|
|
292
|
-
'mission_anchor': mission,
|
|
293
|
-
'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.',
|
|
294
|
-
'task_type': task_type,
|
|
295
|
-
'evaluation_profile': evaluation_profile,
|
|
296
|
-
'scope': [
|
|
297
|
-
'Persist canonical verification evidence for the selected slice.',
|
|
298
|
-
'Keep the verifier fail-closed on stale or missing evidence.',
|
|
299
|
-
],
|
|
300
|
-
'constraints': [
|
|
301
|
-
'Keep the fixture scoped to canonical verification evidence parity.',
|
|
302
|
-
],
|
|
303
|
-
'acceptance': acceptance,
|
|
304
|
-
'risks': [
|
|
305
|
-
'Stale startup-plan parity could mask canonical evidence regressions.',
|
|
306
|
-
],
|
|
307
|
-
'notes': [
|
|
308
|
-
'Use startup-plan parity to prove the verifier reads the approved startup plan alongside other canonical state.',
|
|
309
|
-
],
|
|
310
|
-
'planned_surfaces': implementation_surfaces,
|
|
311
|
-
'verification_intent': verification_commands,
|
|
312
|
-
'sequencing_hints': [
|
|
313
|
-
'First slice goal: Persist canonical verification evidence for the selected slice.',
|
|
314
|
-
],
|
|
315
|
-
}
|
|
316
300
|
state = {
|
|
317
301
|
'schema_version': 1,
|
|
318
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',
|
|
319
308
|
'current_phase': 'implement',
|
|
320
309
|
'continuation_policy': 'continue',
|
|
321
310
|
'continuation_reason': 'Fixture for canonical evidence artifact regression coverage.',
|
|
@@ -389,22 +378,25 @@ active = {
|
|
|
389
378
|
'why_now': 'Exercise fail-closed evidence parity.',
|
|
390
379
|
}
|
|
391
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
|
+
|
|
392
398
|
Path('.agent/state.json').write_text(json.dumps(state, indent=2) + '\n')
|
|
393
|
-
Path('.agent/startup-
|
|
394
|
-
Path('.agent/startup-plan.md').write_text(
|
|
395
|
-
'# Approved Startup Plan\n\n'
|
|
396
|
-
f'Mission anchor: {mission}\n'
|
|
397
|
-
'Source: deferred_primary_agent_handoff\n'
|
|
398
|
-
'Captured at: 2026-05-03T00:00:00Z\n'
|
|
399
|
-
f'Task type: {task_type}\n'
|
|
400
|
-
f'Evaluation profile: {evaluation_profile}\n\n'
|
|
401
|
-
'## Goal\n\n'
|
|
402
|
-
f"{startup_plan['goal_text']}\n\n"
|
|
403
|
-
'## Planned surfaces\n\n'
|
|
404
|
-
+ ''.join(f'- {item}\n' for item in startup_plan['planned_surfaces'])
|
|
405
|
-
+ '\n## Verification intent\n\n'
|
|
406
|
-
+ ''.join(f'- {item}\n' for item in startup_plan['verification_intent'])
|
|
407
|
-
)
|
|
399
|
+
Path('.agent/startup-brief.json').write_text(json.dumps(startup_brief, indent=2) + '\n')
|
|
408
400
|
Path('.agent/plan.json').write_text(json.dumps(plan, indent=2) + '\n')
|
|
409
401
|
Path('.agent/active-slice.json').write_text(json.dumps(active, indent=2) + '\n')
|
|
410
402
|
PY
|
|
@@ -506,7 +498,7 @@ Path('.agent/verification-evidence.json').write_text(json.dumps(valid, indent=2)
|
|
|
506
498
|
PY
|
|
507
499
|
|
|
508
500
|
bash .agent/verify_completion_control_plane.sh >/dev/null
|
|
509
|
-
bash .agent/verify_completion_stop.sh >/dev/null
|
|
501
|
+
PI_COMPLETION_RUNNING_RELEASE_CHECK=1 bash .agent/verify_completion_stop.sh >/dev/null
|
|
510
502
|
|
|
511
503
|
rm -f "$SYSTEM_REMINDER"
|
|
512
504
|
PI_COMPLETION_TEST_SYSTEM_REMINDER_PATH="$SYSTEM_REMINDER" \
|