@linimin/pi-letscook 0.1.59 → 0.1.60

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/mission.md CHANGED
@@ -3,6 +3,6 @@
3
3
  Project: pi-letscook
4
4
 
5
5
  Mission anchor:
6
- Implement the primary-agent /cook handoff pipeline refactor so /cook only starts implementation workflow from structurally startable handoffs, while preserving explicit handoff as the preferred startup-intake path.
6
+ Refactor the /cook startup boundary into the agreed mixed model: ordinary chat stays advisory-first by default with no default pre-/cook handoff capsule formation, while explicit /cook performs structured startup synthesis from recent discussion and preserves the approval-only Start/Cancel gate.
7
7
 
8
8
  This file is a tracked human-readable statement of the repo's completion mission. Re-grounders may refine this file when repo truth becomes clearer, but it must stay truthful to shipped behavior and the active completion objective.
package/CHANGELOG.md CHANGED
@@ -2,15 +2,17 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ## 0.1.60
6
+
5
7
  ## 0.1.59
6
8
 
7
9
  ### Changed
8
10
 
9
11
  - relaxed the pre-`/cook` ordinary-chat boundary so the primary agent can keep discussing and refining requirements before explicit `/cook` instead of switching into a hard handoff-only refusal mode as soon as workflow-worthiness is detected
10
- - kept `/cook` as the only explicit workflow boundary, while teaching the pre-`/cook` prompt surfaces to recommend `/cook` advisory-first and only emit implementation-ready capsules once the first bounded slice is concrete enough
11
- - made fresh explicit `/cook` handoffs reusable from recent ordinary-chat discussion instead of requiring the immediately preceding turn, so Cancel can return users cleanly to ordinary discussion before they rerun `/cook`
12
- - kept bare `/cook` startup and done-workflow next-round entry fail-closed on missing or non-startable explicit handoffs, while active workflows still resume from canonical `.agent/**` state unless a fresh explicit handoff proposes replacement
13
- - updated public parity and shipped package contents so the tracked `.agent` contract files are included in package tarballs and packaged smoke/release verification can scaffold canonical state truthfully
12
+ - kept `/cook` as the only explicit workflow boundary, while moving default startup and done-workflow next-round synthesis to bare `/cook` from recent ordinary-chat discussion behind the existing **Start** / **Cancel** approval gate
13
+ - kept pre-`/cook` previews or `cook_handoff` capsules opt-in only, non-canonical, and advisory until the user explicitly runs `/cook`; bare `/cook` no longer depends on a default prebuilt capsule for new-workflow startup
14
+ - kept active workflows resuming from canonical `.agent/**` state unless a fresh explicit handoff proposes a replacement, so discussion-only context does not silently rewrite an in-progress workflow
15
+ - updated public parity and packaged release verification so README/help/changelog/release-check all describe and gate the shipped mixed model truthfully, while still packaging the tracked `.agent` contract files
14
16
 
15
17
  ## 0.1.58
16
18
 
package/README.md CHANGED
@@ -43,22 +43,22 @@ Then run `/reload` in Pi.
43
43
 
44
44
  | If you want to... | Do this |
45
45
  |---|---|
46
- | Start a long-running task | Discuss the concrete repo change in the main chat, wait for a fresh primary-agent handoff, then run `/cook` |
46
+ | Start a long-running task | Discuss the concrete repo change in the main chat, then run `/cook` once the recent discussion is specific enough for a startup brief. If you explicitly want a pre-`/cook` preview or capsule first, ask for one. |
47
47
  | Continue the current workflow | Run `/cook` |
48
- | Refocus or start the next round | Discuss the new concrete repo change in the main chat, wait for a fresh primary-agent handoff, then run `/cook` |
48
+ | Refocus or start the next round | Discuss the new concrete repo change in the main chat, then run `/cook` to synthesize the next startup brief. Active-workflow replacement still stays explicit and confirm-first. |
49
49
 
50
50
  ## What `/cook` expects
51
51
 
52
- - a fresh valid explicit primary-agent `/cook` handoff capsule from recent ordinary-chat discussion whenever `/cook` is starting a new workflow or the next round after a completed workflow
53
- - for that handoff capsule to start workflow immediately, it must already be implementation-startable: a bounded `first_slice_goal`, repo-change-oriented acceptance, `implementation_surfaces`, `verification_commands`, and `why_this_slice_first`
54
- - enough detail in the main chat for the primary agent to form that bounded handoff capsule before you run `/cook`
52
+ - recent ordinary-chat discussion concrete enough for bare `/cook` to synthesize a startup brief for a new workflow or the next round after a completed workflow
53
+ - enough repo-change detail for that startup brief to stay implementation-oriented once you review it behind **Start** or **Cancel**
55
54
  - README/CHANGELOG updates still count as concrete repo changes
56
- - assistant-produced summaries and plan/spec/design-doc/proposal-only artifacts still do not count unless they include the explicit structured `/cook` handoff capsule
57
- - recent main-chat discussion can still validate or supplement an accepted explicit handoff, but it no longer starts a new workflow by itself
55
+ - assistant-produced summaries and plan/spec/design-doc/proposal-only artifacts still do not become canonical workflow state by themselves
56
+ - any pre-`/cook` preview or `cook_handoff` capsule only when you explicitly ask for it; that preview stays advisory startup intake, not canonical `.agent/**` state
57
+ - active-workflow replacement still stays conservative: `/cook` resumes from canonical state unless a fresh explicit handoff proposes a different concrete repo change and you confirm that replacement
58
58
 
59
- If no fresh valid handoff exists for new-workflow or next-round entry, `/cook` fails closed, leaves canonical `.agent/**` state unchanged, and tells you to get an explicit primary-agent handoff in the main chat before rerunning `/cook`.
59
+ If recent discussion is too weak, ambiguous, stale, or planning-only for new-workflow or next-round entry, `/cook` fails closed, leaves canonical `.agent/**` state unchanged, and tells you to clarify the concrete repo change in the main chat before rerunning `/cook`.
60
60
 
61
- If a fresh explicit handoff exists but is still workflow-worthy rather than implementation-startable, `/cook` also fails closed instead of silently treating that capsule as planning support or canonical workflow state.
61
+ If you explicitly asked for a preview capsule and it is still workflow-worthy rather than implementation-startable, `/cook` also fails closed instead of silently treating that preview as planning support or canonical workflow state.
62
62
 
63
63
  If you pass inline arguments to `/cook`, it also fails closed and tells you to move that intent into the main chat before rerunning bare `/cook`.
64
64
 
@@ -70,36 +70,37 @@ If a task has clearly matured into completion-workflow scope, the primary agent
70
70
 
71
71
  Before you explicitly run `/cook`, the conversation can still stay in ordinary chat: the primary agent may keep answering follow-up questions and refining requirements rather than switching into a hard handoff-only refusal mode.
72
72
 
73
- That handoff should include an explicit structured `/cook` capsule in the assistant reply once the first slice is implementation-ready, so `/cook` can confirm the already-formed mission instead of re-deriving it from broad ambient context.
73
+ If you explicitly ask for a pre-`/cook` preview or capsule, the primary agent may provide one, but that preview is opt-in only and stays non-canonical until you later run `/cook` and choose **Start**.
74
74
 
75
- The capsule is still advisory startup intake, not canonical workflow state, and new-workflow or next-round entry only proceeds when it already names the first bounded slice, repo-change-oriented acceptance, implementation surfaces, and verification commands.
75
+ Bare `/cook` is still the canonical workflow boundary: it synthesizes the startup brief from recent ordinary-chat discussion at `/cook` time, then waits for **Start** or **Cancel** before any canonical `.agent/**` write.
76
76
 
77
77
  Important behavior:
78
78
  - `/cook` is the canonical workflow boundary and manual entry point
79
- - startup and next-round entry stay confirm-first and require a fresh valid explicit primary-agent handoff
79
+ - startup and next-round entry stay confirm-first: bare `/cook` synthesizes the startup brief from recent discussion, then waits for **Start** or **Cancel**
80
80
  - active workflows resume from canonical `.agent/**` state unless a fresh valid explicit handoff proposes a replacement
81
+ - any pre-`/cook` preview or capsule is explicit-request-only and non-canonical
81
82
  - explicit slash commands other than `/cook` continue normally in the main chat
82
83
  - ordinary main-chat discussion may clarify or propose, but mature long-running implementation should be handed off to `/cook`
83
84
 
84
85
  ## Typical examples
85
86
 
86
- Start a new workflow after a fresh primary-agent handoff:
87
+ Start a new workflow from recent discussion:
87
88
 
88
89
  ```text
89
90
  I want to add login redirect handling and tests.
90
- # let the primary agent hand you off to /cook
91
+ # discuss scope until the startup brief is clear enough
91
92
  /cook
92
93
  ```
