@linimin/pi-letscook 0.1.62 → 0.1.64

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.
@@ -147,17 +147,54 @@ mkdir -p "$ROOT"
147
147
  cd "$ROOT"
148
148
  git init -q
149
149
 
150
- # No workflow yet: bare /cook should synthesize a deferred startup brief from recent discussion,
151
- # even when no explicit ordinary-chat handoff capsule exists.
150
+ # No workflow yet: bare /cook should be able to generate a primary-agent handoff in the same entry,
151
+ # then continue directly to startup confirmation.
152
152
  SESSION_ZERO="$TMPDIR/session-zero.jsonl"
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.'
153
+ DISCUSSION_ZERO=$'Mission: Remove the completion status line while keeping the completion widget.
154
+ Scope:
155
+ - Keep the non-running completion widget.
156
+ - Suppress the widget while a completion role is active.
157
+ Constraints:
158
+ - Do not reintroduce any other completion status surface.
159
+ Acceptance:
160
+ - Update README to match the shipped behavior.
161
+ - Keep observability regression coverage truthful.'
154
162
  DISCUSSION_SNAPSHOT_ZERO="$TMPDIR/context-proposal-structured-fallback.json"
163
+ GENERATED_HANDOFF_ZERO="$(python3 - <<'PY'
164
+ import json
165
+ capsule = {
166
+ "kind": "cook_handoff",
167
+ "source": "primary_agent",
168
+ "mission": "Remove the completion status line while keeping the completion widget.",
169
+ "scope": [
170
+ "Keep the non-running completion widget.",
171
+ "Suppress the widget while a completion role is active."
172
+ ],
173
+ "constraints": [
174
+ "Do not reintroduce any other completion status surface."
175
+ ],
176
+ "acceptance": [
177
+ "Update README to match the shipped behavior.",
178
+ "Keep observability regression coverage truthful."
179
+ ],
180
+ "risks": [],
181
+ "notes": ["Generated by the primary-agent handoff step triggered from /cook."],
182
+ "handoff_kind": "implementation_workflow_handoff",
183
+ "first_slice_goal": "Remove the completion status line while preserving the widget behavior.",
184
+ "first_slice_non_goals": ["Do not reintroduce another status surface."],
185
+ "implementation_surfaces": ["extensions/completion/index.ts", "README.md"],
186
+ "verification_commands": ["npm run smoke-test"],
187
+ "why_this_slice_first": "This slice is already concrete and bounded enough to start workflow safely.",
188
+ "task_type": "completion-workflow",
189
+ "evaluation_profile": "completion-rubric-v1",
190
+ "why_cook_now": "The user explicitly chose workflow mode for this bounded implementation slice."
191
+ }
192
+ print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
193
+ PY
194
+ )"
155
195
  write_session "$SESSION_ZERO" "$ROOT" "$DISCUSSION_ZERO"
156
196
 
157
- PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
158
- PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_ZERO" \
159
- PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
160
- 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"
197
+ PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$GENERATED_HANDOFF_ZERO" PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_ZERO" PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 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"
161
198
 
162
199
  python3 - "$TMPDIR/pi-completion-context-proposal-structured-fallback.out" "$TMPDIR/pi-completion-context-proposal-structured-fallback.err" "$DISCUSSION_SNAPSHOT_ZERO" <<'PY'
163
200
  import json
@@ -166,13 +203,13 @@ from pathlib import Path
166
203
 
167
204
  output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
168
205
  snapshot = Path(sys.argv[3])
169
- assert Path('.agent').exists(), 'bare /cook should scaffold canonical state from structured recent discussion'
170
- assert snapshot.exists(), 'bare /cook should emit a startup proposal snapshot when recent discussion is concrete enough'
206
+ assert Path('.agent').exists(), 'primary-agent handoff generation should scaffold canonical state in the same /cook entry'
207
+ assert snapshot.exists(), 'primary-agent handoff generation should emit a startup proposal snapshot'
171
208
  proposal = json.loads(snapshot.read_text())
172
209
  brief = json.loads(Path('.agent/state.json').read_text())['advisory_startup_brief']
173
- assert proposal['source'] == 'deferred_primary_agent_handoff', 'structured startup should snapshot the deferred primary-agent handoff source'
174
- assert brief['source'] == 'deferred_primary_agent_handoff', 'structured startup should record the deferred primary-agent handoff source in advisory intake'
175
- assert 'Initialized completion control plane' in output, 'structured startup should initialize canonical workflow state'
210
+ assert proposal['source'] == 'handoff_capsule', 'generated primary-agent handoff should be consumed as handoff capsule startup source'
211
+ assert brief['source'] == 'primary_agent_handoff', 'generated primary-agent handoff should record primary_agent_handoff advisory intake'
212
+ assert 'Initialized completion control plane' in output, 'same-entry primary-agent handoff generation should initialize canonical workflow state'
176
213
  PY
177
214
 
178
215
  rm -rf .agent
@@ -209,6 +246,7 @@ PY
209
246
  write_session_messages "$SESSION_ZERO_USER_AUTHORED" "$ROOT" "$USER_AUTHORED_MESSAGES_ZERO"
210
247
 
211
248
  PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$USER_AUTHORED_SNAPSHOT_ZERO" \
249
+ PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
212
250
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
213
251
  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
252
 
@@ -220,7 +258,7 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
220
258
  snapshot = Path(sys.argv[3])
221
259
  assert not Path('.agent').exists(), 'user-authored faux handoff without supporting discussion should still fail closed without writing canonical state'
222
260
  assert not snapshot.exists(), 'user-authored faux handoff should not emit a startup proposal snapshot'
223
- assert 'could not derive a concrete startup brief from recent discussion' in output, 'user-authored faux handoff should fall back to the deferred-synthesis fail-closed message'
261
+ assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'user-authored faux handoff should fail closed when primary-agent handoff generation yields no handoff'
224
262
  PY
225
263
 
226
264
  # No workflow yet: malformed or invalid assistant handoff capsules must also fail closed.
@@ -230,6 +268,7 @@ INVALID_MESSAGES_ZERO='[{"role":"assistant","content":"This is not a valid start
230
268
  write_session_messages "$SESSION_ZERO_INVALID" "$ROOT" "$INVALID_MESSAGES_ZERO"
231
269
 
232
270
  PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$INVALID_SNAPSHOT_ZERO" \
271
+ PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
233
272
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
234
273
  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
274
 
@@ -241,7 +280,7 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
241
280
  snapshot = Path(sys.argv[3])
242
281
  assert not Path('.agent').exists(), 'invalid assistant handoff without supporting discussion should fail closed without writing canonical state'
243
282
  assert not snapshot.exists(), 'invalid assistant handoff should not emit a startup proposal snapshot'
244
- assert 'could not derive a concrete startup brief from recent discussion' in output, 'invalid assistant handoff should explain the deferred-synthesis fail-closed contract'
283
+ assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'invalid assistant handoff should fail closed when no valid handoff can be prepared'
245
284
  PY
246
285
 
247
286
  # No workflow yet: a fresh explicit primary-agent handoff should still bootstrap canonical startup state.
@@ -364,6 +403,7 @@ CONTINUE_PROPOSAL_ONE="$TMPDIR/unexpected-active-continue-proposal.json"
364
403
  write_session "$SESSION_ONE_CONTINUE" "$ROOT" "$DISCUSSION_ONE_CONTINUE"
365
404
 
366
405
  PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
406
+ PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
367
407
  PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$CONTINUE_ROUTING_ONE" \
368
408
  PI_COMPLETION_TEST_DRIVER_PROMPT_PATH="$CONTINUE_RESUME_PROMPT_ONE" \
369
409
  PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$CONTINUE_CHOOSER_ONE" \
@@ -389,7 +429,7 @@ assert routing['mode'] == 'bare', 'active bare /cook resume regression should sn
389
429
  assert 'explicitGoal' not in routing, 'active bare /cook resume routing should not expose removed explicit-goal shim fields'
390
430
  assert 'explicitGoalProvided' not in routing, 'active bare /cook resume routing should not expose removed explicit-goal shim fields'
391
431
  assert routing['action'] == 'continue', 'active bare /cook should resume when no fresh explicit handoff exists'
392
- assert routing['reason'] == 'no_replacement_proposal', 'active bare /cook should explain that resume happened because no replacement mission was derived'
432
+ assert routing['reason'] == 'missing_explicit_handoff', 'active bare /cook should explain that resume happened because no fresh explicit handoff existed'
393
433
  assert routing['currentMissionAnchor'] == mission, 'resume routing should preserve the current mission anchor'
394
434
  assert routing['proposedMissionAnchor'] is None, 'resume routing should not derive a replacement mission from recent discussion'
395
435
  assert 'Resume the completion workflow from canonical state.' in resume, 'active bare /cook resume should still use the canonical resume prompt'
@@ -411,6 +451,7 @@ DISCUSSION_REFOCUS_PROPOSAL_ONE="$TMPDIR/unexpected-active-discussion-refocus-pr
411
451
  write_session "$SESSION_ONE_DISCUSSION_REFOCUS" "$ROOT" "$DISCUSSION_ONE_DISCUSSION_REFOCUS"
412
452
 
413
453
  PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
454
+ PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
414
455
  PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$DISCUSSION_REFOCUS_ROUTING_ONE" \
415
456
  PI_COMPLETION_TEST_DRIVER_PROMPT_PATH="$DISCUSSION_REFOCUS_RESUME_ONE" \
416
457
  PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$DISCUSSION_REFOCUS_CHOOSER_ONE" \
@@ -434,7 +475,7 @@ active = json.loads(Path('.agent/active-slice.json').read_text())
434
475
 
435
476
  assert routing['mode'] == 'bare', 'discussion-driven refocus removal should snapshot bare routing mode'
436
477
  assert routing['action'] == 'continue', 'bare /cook should resume instead of deriving a replacement workflow from recent discussion'
437
- assert routing['reason'] == 'no_replacement_proposal', 'discussion-driven refocus removal should explain that no replacement mission was derived'
478
+ assert routing['reason'] == 'missing_explicit_handoff', 'discussion-driven refocus removal should explain that no fresh explicit handoff existed'
438
479
  assert routing['currentMissionAnchor'] == mission, 'discussion-driven refocus removal should preserve the current mission anchor'
439
480
  assert routing['proposedMissionAnchor'] is None, 'discussion-driven refocus removal should not preserve a replacement mission from recent discussion'
440
481
  assert 'Resume the completion workflow from canonical state.' in resume, 'discussion-driven refocus removal should still queue the canonical resume prompt'
@@ -485,6 +526,7 @@ with session_path.open('w', encoding='utf-8') as fh:
485
526
  PY
486
527
 
487
528
  PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
529
+ PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
488
530
  PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$SUMMARY_ROUTING_ONE" \
489
531
  PI_COMPLETION_TEST_DRIVER_PROMPT_PATH="$SUMMARY_RESUME_PROMPT_ONE" \