93
94
 
94
95
  ## What happens when you run `/cook`
95
96
 
96
- `/cook` first looks for a fresh explicit primary-agent handoff capsule from recent ordinary-chat discussion. New-workflow entry and done-workflow next-round entry start only when that capsule is fresh, valid, and implementation-startable; otherwise `/cook` fails closed instead of deriving startup from recent discussion. When a workflow is already active and no fresh valid explicit handoff is present, `/cook` resumes from canonical `.agent/**` state instead of deriving replacement startup from recent discussion.
97
+ When no workflow is active, bare `/cook` synthesizes a startup brief from recent ordinary-chat discussion and then waits for **Start** or **Cancel**. If recent discussion is too weak, ambiguous, stale, or planning-only, `/cook` fails closed instead of guessing. If you explicitly asked for a preview capsule first and that preview is fresh but still non-startable, `/cook` also fails closed instead of silently treating it as canonical state. When a workflow is already active and no fresh valid explicit replacement handoff is present, `/cook` resumes from canonical `.agent/**` state instead of deriving replacement startup from recent discussion.
97
98
 
98
99
  | Repo state | What you'll see |
99
100
  |---|---|
100
- | No workflow yet | If a fresh explicit handoff capsule exists and is implementation-startable, you get a startup brief built from that handoff and choose **Start** or **Cancel**. Otherwise `/cook` fails closed, leaves canonical state unchanged, and tells you to get a fresh explicit primary-agent handoff. Weak, unreliable, stale, planning-only, or non-startable explicit-handoff intake also fails closed. |
101
+ | No workflow yet | `/cook` synthesizes a startup brief from recent discussion and shows **Start** / **Cancel**. If recent discussion is too weak, ambiguous, stale, or planning-only, `/cook` fails closed and leaves canonical state unchanged. An explicit-request preview capsule can inform that startup brief, but it is still non-canonical until you choose **Start**. |
101
102
  | Active workflow exists | Usually a resume of the current workflow from canonical `.agent/**` state. If a fresh explicit handoff capsule points to a different concrete repo change, `/cook` shows a chooser first and only rewrites canonical state after you confirm the replacement. Ambiguous intake stays conservative. |
102
- | Previous workflow is `done` | A fresh explicit handoff capsule can still start the next implementation round behind **Start** or **Cancel**. Without one, `/cook` fails closed instead of deriving the next round from recent discussion. |
103
+ | Previous workflow is `done` | `/cook` synthesizes the next implementation round from recent discussion behind **Start** / **Cancel**. If that recent discussion is too weak or ambiguous, `/cook` fails closed and leaves the finished workflow state unchanged. |
103
104
 
104
105
  ## Confirmation and fail-closed behavior
105
106
 
@@ -109,6 +110,7 @@ I want to add login redirect handling and tests.
109
110
  - actions are **Start** and **Cancel**
110
111
  - **Cancel** is side-effect free: canonical workflow state stays unchanged, so you can discuss changes in the main chat and rerun `/cook`
111
112
  - weak, ambiguous, stale, invalid, assistant-produced, or planning-only intake does not start a workflow
113
+ - any pre-`/cook` preview or capsule is advisory only and never writes canonical workflow state by itself
112
114
  - when a fresh explicit handoff suggests replacing an active workflow, `/cook` shows a chooser before any canonical state rewrite
113
115
 
114
116
  When you accept startup or refocus, `/cook` persists the chosen workflow state in canonical `.agent/**` files before the re-ground round begins.
@@ -262,7 +264,7 @@ npm run rubric-contract-test
262
264
  npm run release-check