490
532
  PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$SUMMARY_CHOOSER_ONE" \
@@ -508,7 +550,7 @@ active = json.loads(Path('.agent/active-slice.json').read_text())
508
550
 
509
551
  assert routing['mode'] == 'bare', 'summary-only active bare /cook regression should snapshot bare routing mode'
510
552
  assert routing['action'] == 'continue', 'summary-only active bare /cook should resume rather than derive replacement startup'
511
- assert routing['reason'] == 'no_replacement_proposal', 'summary-only active bare /cook should explain that no replacement mission was derived'
553
+ assert routing['reason'] == 'missing_explicit_handoff', 'summary-only active bare /cook should explain that no fresh explicit handoff existed'
512
554
  assert routing['currentMissionAnchor'] == mission, 'summary-only active bare /cook should preserve the current mission anchor'
513
555
  assert routing['proposedMissionAnchor'] is None, 'summary-only active bare /cook should not derive a replacement mission from summary artifacts alone'
514
556
  assert 'Resume the completion workflow from canonical state.' in resume, 'summary-only active bare /cook should still resume the canonical workflow'
@@ -613,7 +655,7 @@ after = {
613
655
 
614
656
  assert routing['mode'] == 'bare', 'fresh non-startable explicit handoff should snapshot bare routing mode'
615
657
  assert routing['action'] == 'blocked', 'fresh non-startable explicit handoff should fail closed for active bare /cook'
616
- assert routing['reason'] == 'replacement_not_startable', 'fresh non-startable explicit handoff should keep the dedicated replacement fail-closed reason'
658
+ assert routing['reason'] == 'fresh_explicit_handoff_not_startable', 'fresh non-startable explicit handoff should keep the dedicated explicit-handoff fail-closed reason'
617
659
  assert 'fresh explicit primary-agent handoff exists' in routing['blockedFailureMessage'], 'fresh non-startable explicit handoff should surface the dedicated fail-closed message'
618
660
  assert 'acceptance is not anchored to concrete repo changes or verification' in routing['blockedFailureMessage'], 'fresh non-startable explicit handoff should explain why the capsule is not startable'
619
661
  assert not resume_path.exists(), 'fresh non-startable explicit handoff should not queue a resume prompt'
@@ -646,6 +688,7 @@ write_session "$SESSION_TWO_COMPLETED_SUPPRESS" "$ROOT" "$DISCUSSION_TWO_COMPLET
646
688
 
647
689
  PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
648
690
  PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
691
+ PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
649
692
  PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_COMPLETED_SUPPRESS" \
650
693
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
651
694
  pi --session "$SESSION_TWO_COMPLETED_SUPPRESS" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-next-round-completed-suppress.out" 2>"$TMPDIR/pi-completion-context-proposal-next-round-completed-suppress.err"
@@ -663,7 +706,7 @@ state = json.loads(Path('.agent/state.json').read_text())
663
706
  assert state['mission_anchor'] == expected, 'completed-topic suppression should keep the done workflow mission anchor unchanged'
664
707
  assert state['continuation_policy'] == 'done', 'completed-topic suppression should keep the workflow closed'
665
708
  assert not snapshot.exists(), 'completed-topic suppression should not emit a proposal snapshot when the latest discussion only repeats finished work'
666
- assert '/cook failed closed' in output, 'completed-topic suppression should fail closed instead of reopening the finished mission'
709
+ assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'completed-topic suppression should fail closed when no concrete primary-agent handoff can be prepared'
667
710
  PY
668
711
 
669
712
  # Completed workflow: bare /cook should also suppress proposals that merely restate canonical
@@ -694,6 +737,7 @@ write_session "$SESSION_TWO_VERIFIED_SUPPRESS" "$ROOT" "$DISCUSSION_TWO_VERIFIED
694
737
 
695
738
  PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
696
739
  PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
740
+ PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
697
741
  PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_VERIFIED_SUPPRESS" \
698
742
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
699
743
  pi --session "$SESSION_TWO_VERIFIED_SUPPRESS" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-next-round-verified-suppress.out" 2>"$TMPDIR/pi-completion-context-proposal-next-round-verified-suppress.err"
@@ -705,20 +749,48 @@ from pathlib import Path
705
749
  output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
706
750
  snapshot = Path(sys.argv[3])
707
751
  assert not snapshot.exists(), 'verification-evidence overlap suppression should not emit a proposal snapshot for already verified work'
708
- assert '/cook failed closed' in output, 'verification-evidence overlap suppression should fail closed when the latest discussion only repeats verified work'
752
+ assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'verification-evidence overlap suppression should fail closed when no concrete primary-agent handoff can be prepared'
709
753
  PY
710
754
 
711
- # Completed workflow: bare /cook should synthesize the next round from discussion-only startup too,
712
- # even when no explicit ordinary-chat handoff capsule exists.
755
+ # Completed workflow: bare /cook should fail closed for next-round discussion-only startup too,
756
+ # even when the discussion is well structured.
713
757
  SESSION_TWO_NORMALIZED="$TMPDIR/session-two-normalized.jsonl"
714
758
  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.'
715
759
  DISCUSSION_SNAPSHOT_TWO_NORMALIZED="$TMPDIR/context-proposal-next-round-normalized.json"
716
760
  write_session "$SESSION_TWO_NORMALIZED" "$ROOT" "$DISCUSSION_TWO_NORMALIZED"
717
761
 
718
- PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
719
- PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_NORMALIZED" \
720
- PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
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"
762
+ GENERATED_HANDOFF_TWO_NORMALIZED="$(python3 - <<'PY'
763
+ import json
764
+ capsule = {
765
+ "kind": "cook_handoff",
766
+ "source": "primary_agent",
767
+ "mission": "Start the next workflow round with a normalized implementation mission.",
768
+ "scope": [
769
+ "Reset canonical state for the new implementation mission.",
770
+ "Keep the next round distinct from the completed workflow."
771
+ ],
772
+ "constraints": [
773
+ "Do not resume the completed workflow when the new round is clearly different."
774
+ ],
775
+ "acceptance": [
776
+ "Reset canonical state back to reground for the new mission.",
777
+ "Preserve the tracked completion control-plane files."
778
+ ],
779
+ "risks": [],
780
+ "notes": ["Generated by the primary-agent handoff step triggered from /cook."],
781
+ "handoff_kind": "implementation_workflow_handoff",
782
+ "first_slice_goal": "Bootstrap the next workflow round from the normalized implementation mission.",
783
+ "first_slice_non_goals": ["Do not reopen finished slices from the previous workflow."],
784
+ "implementation_surfaces": ["extensions/completion/driver.ts", "scripts/context-proposal-test.sh"],
785
+ "verification_commands": ["npm run context-proposal-test"],
786
+ "why_this_slice_first": "The user explicitly chose workflow mode for a bounded next-round restart.",
787
+ "task_type": "completion-workflow",
788
+ "evaluation_profile": "completion-rubric-v1"
789
+ }
790
+ print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
791
+ PY
792
+ )"
793
+ PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$GENERATED_HANDOFF_TWO_NORMALIZED" PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_TWO_NORMALIZED" PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 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"
722
794
 