263
265
  ```
264
266
 
265
- `npm run release-check` is the broad packaged-release verifier. It begins with `bash .agent/verify_completion_control_plane.sh`, so missing or stale `.agent/verification-evidence.json` parity fails closed before the broader suite runs, then asserts the shipped `/cook` public parity surfaces in `README.md`, `CHANGELOG.md`, and the `/cook` help/fail-closed copy in `extensions/completion/index.ts`, reruns the startup/refocus/context checks — including the critique-aware `/cook` confirmation regression and the smoke auto-resume prompt path — includes deterministic canonical evidence artifact coverage and includes deterministic active-slice contract coverage plus observability coverage, evaluator calibration, and the rubric-contract regression, and finishes with `npm pack --dry-run`.
267
+ `npm run release-check` is the broad packaged-release verifier. It begins with `bash .agent/verify_completion_control_plane.sh`, so missing or stale `.agent/verification-evidence.json` parity fails closed before the broader suite runs, then asserts the shipped mixed-model `/cook` public parity surfaces in `README.md`, `CHANGELOG.md`, and the `/cook` help/fail-closed copy in `extensions/completion/index.ts`, reruns the startup/refocus/context checks — including the critique-aware `/cook` confirmation regression and the smoke auto-resume prompt path — includes deterministic canonical evidence artifact coverage and includes deterministic active-slice contract coverage plus observability coverage, evaluator calibration, and the rubric-contract regression, and finishes with `npm pack --dry-run`.
266
268
 
267
269
  The direct package-root verifier commands above intentionally self-isolate the repo-local extension when they shell back into `pi`, so you should not need to wrap them with `pi --no-extensions` even if `@linimin/pi-letscook` is also installed globally on the same machine.
268
270
 
@@ -60,9 +60,9 @@ type CookContextProposalResult = {
60
60
  blockedFailureMessage?: string;
61
61
  };
62
62
 
63
- function buildCookExplicitHandoffRequiredMessage(deps: CompletionDriverDeps, prefix?: string): string {
63
+ function buildCookStartupBriefRequiredMessage(deps: CompletionDriverDeps, prefix?: string): string {
64
64
  const requirement =
65
- "/cook failed closed because starting a new completion workflow now requires a fresh valid explicit primary-agent handoff. Ask the primary agent to emit a fresh ```cook_handoff``` capsule in the main chat, then rerun /cook.";
65
+ "/cook failed closed because recent discussion did not produce a clear execution-ready startup brief with Mission/Scope/Constraints/Acceptance for concrete repo changes. Clarify the concrete repo changes in the main chat and rerun /cook.";
66
66
  return prefix ? `${prefix} ${requirement}` : requirement;
67
67
  }
68
68
 
@@ -536,14 +536,14 @@ export async function runCookEntry(
536
536
  if (!snapshot) {
537
537
  const root = findRepoRoot(cwd) ?? cwd;
538
538
  const projectName = path.basename(root);
539
- const derived = await deps.deriveCookStartupProposal(ctx, projectName);
539
+ const derived = await deps.deriveCookContextProposal(ctx, projectName);
540
540
  if (derived.blockedFailureMessage) {
541
541
  deps.emitCommandText(ctx, derived.blockedFailureMessage, "info");
542
542
  return;
543
543
  }
544
544
  const proposal = derived.proposal;
545
545
  if (!proposal) {
546
- deps.emitCommandText(ctx, buildCookExplicitHandoffRequiredMessage(deps), "info");
546
+ deps.emitCommandText(ctx, buildCookStartupBriefRequiredMessage(deps), "info");
547
547
  return;
548
548
  }
549
549
  const decision = await deps.confirmContextProposal(ctx, proposal, {
@@ -581,14 +581,14 @@ export async function runCookEntry(
581
581
  if (!goal) {
582
582
  if (workflowDone) {
583
583
  const projectName = path.basename(snapshot.files.root);
584
- const derived = await deps.deriveCookStartupProposal(ctx, projectName);
584
+ const derived = await deps.deriveCookContextProposal(ctx, projectName);
585
585
  if (derived.blockedFailureMessage) {
586
586
  deps.emitCommandText(ctx, derived.blockedFailureMessage, "info");
587
587
  return;
588
588
  }
589
589
  const proposal = derived.proposal;
590
590
  if (!proposal) {
591
- deps.emitCommandText(ctx, buildCookExplicitHandoffRequiredMessage(deps, "The previous completion workflow is already done."), "info");
591
+ deps.emitCommandText(ctx, buildCookStartupBriefRequiredMessage(deps, "The previous completion workflow is already done."), "info");
592
592
  return;
593
593
  }
594
594
  const decision = await deps.confirmContextProposal(ctx, proposal, {
@@ -610,7 +610,13 @@ export async function runCookEntry(
610
610
  buildAdvisoryStartupBrief({ proposal, analysis: decision.analysis }),
611
611
  );
612
612
  snapshot = (await loadCompletionSnapshot(snapshot.files.root)) ?? snapshot;
613
- deps.emitCommandText(ctx, `Started a new completion workflow round from explicit primary-agent handoff: ${decision.missionAnchor}`, "info");
613
+ deps.emitCommandText(
614
+ ctx,
615
+ proposal.source === "handoff_capsule"
616
+ ? `Started a new completion workflow round from explicit primary-agent handoff: ${decision.missionAnchor}`
617
+ : `Started a new completion workflow round from recent discussion: ${decision.missionAnchor}`,
618
+ "info",
619
+ );
614
620
  } else {
615
621
  const assessment = await assessActiveWorkflowProposalRouting(ctx, snapshot, deps);
616
622
  if (assessment.action === "blocked") {
@@ -209,7 +209,7 @@ function maybeWriteTestSnapshot(targetPath: string | undefined, content: string)
209
209
 
210
210
  const COOK_MAIN_CHAT_RERUN_GUIDANCE = "Discuss changes in the main chat and rerun /cook.";
211
211
  const COOK_STRUCTURED_DISCUSSION_FAILURE_DETAIL =
212
- "/cook failed closed because new-workflow startup now requires a fresh valid explicit primary-agent handoff from recent ordinary-chat discussion; recent discussion alone no longer starts a workflow. Ask the primary agent to hand off explicitly in the main chat, then rerun /cook.";
212
+ "/cook failed closed because recent discussion did not produce a clear execution-ready startup brief for bare /cook with Mission/Scope/Constraints/Acceptance for concrete repo changes. Clarify the concrete repo changes in the main chat and rerun /cook; canonical workflow state is still only written after Start.";
213
213
 
214
214
  function isWorkflowDone(snapshot: CompletionStateSnapshot | undefined): boolean {
215
215
  return asString(snapshot?.state?.continuation_policy) === "done";
@@ -929,7 +929,7 @@ export default function completionExtension(pi: ExtensionAPI) {
929
929
  structuredDiscussionFailureDetail: COOK_STRUCTURED_DISCUSSION_FAILURE_DETAIL,
930
930
  mainChatRerunGuidance: COOK_MAIN_CHAT_RERUN_GUIDANCE,
931
931
  cookCommandSpec: {
932
- description: "/cook workflow: start a new workflow or next round only from a fresh recent explicit primary-agent handoff, resume the current workflow from canonical state, or confirm an explicit replacement from the explicit /cook command",
932
+ description: "/cook workflow: synthesize an approval-gated startup brief from recent discussion for new-workflow or next-round entry, resume the current workflow from canonical state, or confirm an explicit active-workflow replacement",
933
933
  },
934
934
  buildContextProposalContinuationReason,
935
935
  completionKickoff,
@@ -32,14 +32,14 @@ export function buildCookHandoffBoundaryReminder(): string {
32
32
  "When you judge that the task has matured into completion-workflow scope — for example the user has clearly shifted from exploration into implementation intent, you have just produced a concrete plan or proposal whose next step would naturally be implementation, or the task spans multiple files, steps, or verification surfaces — do not begin long-running product implementation in ordinary chat and do not edit tracked product files for that workflow-level task.",
33
33
  "Instead, recommend /cook as the workflow boundary while keeping the conversation in ordinary chat until the user explicitly runs /cook.",
34
34
  "If the user keeps asking follow-up questions or refining requirements before /cook, continue that ordinary-chat discussion normally instead of switching into a handoff-only refusal mode, but do not act as though /cook had already been invoked.",
35
- "Distinguish a workflow-worthy handoff from an implementation-ready handoff: only emit the implementation-ready capsule when the first bounded implementation slice is concrete enough to start immediately.",
36
- "If the task is workflow-worthy but that first slice is still vague, say that /cook will be the right next step once the first bounded slice is concrete enough, then keep refining in ordinary chat without emitting an implementation-ready capsule yet.",
37
- "When handing off, explain that /cook can start a new workflow or next round only from a fresh valid explicit primary-agent handoff capsule from recent ordinary-chat discussion; otherwise it fails closed, while already-active workflows resume from canonical .agent state unless a fresh valid explicit handoff proposes replacement.",
38
- "Once the task is implementation-ready, append one exact fenced block in the same assistant reply using ```cook_handoff ... ``` JSON with kind/source/handoff_kind plus mission, scope, constraints or non_goals, acceptance, risks, notes, captured_at, source_turn_id, first_slice_goal, first_slice_non_goals, implementation_surfaces, verification_commands, why_this_slice_first, and optional task_type/evaluation_profile/why_cook_now.",
39
- "Use handoff_kind implementation_workflow_handoff for that implementation-ready capsule.",
40
- "If later ordinary-chat discussion materially changes the startup brief before /cook runs, update or replace the capsule in a later assistant reply instead of pretending the workflow already started.",
41
- "The capsule is startup intake for /cook only: do not present it as canonical .agent state, an active slice, or a persistent repo contract.",
42
- "If the task is still ordinary Q&A, lightweight brainstorming, or a tiny one-off fix, continue normally without forcing /cook.",
35
+ "Distinguish a workflow-worthy handoff from an opt-in preview request: by default, do not emit a structured preview or cook_handoff capsule in ordinary chat once the task is concrete enough; recommend bare /cook instead.",
36
+ "If the task is workflow-worthy but the user still wants to refine scope before /cook, keep refining in ordinary chat without acting as though workflow already started.",
37
+ "When handing off, explain that bare /cook will synthesize a startup brief from recent ordinary-chat discussion for a new workflow or next round, while already-active workflows resume from canonical .agent state unless the user explicitly chooses a replacement path backed by a fresh valid explicit handoff.",
38
+ "If the user explicitly asks for a /cook preview or capsule before running /cook, you may append one exact fenced block in the same assistant reply using ```cook_handoff ... ``` JSON with kind/source/handoff_kind plus mission, scope, constraints or non_goals, acceptance, risks, notes, captured_at, source_turn_id, first_slice_goal, first_slice_non_goals, implementation_surfaces, verification_commands, why_this_slice_first, and optional task_type/evaluation_profile/why_cook_now.",
39
+ "Use handoff_kind implementation_workflow_handoff for that opt-in preview capsule.",
40
+ "If later ordinary-chat discussion materially changes the startup brief before /cook runs, update or replace the preview capsule in a later assistant reply instead of pretending the workflow already started.",
41
+ "Any preview capsule is startup intake for /cook only: do not present it as canonical .agent state, an active slice, or a persistent repo contract.",
42
+ "If the task is still ordinary Q&A, lightweight brainstorming, or a tiny one-off fix, continue normally without forcing /cook or emitting an unsolicited preview capsule.",
43
43
  ].join(" ");
44
44
  }
45
45
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@linimin/pi-letscook",
3
- "version": "0.1.59",
3
+ "version": "0.1.60",
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,
@@ -147,28 +147,32 @@ mkdir -p "$ROOT"
147
147
  cd "$ROOT"
148
148
  git init -q
149
149
 
150
- # No workflow yet: bare /cook should fail closed without a fresh valid explicit primary-agent handoff,
151
- # even when recent discussion is fully structured.
150
+ # No workflow yet: bare /cook should synthesize a startup brief from recent discussion,
151
+ # and Cancel should leave canonical workflow state untouched.
152
152
  SESSION_ZERO="$TMPDIR/session-zero.jsonl"
153
153
  DISCUSSION_ZERO=$'Mission: Remove the completion status line while keeping the completion widget.\nScope:\n- Keep the non-running completion widget.\n- Suppress the widget while a completion role is active.\nConstraints:\n- Do not reintroduce any other completion status surface.\nAcceptance:\n- Update README to match the shipped behavior.\n- Keep observability regression coverage truthful.'
154
154
  DISCUSSION_SNAPSHOT_ZERO="$TMPDIR/context-proposal-structured-fallback.json"
155
155
  write_session "$SESSION_ZERO" "$ROOT" "$DISCUSSION_ZERO"
156
156
 
157
- PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
157
+ PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=cancel \
158
158
  PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
159
159
  PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_ZERO" \
160
160
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
161
161
  pi --session "$SESSION_ZERO" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-structured-fallback.out" 2>"$TMPDIR/pi-completion-context-proposal-structured-fallback.err"
162
162
 
163
163
  python3 - "$TMPDIR/pi-completion-context-proposal-structured-fallback.out" "$TMPDIR/pi-completion-context-proposal-structured-fallback.err" "$DISCUSSION_SNAPSHOT_ZERO" <<'PY'
164
+ import json
164
165
  import sys
165
166
  from pathlib import Path
166
167
 
167
168
  output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
168
169
  snapshot = Path(sys.argv[3])
169
- assert not Path('.agent').exists(), 'missing explicit handoff should fail closed without writing canonical state'
170
- assert not snapshot.exists(), 'missing explicit handoff should not emit a startup proposal snapshot'
171
- assert 'fresh valid explicit primary-agent handoff' in output, 'missing explicit handoff should explain the explicit-handoff-only startup contract'
170
+ proposal = json.loads(snapshot.read_text())
171
+ assert not Path('.agent').exists(), 'recent-discussion Cancel should leave canonical state untouched before workflow bootstrap'
172
+ assert snapshot.exists(), 'recent-discussion startup synthesis should emit a proposal snapshot before the Start/Cancel gate'
173
+ assert proposal['mission'] == 'Remove the completion status line while keeping the completion widget.', 'recent-discussion startup synthesis should preserve the structured mission anchor'
174
+ assert proposal['source'] == 'session', 'recent-discussion startup synthesis should snapshot the structured-session proposal source'
175
+ assert 'Cancelled recent-discussion workflow proposal' in output, 'recent-discussion Cancel should report that canonical state was left unchanged'
172
176
  PY
173
177
 
174
178
  # No workflow yet: user-authored faux handoffs must not bootstrap canonical workflow state.
@@ -202,6 +206,7 @@ PY
202
206
  )"
203
207
  write_session_messages "$SESSION_ZERO_USER_AUTHORED" "$ROOT" "$USER_AUTHORED_MESSAGES_ZERO"
204
208
 
209
+ PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
205
210
  PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$USER_AUTHORED_SNAPSHOT_ZERO" \
206
211
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
207
212
  pi --session "$SESSION_ZERO_USER_AUTHORED" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-user-authored.out" 2>"$TMPDIR/pi-completion-context-proposal-user-authored.err"
@@ -214,7 +219,7 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
214
219
  snapshot = Path(sys.argv[3])
215
220
  assert not Path('.agent').exists(), 'user-authored faux handoff should fail closed without writing canonical state'
216
221
  assert not snapshot.exists(), 'user-authored faux handoff should not emit a startup proposal snapshot'
217
- assert 'fresh valid explicit primary-agent handoff' in output, 'user-authored faux handoff should still explain the explicit-handoff-only startup contract'
222
+ assert 'recent discussion did not produce a clear execution-ready startup brief' in output, 'user-authored faux handoff should still fail closed unless ordinary discussion is concretely startable'
218
223
  PY
219
224
 
220
225
  # No workflow yet: malformed or invalid assistant handoff capsules must also fail closed.
@@ -223,6 +228,7 @@ INVALID_SNAPSHOT_ZERO="$TMPDIR/context-proposal-invalid-handoff.json"
223
228
  INVALID_MESSAGES_ZERO='[{"role":"assistant","content":"This is not a valid startup capsule.\n\n```cook_handoff\n{\"kind\":\"cook_handoff\",\"source\":\"primary_agent\",\"mission\":\"Broken JSON handoff\"\n```"}]'
224
229
  write_session_messages "$SESSION_ZERO_INVALID" "$ROOT" "$INVALID_MESSAGES_ZERO"
225
230
 
231
+ PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
226
232
  PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$INVALID_SNAPSHOT_ZERO" \
227
233
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
228
234
  pi --session "$SESSION_ZERO_INVALID" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-invalid-handoff.out" 2>"$TMPDIR/pi-completion-context-proposal-invalid-handoff.err"
@@ -235,7 +241,7 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
235
241
  snapshot = Path(sys.argv[3])
236
242
  assert not Path('.agent').exists(), 'invalid assistant handoff should fail closed without writing canonical state'
237
243
  assert not snapshot.exists(), 'invalid assistant handoff should not emit a startup proposal snapshot'
238
- assert 'fresh valid explicit primary-agent handoff' in output, 'invalid assistant handoff should still explain the explicit-handoff-only startup contract'
244
+ assert 'recent discussion did not produce a clear execution-ready startup brief' in output, 'invalid assistant handoff should still fail closed when no clear recent-discussion startup brief exists'
239
245
  PY
240
246
 
241
247
  # No workflow yet: a fresh explicit primary-agent handoff should still bootstrap canonical startup state.
@@ -702,10 +708,9 @@ assert not snapshot.exists(), 'verification-evidence overlap suppression should
702
708
  assert '/cook failed closed' in output, 'verification-evidence overlap suppression should fail closed when the latest discussion only repeats verified work'
703
709
  PY
704
710
 
705
- # Completed workflow: bare /cook should fail closed for next-round discussion-only startup too,
706
- # even when the discussion is well structured.
711
+ # Completed workflow: bare /cook should synthesize the next-round startup brief from recent discussion.
707
712
  SESSION_TWO_NORMALIZED="$TMPDIR/session-two-normalized.jsonl"
708
- DISCUSSION_TWO_NORMALIZED=$'Mission: 開始實作這個方案\nScope:\n- Normalize bare /cook planning phrasing for the next workflow round.\n- Reset canonical state for the new implementation mission.\nConstraints:\n- Do not resume the completed workflow when the new round is clearly different.\nAcceptance:\n- Start a new round with the normalized mission anchor.'
713
+ DISCUSSION_TWO_NORMALIZED=$'Mission: Ship the next workflow round from recent discussion.\nScope:\n- Reset canonical state back to reground for the new mission.\n- Preserve the tracked completion control-plane files.\nConstraints:\n- Do not resume the completed workflow when the new round is clearly different.\nAcceptance:\n- Reset canonical state back to reground for the new mission.\n- Preserve the tracked completion control-plane files.'
709
714
  DISCUSSION_SNAPSHOT_TWO_NORMALIZED="$TMPDIR/context-proposal-next-round-normalized.json"
710
715
  write_session "$SESSION_TWO_NORMALIZED" "$ROOT" "$DISCUSSION_TWO_NORMALIZED"
711
716
 
@@ -715,20 +720,45 @@ PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_NORMALIZED" \
715
720
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
716
721
  pi --session "$SESSION_TWO_NORMALIZED" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-next-round-normalized.out" 2>"$TMPDIR/pi-completion-context-proposal-next-round-normalized.err"
717
722
 
718
- python3 - "$TMPDIR/pi-completion-context-proposal-next-round-normalized.out" "$TMPDIR/pi-completion-context-proposal-next-round-normalized.err" "$DISCUSSION_SNAPSHOT_TWO_NORMALIZED" "$CURRENT_DONE_MISSION" <<'PY'
723
+ python3 - "$DISCUSSION_SNAPSHOT_TWO_NORMALIZED" <<'PY'
719
724
  import json
720
725
  import sys
721
726
  from pathlib import Path
722
727
 
723
- output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
724
- snapshot = Path(sys.argv[3])
725
- expected = sys.argv[4]
728
+ mission = 'Ship the next workflow round from recent discussion.'
729
+ expected_task_type = 'completion-workflow'
730
+ expected_eval_profile = 'completion-rubric-v1'
731
+ mission_text = Path('.agent/mission.md').read_text()
732
+ profile = json.loads(Path('.agent/profile.json').read_text())
726
733
  state = json.loads(Path('.agent/state.json').read_text())
734
+ plan = json.loads(Path('.agent/plan.json').read_text())
735
+ active = json.loads(Path('.agent/active-slice.json').read_text())
736
+ proposal = json.loads(Path(sys.argv[1]).read_text())
727
737
 