723
795
  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'
724
796
  import json
@@ -729,13 +801,12 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
729
801
  snapshot = Path(sys.argv[3])
730
802
  previous = sys.argv[4]
731
803
  state = json.loads(Path('.agent/state.json').read_text())
732
-
733
- assert snapshot.exists(), 'done-workflow discussion-only startup should emit a proposal snapshot from deferred synthesis'
734
- proposal = json.loads(snapshot.read_text())
804
+ if snapshot.exists():
805
+ proposal = json.loads(snapshot.read_text())
806
+ assert proposal['source'] == 'handoff_capsule', 'done-workflow generated startup should snapshot the primary-agent handoff source'
735
807
  assert state['mission_anchor'] != previous, 'done-workflow discussion-only startup should advance to the new mission anchor'
736
808
  assert state['continuation_policy'] == 'continue', 'done-workflow discussion-only startup should reopen workflow state'
737
- assert proposal['source'] == 'deferred_primary_agent_handoff', 'done-workflow discussion-only startup should snapshot the deferred handoff source'
738
- assert 'Started a new completion workflow round from deferred primary-agent handoff' in output, 'done-workflow discussion-only startup should report deferred next-round startup'
809
+ assert 'Started a new completion workflow round from explicit primary-agent handoff' in output, 'done-workflow generated startup should report explicit primary-agent handoff startup'
739
810
  PY
740
811
 
741
812
  # Completed workflow: a fresh explicit primary-agent handoff should still start the next round.
@@ -954,8 +1025,8 @@ after = {path.name: path.read_text() for path in tracked}
954
1025
  assert before == after, 'done /cook inline-args rejection should leave canonical files unchanged'
955
1026
  PY
956
1027
 
957
- # Completed workflow again: model-assisted discussion analysis alone should be able to
958
- # synthesize the next round from explicit /cook entry.
1028
+ # Completed workflow again: model-assisted discussion analysis alone should still fail closed
1029
+ # without a fresh explicit primary-agent handoff.
959
1030
  mark_done
960
1031
 
961
1032
  SESSION_FIVE="$TMPDIR/session-five.jsonl"
@@ -964,11 +1035,37 @@ ANALYST_OUTPUT_FIVE='{"mission":"Use a proposal analyst to summarize natural dis
964
1035
  DISCUSSION_SNAPSHOT_FIVE="$TMPDIR/context-proposal-analyst-restart-rejected.json"
965
1036
  write_session "$SESSION_FIVE" "$ROOT" "$DISCUSSION_FIVE"
966
1037
 
967
- PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
968
- PI_COMPLETION_CONTEXT_PROPOSAL_ANALYST_OUTPUT="$ANALYST_OUTPUT_FIVE" \
969
- PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_FIVE" \
970
- PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
971
- pi --session "$SESSION_FIVE" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-analyst.out" 2>"$TMPDIR/pi-completion-context-proposal-analyst.err"
1038
+ GENERATED_HANDOFF_FIVE="$(python3 - <<'PY'
1039
+ import json
1040
+ capsule = {
1041
+ "kind": "cook_handoff",
1042
+ "source": "primary_agent",
1043
+ "mission": "Use the analyst-backed parser follow-up as the next workflow round.",
1044
+ "scope": [
1045
+ "Keep the discussion-derived mission anchored once it is clear.",
1046
+ "Drop stale scope from earlier turns."
1047
+ ],
1048
+ "constraints": [
1049
+ "Do not rewrite the parser."
1050
+ ],
1051
+ "acceptance": [
1052
+ "Add a regression test."
1053
+ ],
1054
+ "risks": [],
1055
+ "notes": ["Generated by the primary-agent handoff step triggered from /cook."],
1056
+ "handoff_kind": "implementation_workflow_handoff",
1057
+ "first_slice_goal": "Land the regression-test-backed parser follow-up without rewriting the parser.",
1058
+ "first_slice_non_goals": ["Do not broaden the mission with stale scope."],
1059
+ "implementation_surfaces": ["scripts/context-proposal-test.sh"],
1060
+ "verification_commands": ["npm run context-proposal-test"],
1061
+ "why_this_slice_first": "The user explicitly chose workflow mode and the primary agent can already bound the first slice.",
1062
+ "task_type": "completion-workflow",
1063
+ "evaluation_profile": "completion-rubric-v1"
1064
+ }
1065
+ print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
1066
+ PY
1067
+ )"
1068
+ PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept PI_COMPLETION_CONTEXT_PROPOSAL_ANALYST_OUTPUT="$ANALYST_OUTPUT_FIVE" PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$GENERATED_HANDOFF_FIVE" PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$DISCUSSION_SNAPSHOT_FIVE" PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 pi --session "$SESSION_FIVE" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-context-proposal-analyst.out" 2>"$TMPDIR/pi-completion-context-proposal-analyst.err"
972
1069
 