728
- assert not snapshot.exists(), 'done-workflow discussion-only startup should not emit a proposal snapshot without a fresh explicit handoff'
729
- assert state['mission_anchor'] == expected, 'done-workflow discussion-only startup should keep the completed mission anchor unchanged'
730
- assert state['continuation_policy'] == 'done', 'done-workflow discussion-only startup should keep the workflow closed'
731
- assert 'fresh valid explicit primary-agent handoff' in output, 'done-workflow discussion-only startup should explain the explicit-handoff-only entry contract'
738
+ assert mission in mission_text, '.agent/mission.md did not update to the recent-discussion next-round mission anchor'
739
+ assert profile['task_type'] == expected_task_type, 'profile.json task_type mismatch after recent-discussion next-round startup'
740
+ assert profile['evaluation_profile'] == expected_eval_profile, 'profile.json evaluation_profile mismatch after recent-discussion next-round startup'
741
+ assert state['mission_anchor'] == mission, 'state.json mission_anchor mismatch after starting the next workflow round from recent discussion'
742
+ assert state['task_type'] == expected_task_type, 'state.json task_type mismatch after starting the next workflow round from recent discussion'
743
+ assert state['evaluation_profile'] == expected_eval_profile, 'state.json evaluation_profile mismatch after starting the next workflow round from recent discussion'
744
+ assert state['advisory_startup_brief']['mission'] == mission, 'recent-discussion next round should preserve the confirmed startup brief as advisory intake'
745
+ assert state['advisory_startup_brief']['source'] == 'recent_discussion', 'recent-discussion next round should preserve the advisory source'
746
+ assert plan['mission_anchor'] == mission, 'plan.json mission_anchor mismatch after starting the next workflow round from recent discussion'
747
+ assert plan['task_type'] == expected_task_type, 'plan.json task_type mismatch after starting the next workflow round from recent discussion'
748
+ assert plan['evaluation_profile'] == expected_eval_profile, 'plan.json evaluation_profile mismatch after starting the next workflow round from recent discussion'
749
+ assert active['mission_anchor'] == mission, 'active-slice.json mission_anchor mismatch after starting the next workflow round from recent discussion'
750
+ assert active['task_type'] == expected_task_type, 'active-slice.json task_type mismatch after starting the next workflow round from recent discussion'
751
+ assert active['evaluation_profile'] == expected_eval_profile, 'active-slice.json evaluation_profile mismatch after starting the next workflow round from recent discussion'
752
+ assert proposal['mission'] == mission, 'recent-discussion next-round proposal snapshot should preserve the synthesized mission anchor'
753
+ assert proposal['source'] == 'session', 'recent-discussion next-round proposal snapshot should record the structured-session source'
754
+ assert state['current_phase'] == 'reground', 'state.json current_phase should reset to reground for the recent-discussion next workflow round'
755
+ assert state['continuation_policy'] == 'continue', 'continuation_policy should reset to continue for the recent-discussion next workflow round'
756
+ assert state['requires_reground'] is True, 'requires_reground should reset to true for the recent-discussion next workflow round'
757
+ assert state['project_done'] is False, 'project_done should reset to false for the recent-discussion next workflow round'
758
+ assert state['next_mandatory_role'] == 'completion-regrounder', 'next_mandatory_role should reset to completion-regrounder for the recent-discussion next workflow round'
759
+ assert state['continuation_reason'].startswith('User refocused workflow via /cook:'), 'continuation_reason should record the recent-discussion next-round refocus'
760
+ assert plan['plan_basis'] == 'user_refocus', 'plan_basis should reset to user_refocus for the recent-discussion next workflow round'
761
+ assert active['status'] == 'idle', 'active-slice should reset to idle for the recent-discussion next workflow round'
732
762
  PY
733
763
 
734
764
  # Completed workflow: a fresh explicit primary-agent handoff should still start the next round.
@@ -947,8 +977,7 @@ after = {path.name: path.read_text() for path in tracked}
947
977
  assert before == after, 'done /cook inline-args rejection should leave canonical files unchanged'
948
978
  PY
949
979
 
950
- # Completed workflow again: model-assisted discussion analysis alone should still fail closed
951
- # without a fresh valid explicit primary-agent handoff.
980
+ # Completed workflow again: model-assisted discussion analysis should also synthesize the next-round startup brief.
952
981
  mark_done
953
982
 
954
983
  SESSION_FIVE="$TMPDIR/session-five.jsonl"
@@ -963,18 +992,20 @@ PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_FIVE" \
963
992
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
964
993
  pi --session "$SESSION_FIVE" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-analyst.out" 2>"$TMPDIR/pi-completion-context-proposal-analyst.err"
965
994
 
966
- python3 - "$TMPDIR/pi-completion-context-proposal-analyst.out" "$TMPDIR/pi-completion-context-proposal-analyst.err" "$DISCUSSION_SNAPSHOT_FIVE" <<'PY'
995
+ python3 - "$DISCUSSION_SNAPSHOT_FIVE" <<'PY'
967
996
  import json
968
997
  import sys
969
998
  from pathlib import Path
970
999
 
971
- output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
972
- snapshot = Path(sys.argv[3])
1000
+ mission = 'Use a proposal analyst to summarize natural discussion before /cook writes canonical state.'
973
1001
  state = json.loads(Path('.agent/state.json').read_text())
1002
+ proposal = json.loads(Path(sys.argv[1]).read_text())
974
1003
 
975
- assert not snapshot.exists(), 'done-workflow analyst-only restart should not emit a startup proposal snapshot'
976
- assert state['continuation_policy'] == 'done', 'done-workflow analyst-only restart should keep the workflow closed'
977
- assert 'fresh valid explicit primary-agent handoff' in output, 'done-workflow analyst-only restart should explain the explicit-handoff-only startup contract'
1004
+ assert proposal['mission'] == mission, 'analyst-driven restart should emit the synthesized mission in the proposal snapshot'
1005
+ assert proposal['source'] == 'analyst', 'analyst-driven restart should preserve the analyst proposal source'
1006
+ assert state['mission_anchor'] == mission, 'analyst-driven restart should promote the synthesized mission into canonical state after Start'
1007
+ assert state['continuation_policy'] == 'continue', 'analyst-driven restart should reopen the workflow after Start'
1008
+ assert state['advisory_startup_brief']['source'] == 'recent_discussion', 'analyst-driven restart should still record recent-discussion advisory intake'
978
1009
  PY
979
1010
 
980
1011
  # Custom confirmation UI: start should render proposal content separately from approval-only Start/Cancel actions.
@@ -1545,7 +1576,7 @@ assert 'First slice goal: Patch the callback edge case and cover it with a focus
1545
1576
  assert 'Verification commands: npm test -- redirect-edge.spec.ts' in state['advisory_startup_brief']['notes'], 'done-workflow handoff should preserve verification_commands in advisory notes'
1546
1577
  PY
1547
1578
 
1548
- # Stale handoff: an aged-out capsule should fail closed even if later discussion exists.
1579
+ # Stale handoff: an aged-out capsule should no longer block /cook from synthesizing a fresh startup brief from later discussion.
1549
1580
  HANDOFF_ROOT_STALE="$TMPDIR/handoff-root-stale"
1550
1581
  mkdir -p "$HANDOFF_ROOT_STALE"
1551
1582
  cd "$HANDOFF_ROOT_STALE"
@@ -1590,16 +1621,18 @@ PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$HANDOFF_SNAPSHOT_STALE" \
1590
1621
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
1591
1622
  pi --session "$HANDOFF_SESSION_STALE" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-handoff-stale.out" 2>"$TMPDIR/pi-completion-handoff-stale.err"
1592
1623
 
1593
- python3 - "$HANDOFF_SNAPSHOT_STALE" "$TMPDIR/pi-completion-handoff-stale.out" "$TMPDIR/pi-completion-handoff-stale.err" <<'PY'
1624
+ python3 - "$HANDOFF_SNAPSHOT_STALE" <<'PY'
1625
+ import json
1594
1626
  import sys
1595
1627
  from pathlib import Path
1596
1628
 
1597
- snapshot = Path(sys.argv[1])
1598
- output = Path(sys.argv[2]).read_text() + Path(sys.argv[3]).read_text()
1629
+ snapshot = json.loads(Path(sys.argv[1]).read_text())
1630
+ state = json.loads(Path('.agent/state.json').read_text())
1599
1631
 
1600
- assert not snapshot.exists(), 'aged-out handoff should not emit a startup proposal snapshot'
1601
- assert not Path('.agent').exists(), 'aged-out handoff should fail closed without writing canonical state'
1602
- assert 'fresh valid explicit primary-agent handoff' in output, 'aged-out handoff should explain that a fresh valid explicit handoff is required'
1632
+ assert snapshot['mission'] == 'Ship logout redirect consistency instead.', 'aged-out handoff should fall back to the newer recent-discussion mission'
1633
+ assert snapshot['source'] == 'session', 'aged-out handoff fallback should preserve the structured-session proposal source'
1634
+ assert state['mission_anchor'] == 'Ship logout redirect consistency instead.', 'aged-out handoff fallback should promote the newer recent-discussion mission after Start'
1635
+ assert state['advisory_startup_brief']['source'] == 'recent_discussion', 'aged-out handoff fallback should keep the advisory startup source non-canonical'
1603
1636
  PY
1604
1637
 
1605
1638
  # Negative handoff rationale: a non-startable capsule must not become the startup mission.
@@ -5,56 +5,57 @@ ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
5
  cd "$ROOT"
6
6
  export PI_COMPLETION_RUNNING_RELEASE_CHECK=1
7
7
 
8
- echo "[release-check] running control-plane validation, tracked .agent contract coverage, slice-surface parity, explicit-/cook parity, startup/refocus/context regressions, canonical evidence artifact, active-slice contract, observability, legacy cleanup, evaluator calibration, and rubric contract coverage"
8
+ echo "[release-check] running control-plane validation, tracked .agent contract coverage, slice-surface parity, mixed-model /cook parity, startup/refocus/context regressions, canonical evidence artifact, active-slice contract, observability, legacy cleanup, evaluator calibration, and rubric contract coverage"
9
9
  bash .agent/verify_completion_control_plane.sh
10
10
  git ls-files --error-unmatch .agent/README.md .agent/mission.md .agent/profile.json .agent/verify_completion_stop.sh .agent/verify_completion_control_plane.sh >/dev/null
11
11
 
12
- echo "[release-check] verifying public /cook parity and explicit-entry docs/help"
12
+ echo "[release-check] verifying public /cook mixed-model parity across docs/help"
13
13
  python3 - <<'PY'