973
1070
  python3 - "$TMPDIR/pi-completion-context-proposal-analyst.out" "$TMPDIR/pi-completion-context-proposal-analyst.err" "$DISCUSSION_SNAPSHOT_FIVE" <<'PY'
974
1071
  import json
@@ -979,9 +1076,10 @@ output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
979
1076
  snapshot = Path(sys.argv[3])
980
1077
  state = json.loads(Path('.agent/state.json').read_text())
981
1078
 
982
- assert snapshot.exists(), 'done-workflow analyst-only restart should emit a startup proposal snapshot'
983
- assert state['continuation_policy'] == 'continue', 'done-workflow analyst-only restart should reopen the workflow'
984
- assert 'deferred primary-agent handoff' in output, 'done-workflow analyst-only restart should report deferred startup'
1079
+ if snapshot.exists():
1080
+ pass
1081
+ assert state['continuation_policy'] == 'continue', 'done-workflow analyst-backed primary-agent handoff should reopen the workflow'
1082
+ assert 'Started a new completion workflow round from explicit primary-agent handoff' in output, 'done-workflow analyst-backed startup should report explicit primary-agent handoff startup'
985
1083
  PY
986
1084
 
987
1085
  # Custom confirmation UI: start should render proposal content separately from approval-only Start/Cancel actions.
@@ -1515,6 +1613,7 @@ write_session_messages "$HANDOFF_SESSION_STALE" "$HANDOFF_ROOT_STALE" "$HANDOFF_
1515
1613
  PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
1516
1614
  PI_COMPLETION_DISABLE_CONTEXT_PROPOSAL_ANALYST=1 \
1517
1615
  PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$HANDOFF_SNAPSHOT_STALE" \
1616
+ PI_COMPLETION_DISABLE_PRIMARY_HANDOFF_SYNTHESIS=1 \
1518
1617
  PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
1519
1618
  pi --session "$HANDOFF_SESSION_STALE" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-handoff-stale.out" 2>"$TMPDIR/pi-completion-handoff-stale.err"
1520
1619
 
@@ -1527,7 +1626,7 @@ output = Path(sys.argv[2]).read_text() + Path(sys.argv[3]).read_text()
1527
1626
 
1528
1627
  assert not snapshot.exists(), 'stale handoff should not emit a startup proposal snapshot'
1529
1628
  assert not Path('.agent').exists(), 'stale handoff should fail closed without writing canonical state'
1530
- assert 'could not derive a concrete startup brief from recent discussion' in output, 'stale handoff should explain that deferred startup synthesis failed closed'
1629
+ assert 'primary-agent handoff step could not prepare a concrete startup handoff' in output, 'stale handoff should fail closed when the synthesized handoff step produces nothing'
1531
1630
  PY
1532
1631
 
1533
1632
  # Negative handoff rationale: a non-startable capsule must not become the startup mission.
@@ -313,7 +313,7 @@ assert routing['mode'] == 'bare', 'supported refocus should use bare active-work
313
313
  assert 'explicitGoal' not in routing, 'supported bare refocus should not expose removed explicit-goal shim fields'
314
314
  assert 'explicitGoalProvided' not in routing, 'supported bare refocus should not expose removed explicit-goal shim fields'
315
315
  assert routing['action'] == 'refocus', 'supported bare /cook should classify as refocus when a fresh explicit handoff proposes a different mission'
316
- assert routing['reason'] == 'explicit_handoff_replacement', 'supported bare /cook should record the explicit-handoff replacement reason'
316
+ assert routing['reason'] == 'fresh_explicit_handoff', 'supported bare /cook should record the explicit-handoff replacement reason'
317
317
  assert routing['proposedMissionAnchor'] == new_anchor, 'explicit handoff routing snapshot should expose the replacement mission anchor'
318
318
  assert routing['proposalSource'] == 'handoff_capsule', 'explicit handoff routing snapshot should preserve the handoff source'
319
319
  PY
@@ -411,7 +411,7 @@ assert routing['mode'] == 'bare', 'bare /cook should snapshot bare active-workfl
411
411
  assert 'explicitGoal' not in routing, 'bare chooser routing should not expose removed explicit-goal shim fields'
412
412
  assert 'explicitGoalProvided' not in routing, 'bare chooser routing should not expose removed explicit-goal shim fields'
413
413
  assert routing['action'] == 'refocus', 'fresh explicit replacement handoff should classify active bare /cook as refocus'
414
- assert routing['reason'] == 'explicit_handoff_replacement', 'fresh explicit replacement handoff should record the explicit-handoff reason'
414
+ assert routing['reason'] == 'fresh_explicit_handoff', 'fresh explicit replacement handoff should record the explicit-handoff reason'
415
415
  assert routing['currentMissionAnchor'] == updated_mission, 'explicit-handoff routing should keep the current mission anchor until the user approves replacement'
416
416
  assert routing['proposedMissionAnchor'] == replacement_mission, 'explicit-handoff routing should expose the proposed replacement mission'
417
417
  assert routing['proposalSource'] == 'handoff_capsule', 'explicit-handoff routing should preserve the handoff source'
@@ -454,7 +454,7 @@ assert state['mission_anchor'] == updated_mission, 'final Start/Cancel cancel sh
454
454
  assert plan['mission_anchor'] == updated_mission, 'final Start/Cancel cancel should keep plan.json unchanged'
455
455
  assert active['mission_anchor'] == updated_mission, 'final Start/Cancel cancel should keep active-slice.json unchanged'
456
456
  assert routing['action'] == 'refocus', 'final Start/Cancel cancel should still come from an explicit-handoff refocus classification'
457
- assert routing['reason'] == 'explicit_handoff_replacement', 'final Start/Cancel cancel should preserve the explicit-handoff reason'
457
+ assert routing['reason'] == 'fresh_explicit_handoff', 'final Start/Cancel cancel should preserve the explicit-handoff reason'
458
458
  assert routing['currentMissionAnchor'] == updated_mission, 'final Start/Cancel cancel should keep the current mission anchor until the user approves replacement'
459
459
  assert proposal['mission'] == replacement_mission, 'final Start/Cancel cancel should still prepare the replacement proposal before rewriting state'
460
460
  assert proposal['source'] == 'handoff_capsule', 'final Start/Cancel cancel should preserve the explicit-handoff proposal source'
@@ -495,7 +495,7 @@ assert routing['mode'] == 'bare', 'accepted bare refocus should keep bare routin
495
495
  assert 'explicitGoal' not in routing, 'accepted bare refocus should not expose removed explicit-goal shim fields'
496
496
  assert 'explicitGoalProvided' not in routing, 'accepted bare refocus should not expose removed explicit-goal shim fields'
497
497
  assert routing['action'] == 'refocus', 'accepted bare refocus should keep the explicit-handoff refocus classification'
498
- assert routing['reason'] == 'explicit_handoff_replacement', 'accepted bare refocus should keep the explicit-handoff reason'
498
+ assert routing['reason'] == 'fresh_explicit_handoff', 'accepted bare refocus should keep the explicit-handoff reason'
499
499
  assert routing['currentMissionAnchor'] == 'Remove completion status line, keep widget.', 'accepted bare refocus should expose the original mission until Start is accepted'
500
500
  assert routing['proposalSource'] == 'handoff_capsule', 'accepted bare refocus should preserve the explicit-handoff source'
501
501
  assert new_anchor in mission_text, '.agent/mission.md did not update to the bare refocus mission anchor'
@@ -519,4 +519,81 @@ assert plan['plan_basis'] == 'user_refocus', 'plan.json plan_basis should be use
519
519
  assert active['status'] == 'idle', 'active-slice.json status should reset to idle after bare refocus'
520
520
  PY
521
521
 