14
14
  from pathlib import Path
15
15
 
16
16
  checks = {
17
17
  "README.md": [
18
18
  "`/cook` is the explicit workflow boundary for starting, continuing, refocusing, or beginning the next round of long-running repo work.",
19
- "Only explicit `/cook` enters the workflow. Ordinary prompts stay in the main chat and go straight to the primary agent.",
20
19
  "Before you explicitly run `/cook`, the conversation can still stay in ordinary chat: the primary agent may keep answering follow-up questions and refining requirements rather than switching into a hard handoff-only refusal mode.",
21
- "That handoff should include an explicit structured `/cook` capsule in the assistant reply once the first slice is implementation-ready, so `/cook` can confirm the already-formed mission instead of re-deriving it from broad ambient context.",
22
- "The capsule is still advisory startup intake, not canonical workflow state, and new-workflow or next-round entry only proceeds when it already names the first bounded slice, repo-change-oriented acceptance, implementation surfaces, and verification commands.",
23
- "- startup and next-round entry stay confirm-first and require a fresh valid explicit primary-agent handoff",
24
- "- active workflows resume from canonical `.agent/**` state unless a fresh valid explicit handoff proposes a replacement",
25
- "`/cook` first looks for a fresh explicit primary-agent handoff capsule from recent ordinary-chat discussion. New-workflow entry and done-workflow next-round entry start only when that capsule is fresh, valid, and implementation-startable; otherwise `/cook` fails closed instead of deriving startup from recent discussion.",
26
- "When a workflow is already active and no fresh valid explicit handoff is present, `/cook` resumes from canonical `.agent/**` state instead of deriving replacement startup from recent discussion.",
27
- "Without one, `/cook` fails closed instead of deriving the next round from recent discussion.",
28
- "when a fresh explicit handoff suggests replacing an active workflow, `/cook` shows a chooser before any canonical state rewrite",
20
+ "If you explicitly ask for a pre-`/cook` preview or capsule, the primary agent may provide one, but that preview is opt-in only and stays non-canonical until you later run `/cook` and choose **Start**.",
21
+ "Bare `/cook` is still the canonical workflow boundary: it synthesizes the startup brief from recent ordinary-chat discussion at `/cook` time, then waits for **Start** or **Cancel** before any canonical `.agent/**` write.",
22
+ "- startup and next-round entry stay confirm-first: bare `/cook` synthesizes the startup brief from recent discussion, then waits for **Start** or **Cancel**",
23
+ "- any pre-`/cook` preview or capsule is explicit-request-only and non-canonical",
24
+ "When no workflow is active, bare `/cook` synthesizes a startup brief from recent ordinary-chat discussion and then waits for **Start** or **Cancel**.",
25
+ "| No workflow yet | `/cook` synthesizes a startup brief from recent discussion and shows **Start** / **Cancel**.",
26
+ "| Previous workflow is `done` | `/cook` synthesizes the next implementation round from recent discussion behind **Start** / **Cancel**.",
27
+ "any pre-`/cook` preview or capsule is advisory only and never writes canonical workflow state by itself",
29
28
  ],
30
29
  "CHANGELOG.md": [
31
- "relaxed the pre-`/cook` ordinary-chat boundary so the primary agent can keep discussing and refining requirements before explicit `/cook` instead of switching into a hard handoff-only refusal mode as soon as workflow-worthiness is detected",
32
- "made fresh explicit `/cook` handoffs reusable from recent ordinary-chat discussion instead of requiring the immediately preceding turn, so Cancel can return users cleanly to ordinary discussion before they rerun `/cook`",
33
- "kept bare `/cook` startup and done-workflow next-round entry fail-closed on missing or non-startable explicit handoffs, while active workflows still resume from canonical `.agent/**` state unless a fresh explicit handoff proposes replacement",
30
+ "moving default startup and done-workflow next-round synthesis to bare `/cook` from recent ordinary-chat discussion behind the existing **Start** / **Cancel** approval gate",
31
+ "kept pre-`/cook` previews or `cook_handoff` capsules opt-in only, non-canonical, and advisory until the user explicitly runs `/cook`; bare `/cook` no longer depends on a default prebuilt capsule for new-workflow startup",
32
+ "updated public parity and packaged release verification so README/help/changelog/release-check all describe and gate the shipped mixed model truthfully",
34
33
  ],
35
34
  "extensions/completion/prompt-surfaces.ts": [
36
- '"/cook is the only explicit entrypoint into long-running completion workflow."',
37
- '"If the user keeps asking follow-up questions or refining requirements before /cook, continue that ordinary-chat discussion normally instead of switching into a handoff-only refusal mode, but do not act as though /cook had already been invoked."',
38
- '"When handing off, explain that /cook can start a new workflow or next round only from a fresh valid explicit primary-agent handoff capsule from recent ordinary-chat discussion; otherwise it fails closed, while already-active workflows resume from canonical .agent state unless a fresh valid explicit handoff proposes replacement."',
39
- '"The capsule is startup intake for /cook only: do not present it as canonical .agent state',
35
+ '"Distinguish a workflow-worthy handoff from an opt-in preview request: by default, do not emit a structured preview or cook_handoff capsule in ordinary chat once the task is concrete enough; recommend bare /cook instead."',
36
+ '"When handing off, explain that bare /cook will synthesize a startup brief from recent ordinary-chat discussion for a new workflow or next round, while already-active workflows resume from canonical .agent state unless the user explicitly chooses a replacement path backed by a fresh valid explicit handoff."',
37
+ '"If the user explicitly asks for a /cook preview or capsule before running /cook, you may append one exact fenced block in the same assistant reply using ```cook_handoff ... ``` JSON',
38
+ '"Any preview capsule is startup intake for /cook only: do not present it as canonical .agent state, an active slice, or a persistent repo contract."',
40
39
  ],
41
40
  "extensions/completion/index.ts": [
42
- '"/cook failed closed because new-workflow startup now requires a fresh valid explicit primary-agent handoff from recent ordinary-chat discussion; recent discussion alone no longer starts a workflow. Ask the primary agent to hand off explicitly in the main chat, then rerun /cook."',
43
- 'description: "/cook workflow: start a new workflow or next round only from a fresh recent explicit primary-agent handoff, resume the current workflow from canonical state, or confirm an explicit replacement from the explicit /cook command"',
41
+ '"/cook failed closed because recent discussion did not produce a clear execution-ready startup brief for bare /cook with Mission/Scope/Constraints/Acceptance for concrete repo changes. Clarify the concrete repo changes in the main chat and rerun /cook; canonical workflow state is still only written after Start."',
42
+ 'description: "/cook workflow: synthesize an approval-gated startup brief from recent discussion for new-workflow or next-round entry, resume the current workflow from canonical state, or confirm an explicit active-workflow replacement"',
44
43
  ],
45
44
  }
46
45
 