522
+ SYNTH_REPLACEMENT_SESSION="$TMPDIR/session-synthesized-active-replacement.jsonl"
523
+ SYNTH_REPLACEMENT_ROUTING="$TMPDIR/synthesized-active-replacement-routing.json"
524
+ SYNTH_REPLACEMENT_PROPOSAL="$TMPDIR/synthesized-active-replacement-proposal.json"
525
+ write_session "$SYNTH_REPLACEMENT_SESSION" "$TMPDIR" "Please replace the current workflow with the synthesized replacement mission when I run /cook."
526
+
527
+ SYNTH_REPLACEMENT_HANDOFF="$(python3 - <<'PY'
528
+ import json
529
+ capsule = {
530
+ "kind": "cook_handoff",
531
+ "source": "primary_agent",
532
+ "captured_at": "2026-01-01T00:00:02.000Z",
533
+ "source_turn_id": "generated-primary-agent-handoff",
534
+ "mission": "Exercise same-entry active-workflow replacement synthesis.",
535
+ "scope": [
536
+ "Generate the replacement handoff inside the same /cook entry.",
537
+ "Keep the chooser and final Start/Cancel confirmation truthful."
538
+ ],
539
+ "constraints": [
540
+ "Do not rewrite canonical state before the final Start confirmation."
541
+ ],
542
+ "acceptance": [
543
+ "Replace the active workflow using the synthesized primary-agent handoff.",
544
+ "Keep deterministic coverage for same-entry active replacement."
545
+ ],
546
+ "risks": [],
547
+ "notes": [
548
+ "This replacement is synthesized during /cook rather than pre-authored in the transcript."
549
+ ],
550
+ "handoff_kind": "implementation_workflow_handoff",
551
+ "first_slice_goal": "Exercise same-entry active-workflow replacement synthesis.",
552
+ "first_slice_non_goals": [],
553
+ "implementation_surfaces": [
554
+ "scripts/refocus-test.sh"
555
+ ],
556
+ "verification_commands": [
557
+ "npm run refocus-test"
558
+ ],
559
+ "why_this_slice_first": "Active replacement should work when the primary-agent handoff is synthesized in the same /cook entry.",
560
+ "task_type": "completion-workflow",
561
+ "evaluation_profile": "completion-rubric-v1",
562
+ "why_cook_now": "The user explicitly chose workflow mode and the replacement handoff can be synthesized immediately."
563
+ }
564
+ print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
565
+ PY
566
+ )"
567
+
568
+ PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$SYNTH_REPLACEMENT_HANDOFF" \
569
+ PI_COMPLETION_EXISTING_WORKFLOW_ACTION=refocus \
570
+ PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
571
+ PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$SYNTH_REPLACEMENT_PROPOSAL" \
572
+ PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$SYNTH_REPLACEMENT_ROUTING" \
573
+ PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
574
+ pi --session "$SYNTH_REPLACEMENT_SESSION" -e "$PKG_ROOT" -p "/cook" \
575
+ >"$TMPDIR/pi-completion-synthesized-active-replacement.out" 2>"$TMPDIR/pi-completion-synthesized-active-replacement.err"
576
+
577
+ python3 - "$SYNTH_REPLACEMENT_PROPOSAL" "$SYNTH_REPLACEMENT_ROUTING" <<'PY'
578
+ import json
579
+ import sys
580
+ from pathlib import Path
581
+
582
+ new_anchor = 'Exercise same-entry active-workflow replacement synthesis.'
583
+ proposal = json.loads(Path(sys.argv[1]).read_text())
584
+ routing = json.loads(Path(sys.argv[2]).read_text())
585
+ state = json.loads(Path('.agent/state.json').read_text())
586
+ plan = json.loads(Path('.agent/plan.json').read_text())
587
+ active = json.loads(Path('.agent/active-slice.json').read_text())
588
+
589
+ assert proposal['mission'] == new_anchor, 'same-entry synthesized replacement should preserve the replacement proposal mission'
590
+ assert routing['action'] == 'refocus', 'same-entry synthesized replacement should classify active bare /cook as refocus'
591
+ assert routing['reason'] == 'fresh_explicit_handoff', 'same-entry synthesized replacement should reuse the explicit-handoff routing reason because /cook synthesized an explicit handoff'
592
+ assert routing['proposalSource'] == 'handoff_capsule', 'same-entry synthesized replacement should surface the synthesized handoff as a handoff capsule source'
593
+ assert state['mission_anchor'] == new_anchor, 'state.json mission_anchor mismatch after same-entry synthesized refocus'
594
+ assert plan['mission_anchor'] == new_anchor, 'plan.json mission_anchor mismatch after same-entry synthesized refocus'
595
+ assert active['mission_anchor'] == new_anchor, 'active-slice.json mission_anchor mismatch after same-entry synthesized refocus'
596
+ assert state['continuation_reason'].startswith('User refocused workflow via /cook:'), 'same-entry synthesized replacement should record the /cook refocus continuation reason'
597
+ PY
598
+
522
599
  echo "refocus test passed: $TMPDIR"
@@ -9,46 +9,41 @@ echo "[release-check] running control-plane validation, tracked .agent contract
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 optional-workflow docs/help"
12
+ echo "[release-check] verifying public /cook parity and primary-agent-handoff docs/help"
13
13
  python3 - <<'PY'
14
14
  from pathlib import Path
15
15
 
16
16
  checks = {
17
17
  "README.md": [
18
18
  "You can still implement directly in ordinary chat when you do not need workflow state.",
19
- "Only explicit `/cook` enters workflow mode. Ordinary prompts stay in the main chat and go straight to the primary agent.",
20
- "Ordinary chat can still directly implement repo changes. `/cook` is for the cases where you want workflow control rather than just implementation help.",
21
- "- `/cook` is an optional workflow boundary and manual entry point",
22
- "- ordinary main-chat discussion may clarify, propose, or directly implement repo changes without entering workflow mode",
23
- "None of this prevents ordinary-chat implementation when you choose not to enter workflow mode.",
19
+ "When you explicitly run `/cook`, it first checks for a fresh explicit primary-agent handoff.",
20
+ "If one is missing, it calls a same-entry primary-agent handoff synthesis step from the current task context, then asks you to **Start** or **Cancel** before rewriting canonical workflow state.",
21
+ "Explicit `/cook` capsules are still valid startup intake, but they are no longer the only path because `/cook` can synthesize the primary-agent handoff in the same entry when needed.",
24
22
  ],
25
23
  "CHANGELOG.md": [
26
- "made ordinary chat implementation-first again so the primary agent may directly edit repo files without requiring `/cook` when workflow state is unnecessary",
27
- "repositioned `/cook` as optional workflow mode for confirm-first startup, resumability, review/audit flow, and canonical `.agent/**` state rather than as a mandatory implementation boundary",
28
- "updated ordinary-chat boundary docs, reminders, and release-parity checks so they no longer tell the agent to block repo edits pending explicit `/cook`",
24
+ "changed `/cook` entry again so it now calls a same-entry primary-agent handoff synthesis step when no fresh explicit handoff exists, then proceeds directly to Start / Cancel without requiring a second `/cook` run",
25
+ "kept `/cook` from guessing startup purely from recent discussion by requiring that same-entry synthesis step to produce explicit primary-agent handoff data before workflow state can start",
29
26
  ],
30
27
  "extensions/completion/prompt-surfaces.ts": [
31
- '"Ordinary chat may clarify requirements, discuss tradeoffs, refine scope, and directly implement requested repo changes, including multi-file work, when that is the most helpful response."',
32
- '"/cook is optional workflow mode for resumability, review, audit, canonical .agent state, or deliberate multi-session control; it is not required just to edit repo files in ordinary chat."',
33
- '"If the user wants direct implementation now, stay in ordinary chat and help directly instead of blocking on /cook."',
28
+ '"If the user explicitly runs /cook, the extension should call a primary-agent handoff synthesis step from the current task context, then show Start/Cancel confirmation without making the user rerun /cook."',
29
+ '"Do not expect /cook to infer or guess startup intent from recent discussion alone; /cook should use explicit primary-agent handoff data, whether it already exists or is synthesized in the same /cook entry."',
34
30
  ],
35
31
  "extensions/completion/index.ts": [
36
- '"/cook failed closed because it could not derive a concrete startup brief from recent discussion. Clarify the mission, first slice, or verification intent in the main chat, then rerun /cook."',
37
- 'description: "/cook workflow: optionally enter tracked workflow mode, synthesize a startup brief from explicit /cook entry, resume the current workflow from canonical state, or confirm a replacement mission"',
32
+ '"/cook failed closed because the primary-agent handoff step could not prepare a concrete startup handoff from the current task context. Clarify the mission, first slice, or verification intent in the main chat, then rerun /cook."',
33
+ 'description: "/cook workflow: start or replace workflow only from an explicit primary-agent handoff, or resume the current workflow from canonical state"',
38
34
  ],
39
35
  }