47
46
  forbidden = {
48
47
  "README.md": [
49
- "Start a new workflow from recent discussion:",
50
- "`/cook` falls back to deriving a startup brief from recent discussion only when no fresh explicit handoff is blocking startup",
51
- "Without a fresh explicit handoff blocking startup, `/cook` can fall back to recent discussion.",
48
+ "wait for a fresh primary-agent handoff, then run `/cook`",
49
+ "That handoff should include an explicit structured `/cook` capsule in the assistant reply once the first slice is implementation-ready, so `/cook` can confirm the already-formed mission instead of re-deriving it from broad ambient context.",
50
+ "- startup and next-round entry stay confirm-first and require a fresh valid explicit primary-agent handoff",
51
+ "`/cook` first looks for a fresh explicit primary-agent handoff capsule from recent ordinary-chat discussion.",
52
+ "Without one, `/cook` fails closed instead of deriving the next round from recent discussion.",
52
53
  ],
53
- "extensions/completion/prompt-surfaces.ts": [
54
- '"When handing off, explain that /cook will first look for a fresh explicit primary-agent handoff capsule and otherwise fall back to recent discussion."',
54
+ "CHANGELOG.md": [
55
+ "kept bare `/cook` startup and done-workflow next-round entry fail-closed on missing or non-startable explicit handoffs, while active workflows still resume from canonical `.agent/**` state unless a fresh explicit handoff proposes replacement",
55
56
  ],
56
57
  "extensions/completion/index.ts": [
57
- 'description: "/cook workflow: derive a startup brief from recent discussion, then start, continue, refocus, or start the next round from the explicit /cook command"',
58
+ 'description: "/cook workflow: derive a startup brief from recent discussion for new-workflow or next-round entry, resume the current workflow from canonical state, or confirm an explicit active-workflow replacement"',
58
59
  '"/cook failed closed because recent discussion did not produce a clear execution-ready startup brief with Mission/Scope/Constraints/Acceptance for concrete repo changes. Clarify the concrete repo changes in the main chat and rerun /cook."',
59
60
  ],
60
61
  }
@@ -63,13 +64,13 @@ for path, needles in checks.items():
63
64
  text = Path(path).read_text()
64
65
  for needle in needles:
65
66
  if needle not in text:
66
- raise SystemExit(f"[release-check] missing expected /cook parity text in {path}: {needle}")
67
+ raise SystemExit(f"[release-check] missing expected /cook mixed-model parity text in {path}: {needle}")
67
68
 
68
69
  for path, needles in forbidden.items():
69
70
  text = Path(path).read_text()
70
71
  for needle in needles:
71
72
  if needle in text:
72
- raise SystemExit(f"[release-check] found stale /cook parity text in {path}: {needle}")
73
+ raise SystemExit(f"[release-check] found stale /cook explicit-handoff-only text in {path}: {needle}")
73
74
  PY
74
75
 
75
76
  npm run smoke-test
@@ -103,55 +103,8 @@ INLINE_REJECTION_ROUTING_SNAPSHOT="$TMPDIR/inline-arg-routing.json"
103
103
  INLINE_REJECTION_PROPOSAL_SNAPSHOT="$TMPDIR/inline-arg-proposal.json"
104
104
  INLINE_REJECTION_CHOOSER_SNAPSHOT="$TMPDIR/inline-arg-chooser.json"
105
105
  BOOTSTRAP_SESSION="$TMPDIR/session-smoke-bootstrap.jsonl"
106
- BOOTSTRAP_MESSAGES="$(python3 - <<'PY'
107
- import json
108
- capsule = {
109
- "kind": "cook_handoff",
110
- "source": "primary_agent",
111
- "captured_at": "2026-01-01T00:00:02.000Z",
112
- "source_turn_id": "m0002",
113
- "mission": "Exercise smoke-test bootstrap.",
114
- "scope": [
115
- "Materialize the canonical completion control-plane files.",
116
- "Keep the smoke test on supported /cook startup behavior."
117
- ],
118
- "constraints": [
119
- "Keep startup proposal confirmation approval-only."
120
- ],
121
- "acceptance": [
122
- "Scaffold .agent/profile.json, .agent/state.json, .agent/plan.json, .agent/active-slice.json, and .agent/verification-evidence.json for the smoke fixture.",
123
- "Keep scripts/smoke-test.sh and kickoff-prompt coverage truthful for packaged bootstrap."
124
- ],
125
- "risks": [
126
- "Smoke-test bootstrap should stay anchored to the fresh explicit handoff."
127
- ],
128
- "notes": [
129
- "Keep the smoke fixture aligned with the shipped explicit-handoff-only startup contract."
130
- ],
131
- "handoff_kind": "implementation_workflow_handoff",
132
- "first_slice_goal": "Scaffold canonical completion files and verify the packaged startup contract.",
133
- "first_slice_non_goals": [
134
- "Do not broaden the smoke fixture beyond the packaged startup surfaces."
135
- ],
136
- "implementation_surfaces": [
137
- ".agent/README.md",
138
- "scripts/smoke-test.sh"
139
- ],
140
- "verification_commands": [
141
- "npm run smoke-test"
142
- ],
143
- "why_this_slice_first": "The packaged explicit-handoff startup path must work before later workflow verification can run.",
144
- "task_type": "completion-workflow",
145
- "evaluation_profile": "completion-rubric-v1",
146
- "why_cook_now": "The startup handoff is concrete enough to bootstrap canonical workflow files."
147
- }
148
- messages = [
149
- {"role": "user", "content": "Please prepare the packaged smoke-test bootstrap path and tell me when it is ready for /cook."},
150
- {"role": "assistant", "content": "This bootstrap path is ready for /cook. Run /cook to confirm the startup brief.\n\n```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```"},
151
- ]
152
- print(json.dumps(messages, ensure_ascii=False))
153
- PY
154
- )"
106
+ BOOTSTRAP_DISCUSSION=$'Mission: Exercise smoke-test bootstrap.\nScope:\n- Materialize the canonical completion control-plane files.\n- Keep the smoke test on supported /cook startup behavior.\nConstraints:\n- Keep startup proposal confirmation approval-only.\nAcceptance:\n- Scaffold .agent/profile.json, .agent/state.json, .agent/plan.json, .agent/active-slice.json, and .agent/verification-evidence.json for the smoke fixture.\n- Keep scripts/smoke-test.sh and kickoff-prompt coverage truthful for packaged bootstrap.'
107
+ BOOTSTRAP_PROPOSAL="$TMPDIR/bootstrap-proposal.json"
155
108
 
156
109
  mkdir -p "$ROOT"
157
110
  cd "$ROOT"
@@ -180,11 +133,12 @@ assert not chooser.exists(), 'startup /cook inline-args rejection should not ope
180
133
  assert '/cook no longer accepts inline arguments.' in output, 'startup /cook inline-args rejection should explain the bare-only entry contract'
181
134
  PY
182
135
 
183
- write_session_messages "$BOOTSTRAP_SESSION" "$ROOT" "$BOOTSTRAP_MESSAGES"
136
+ write_session "$BOOTSTRAP_SESSION" "$ROOT" "$BOOTSTRAP_DISCUSSION"
184
137
 
185
138
  PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
186
139
  PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
187
140
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
141
+ PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$BOOTSTRAP_PROPOSAL" \
188
142
  PI_COMPLETION_TEST_DRIVER_PROMPT_PATH="$KICKOFF_PROMPT" \
189
143
  pi --session "$BOOTSTRAP_SESSION" -e "$PKG_ROOT" -p "/cook" \
190
144
  >"$TMPDIR/pi-completion-smoke-bootstrap.out" 2>"$TMPDIR/pi-completion-smoke-bootstrap.err"
@@ -197,7 +151,7 @@ git ls-files --error-unmatch .agent/README.md .agent/mission.md .agent/profile.j
197
151
  bash .agent/verify_completion_control_plane.sh >/dev/null
198
152
  bash .agent/verify_completion_stop.sh >/dev/null
199
153
 
200
- python3 - "$KICKOFF_PROMPT" <<'PY'
154
+ python3 - "$KICKOFF_PROMPT" "$BOOTSTRAP_PROPOSAL" <<'PY'
201
155
  import json
202
156
  import sys
203
157
  from pathlib import Path
@@ -211,6 +165,7 @@ plan = json.loads(Path('.agent/plan.json').read_text())
211
165
  active = json.loads(Path('.agent/active-slice.json').read_text())
212
166
  evidence = json.loads(Path('.agent/verification-evidence.json').read_text())
213
167
  kickoff = Path(sys.argv[1]).read_text()
168
+ proposal = json.loads(Path(sys.argv[2]).read_text())
214
169
 
215
170
  assert profile['task_type'] == expected_task_type, 'profile.json task_type mismatch after bootstrap'
216
171
  assert profile['evaluation_profile'] == expected_eval_profile, 'profile.json evaluation_profile mismatch after bootstrap'
@@ -224,7 +179,7 @@ assert active['implementation_surfaces'] == [], 'active-slice.json should scaffo
224
179
  assert active['verification_commands'] == [], 'active-slice.json should scaffold empty verification_commands'
225
180
  brief = state['advisory_startup_brief']
226
181
  assert brief['kind'] == 'startup_brief', 'state.json should preserve the confirmed startup brief as advisory intake'
227
- assert brief['source'] == 'primary_agent_handoff', 'smoke bootstrap should record the explicit handoff source in advisory intake'
182
+ assert brief['source'] == 'recent_discussion', 'smoke bootstrap should record recent-discussion synthesis in advisory intake'
228
183
  assert brief['mission'] == state['mission_anchor'], 'advisory startup brief mission should match the canonical mission anchor after bootstrap'
229
184
  assert brief['scope'] == ['Materialize the canonical completion control-plane files.', 'Keep the smoke test on supported /cook startup behavior.'], 'advisory startup brief should preserve scope items'
230
185
  assert brief['constraints'] == ['Keep startup proposal confirmation approval-only.'], 'advisory startup brief should preserve constraints'
@@ -232,9 +187,10 @@ assert brief['acceptance'] == [
232
187
  'Scaffold .agent/profile.json, .agent/state.json, .agent/plan.json, .agent/active-slice.json, and .agent/verification-evidence.json for the smoke fixture.',
233
188
  'Keep scripts/smoke-test.sh and kickoff-prompt coverage truthful for packaged bootstrap.'
234
189
  ], 'advisory startup brief should preserve acceptance'