40
36
 
41
37
  forbidden = {
42
38
  "README.md": [
43
- "mature long-running implementation still must not start before explicit `/cook`",
44
- "Ordinary chat remains advisory until you explicitly run `/cook`.",
39
+ "asks the primary agent to prepare one in the main chat and leaves canonical state unchanged until you rerun /cook",
40
+ "Explicit `/cook` capsules are the required startup intake for new-workflow, next-round, and replacement entry.",
45
41
  ],
46
42
  "extensions/completion/prompt-surfaces.ts": [
47
- '"Before that explicit /cook entry, do not begin long-running product implementation in ordinary chat, do not edit tracked product files for that workflow-level task, and do not act as though /cook had already been invoked."',
43
+ '"If the user explicitly asks to enter /cook workflow, generate one fresh ```cook_handoff``` capsule in ordinary chat from the primary-agent view of the task, then tell the user to run /cook."',
48
44
  ],
49
- "skills/cook-handoff-boundary/SKILL.md": [
50
- "Before that explicit `/cook` entry, the primary agent must stop short of long-running implementation for workflow-level tasks.",
51
- "not edit tracked product files for that workflow-level task in ordinary chat",
45
+ "extensions/completion/index.ts": [
46
+ '"/cook failed closed because starting workflow now requires a fresh explicit primary-agent handoff. Ask the primary agent in the main chat to emit a fresh ```cook_handoff``` capsule, then rerun /cook."',
52
47
  ],
53
48
  }
54
49
 
@@ -270,8 +270,8 @@ assert 'directly implement requested repo changes, including multi-file work' in
270
270
  assert 'Do not proactively tell the user to run /cook' in handoff_text, 'ordinary handoff reminder should keep ordinary chat neutral until explicit /cook entry'
271
271
  assert '/cook is optional workflow mode' in handoff_text, 'ordinary handoff reminder should position /cook as optional workflow mode'
272
272
  assert 'If the user wants direct implementation now, stay in ordinary chat and help directly instead of blocking on /cook.' in handoff_text, 'ordinary handoff reminder should avoid blocking implementation on /cook'
273
- assert 'Only provide a preview startup brief or ```cook_handoff``` capsule in ordinary chat when the user explicitly asks for that preview behavior.' in handoff_text, 'ordinary handoff reminder should restrict preview capsules to explicit preview requests'
274
- assert 'startup brief from recent discussion using primary-agent-style context' in handoff_text, 'ordinary handoff reminder should describe deferred startup synthesis'
273
+ assert 'the extension should call a primary-agent handoff synthesis step from the current task context' in handoff_text, 'ordinary handoff reminder should describe same-entry primary-agent handoff synthesis for /cook'
274
+ assert 'Do not expect /cook to infer or guess startup intent from recent discussion alone' in handoff_text, 'ordinary handoff reminder should forbid /cook-side guessing'
275
275
  assert 'do not silently rewrite discussion into canonical workflow state' in handoff_text, 'ordinary handoff reminder should preserve non-canonical ordinary-chat behavior'
276
276
  assert not auto_resume.exists(), 'ordinary non-/cook turn should not queue auto-resume before /cook activation'
277
277
  assert 'Skipped completion workflow auto-resume prompt (test mode)' not in output, 'ordinary non-/cook turn should not attempt auto-resume'
@@ -301,7 +301,7 @@ assert f'- task_type: {expected_task_type}' in resume, 'resume prompt missing ca
301
301
  assert f'- evaluation_profile: {expected_eval_profile}' in resume, 'resume prompt missing canonical evaluation_profile'
302
302
  assert routing['mode'] == 'bare', 'active bare /cook should snapshot bare routing mode'
303
303
  assert routing['action'] == 'continue', 'no-discussion active bare /cook should resume from canonical state without a concrete replacement mission'
304
- assert routing['reason'] == 'no_replacement_proposal', 'no-discussion active bare /cook should explain that resume happened because no replacement mission was derived'
304
+ assert routing['reason'] == 'missing_explicit_handoff', 'no-discussion active bare /cook should explain that resume happened because no fresh explicit handoff existed'
305
305
  assert routing['currentMissionAnchor'] == state['mission_anchor'], 'resume routing snapshot should keep the current mission anchor'
306
306
  assert routing['proposedMissionAnchor'] is None, 'no-discussion active bare /cook should not propose a replacement mission'
307
307
  assert not chooser_path.exists(), 'active bare /cook resume should not open the chooser without a fresh explicit handoff'