235
- assert brief['risks'] == ['Smoke-test bootstrap should stay anchored to the fresh explicit handoff.'], 'advisory startup brief should preserve handoff risks'
236
- assert 'First slice goal: Scaffold canonical completion files and verify the packaged startup contract.' in brief['notes'], 'advisory startup brief should preserve the first_slice_goal in notes'
237
- assert 'Verification commands: npm run smoke-test' in brief['notes'], 'advisory startup brief should preserve verification_commands in notes'
190
+ assert brief['risks'] == [], 'recent-discussion smoke bootstrap should not invent handoff-only risks'
191
+ assert brief['notes'] == ['No additional operator notes were derived from recent discussion.'], 'recent-discussion smoke bootstrap should keep advisory notes non-canonical'
192
+ assert proposal['mission'] == state['mission_anchor'], 'recent-discussion smoke bootstrap should persist the synthesized mission in the proposal snapshot'
193
+ assert proposal['source'] == 'session', 'recent-discussion smoke bootstrap should snapshot the structured-session proposal source'
238
194
  assert evidence['artifact_type'] == 'completion-verification-evidence', 'verification-evidence.json artifact_type mismatch after bootstrap'
239
195
  assert evidence['subject_type'] == 'none', 'verification-evidence.json should scaffold idle subject_type'
240
196
  assert evidence['verification_commands'] == [], 'verification-evidence.json should scaffold empty verification_commands'
@@ -269,14 +225,14 @@ assert '/cook is the only explicit entrypoint into long-running completion workf
269
225
  assert 'do not begin long-running product implementation in ordinary chat' in handoff_text, 'ordinary handoff reminder should block workflow-level implementation before /cook'
270
226
  assert 'recommend /cook as the workflow boundary while keeping the conversation in ordinary chat until the user explicitly runs /cook.' in handoff_text, 'ordinary handoff reminder should keep pre-/cook discussion advisory-first'
271
227
  assert 'continue that ordinary-chat discussion normally instead of switching into a handoff-only refusal mode' in handoff_text, 'ordinary handoff reminder should avoid hard refusal mode before explicit /cook'
272
- assert '```cook_handoff ... ``` JSON' in handoff_text, 'ordinary handoff reminder should require the explicit structured /cook handoff capsule'
273
- assert 'implementation_workflow_handoff' in handoff_text, 'ordinary handoff reminder should require the implementation-ready handoff kind'
274
- assert 'first_slice_goal, first_slice_non_goals, implementation_surfaces, verification_commands, why_this_slice_first' in handoff_text, 'ordinary handoff reminder should require first-slice startability fields'
275
- assert 'The capsule is startup intake for /cook only' in handoff_text, 'ordinary handoff reminder should keep the capsule non-canonical'
276
- assert 'fresh valid explicit primary-agent handoff capsule from recent ordinary-chat discussion' in handoff_text, 'ordinary handoff reminder should describe recent explicit-handoff startup truthfully'
277
- assert 'fails closed' in handoff_text, 'ordinary handoff reminder should describe fail-closed startup when no fresh valid handoff exists'
228
+ assert 'do not emit a structured preview or cook_handoff capsule in ordinary chat once the task is concrete enough' in handoff_text, 'ordinary handoff reminder should keep pre-/cook capsules opt-in instead of default'
229
+ assert 'bare /cook will synthesize a startup brief from recent ordinary-chat discussion' in handoff_text, 'ordinary handoff reminder should describe /cook-time startup synthesis truthfully'
230
+ assert 'If the user explicitly asks for a /cook preview or capsule before running /cook' in handoff_text, 'ordinary handoff reminder should keep previews opt-in'
231
+ assert 'implementation_workflow_handoff' in handoff_text, 'ordinary handoff reminder should preserve the explicit preview handoff kind'
232
+ assert 'first_slice_goal, first_slice_non_goals, implementation_surfaces, verification_commands, why_this_slice_first' in handoff_text, 'ordinary handoff reminder should preserve first-slice preview fields when explicitly requested'
233
+ assert 'Any preview capsule is startup intake for /cook only' in handoff_text, 'ordinary handoff reminder should keep any preview non-canonical'
278
234
  assert 'resume from canonical .agent state' in handoff_text, 'ordinary handoff reminder should preserve active-workflow canonical resume wording'
279
- assert 'fall back to recent discussion' not in handoff_text, 'ordinary handoff reminder should no longer promise recent-discussion startup fallback'
235
+ assert 'fresh valid explicit primary-agent handoff capsule from recent ordinary-chat discussion' not in handoff_text, 'ordinary handoff reminder should no longer describe explicit capsules as the default startup path'
280
236
  assert not auto_resume.exists(), 'ordinary non-/cook turn should not queue auto-resume before /cook activation'
281
237
  assert 'Skipped completion workflow auto-resume prompt (test mode)' not in output, 'ordinary non-/cook turn should not attempt auto-resume'
282
238
  PY
@@ -36,12 +36,13 @@ When the task is judged ready for completion workflow, the primary agent must:
36
36
  - stop before long-running implementation
37
37
  - not edit tracked product files in ordinary chat for that workflow-level task
38
38
  - recommend bare `/cook` as the explicit workflow boundary once the task is implementation-ready
39
- - explain that `/cook` starts a new workflow or next round only from a fresh valid explicit primary-agent handoff capsule from recent ordinary-chat discussion, while active workflows resume from canonical state unless a fresh valid explicit handoff proposes replacement
40
- - distinguish a workflow-worthy handoff from an implementation-ready handoff
41
- - only append an implementation-ready `/cook` handoff capsule when the first bounded implementation slice is concrete enough to start immediately
39
+ - explain that bare `/cook` synthesizes a startup brief from recent ordinary-chat discussion for a new workflow or next round, while active workflows resume from canonical state unless the user explicitly chooses a replacement path backed by a fresh valid explicit handoff
40
+ - distinguish a workflow-worthy handoff from an opt-in preview request
41
+ - not append an implementation-ready `/cook` handoff capsule by default once the task becomes concrete enough; ordinary chat stays advisory-first until explicit `/cook`
42
+ - only provide a `/cook` startup preview or `cook_handoff` capsule when the user explicitly asks for that preview behavior in ordinary chat
42
43
  - if the user asks follow-up questions or refines requirements before running `/cook`, continue ordinary-chat discussion normally without acting as though workflow already started
43
44
 
44
- Required capsule format:
45
+ Optional preview capsule format when the user explicitly asks for it:
45
46
 
46
47
  ````text
47
48
  ```cook_handoff
@@ -73,15 +74,15 @@ Required capsule format:
73
74
  Notes:
74
75
 
75
76
  - `constraints` may be replaced or supplemented by `non_goals` when clearer.
76
- - `first_slice_goal`, `first_slice_non_goals`, `implementation_surfaces`, `verification_commands`, and `why_this_slice_first` are required only for implementation-ready handoffs.
77
- - If the work is workflow-worthy but that first slice is still vague, say that `/cook` will be the right next step once the first slice is concrete enough, then keep refining in ordinary chat without emitting this implementation-ready capsule yet.
78
- - If later ordinary-chat discussion materially changes the startup brief before `/cook` runs, update or replace the capsule in a later assistant reply.
77
+ - `first_slice_goal`, `first_slice_non_goals`, `implementation_surfaces`, `verification_commands`, and `why_this_slice_first` are required only for an implementation-ready preview capsule.
78
+ - If the work is workflow-worthy but the first slice still needs refinement, say that `/cook` will be the right next step once the slice is concrete enough, then keep refining in ordinary chat without emitting a preview capsule unless the user explicitly asks for one.
79
+ - If later ordinary-chat discussion materially changes the startup brief before `/cook` runs, update or replace the preview capsule in a later assistant reply.
79
80
  - The mission must be positively startable implementation work; do not use rejection or suppression text as the mission.
80
- - The capsule is startup intake for `/cook` only. It is not canonical `.agent/**` state, not active-slice state, and not a second repo contract source.
81
+ - Any preview capsule is startup intake for `/cook` only. It is not canonical `.agent/**` state, not active-slice state, and not a second repo contract source.
81
82
 
82
83
  Suggested wording:
83
84
 
84
- > This task now looks like `/cook` workflow work, but we are still in ordinary chat until you explicitly run `/cook`. If you want to keep refining the first slice first, we can do that here. Once you want to start implementation workflow, run bare `/cook`. I’ve also attached an explicit `/cook` handoff capsule so `/cook` can confirm this startup brief directly before the workflow begins.
85
+ > This task now looks like `/cook` workflow work, but we are still in ordinary chat until you explicitly run `/cook`. If you want to keep refining the first slice first, we can do that here. Once you want to start implementation workflow, run bare `/cook` and it will synthesize the startup brief from our recent discussion before the Start/Cancel gate. If you explicitly want a preview capsule first, ask and I can sketch one here.
85
86
 
86
87
  A short recap may include mission, scope, or acceptance, but that recap must not be presented as canonical plan state.
87
88