@linimin/pi-letscook 0.1.67 → 0.1.68
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/CHANGELOG.md +8 -0
- package/README.md +11 -11
- package/extensions/completion/driver.ts +25 -26
- package/extensions/completion/index.ts +25 -87
- package/extensions/completion/prompt-surfaces.ts +3 -3
- package/extensions/completion/proposal.ts +42 -7
- package/extensions/completion/role-runner.ts +6 -2
- package/package.json +1 -1
- package/scripts/active-slice-contract-test.sh +7 -12
- package/scripts/canonical-evidence-artifact-test.sh +9 -14
- package/scripts/context-proposal-test.sh +307 -1426
- package/scripts/refocus-test.sh +185 -459
- package/scripts/release-check.sh +7 -5
- package/scripts/role-runner-contract-test.sh +2 -2
- package/scripts/smoke-test.sh +11 -16
- package/skills/cook-handoff-boundary/SKILL.md +7 -6
package/scripts/refocus-test.sh
CHANGED
|
@@ -47,130 +47,31 @@ with session_path.open('w', encoding='utf-8') as fh:
|
|
|
47
47
|
PY
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
local
|
|
52
|
-
local
|
|
53
|
-
local
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
session_path
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
},
|
|
71
|
-
]
|
|
72
|
-
parent_id = None
|
|
73
|
-
for index, message in enumerate(messages, start=1):
|
|
74
|
-
entry_id = f"m{index:04d}"
|
|
75
|
-
entries.append({
|
|
76
|
-
"type": "message",
|
|
77
|
-
"id": entry_id,
|
|
78
|
-
"parentId": parent_id,
|
|
79
|
-
"timestamp": f"2026-01-01T00:00:{index:02d}.000Z",
|
|
80
|
-
"message": {
|
|
81
|
-
"role": message["role"],
|
|
82
|
-
"content": message["content"],
|
|
83
|
-
"timestamp": 1767225600000 + index * 1000,
|
|
84
|
-
},
|
|
85
|
-
})
|
|
86
|
-
parent_id = entry_id
|
|
87
|
-
with session_path.open('w', encoding='utf-8') as fh:
|
|
88
|
-
for entry in entries:
|
|
89
|
-
fh.write(json.dumps(entry, ensure_ascii=False) + "\n")
|
|
90
|
-
PY
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
cd "$TMPDIR"
|
|
94
|
-
git init -q
|
|
95
|
-
|
|
96
|
-
BOOTSTRAP_SESSION="$TMPDIR/session-bootstrap.jsonl"
|
|
97
|
-
BOOTSTRAP_MESSAGES="$(python3 - <<'PY'
|
|
98
|
-
import json
|
|
99
|
-
capsule = {
|
|
100
|
-
"kind": "cook_handoff",
|
|
101
|
-
"source": "primary_agent",
|
|
102
|
-
"captured_at": "2026-01-01T00:00:02.000Z",
|
|
103
|
-
"source_turn_id": "m0002",
|
|
104
|
-
"mission": "Smoke-test mission.",
|
|
105
|
-
"scope": [
|
|
106
|
-
"Bootstrap a completion workflow for the refocus regression fixture."
|
|
107
|
-
],
|
|
108
|
-
"constraints": [
|
|
109
|
-
"Keep active-workflow refocus behavior under the explicit-handoff startup contract."
|
|
110
|
-
],
|
|
111
|
-
"acceptance": [
|
|
112
|
-
"Bootstrap canonical refocus-fixture state for the active-workflow regression.",
|
|
113
|
-
"Verify the refocus regression with npm run refocus-test."
|
|
114
|
-
],
|
|
115
|
-
"risks": [],
|
|
116
|
-
"notes": [
|
|
117
|
-
"Use an explicit primary-agent startup-plan preview for the refocus regression fixture."
|
|
118
|
-
],
|
|
119
|
-
"handoff_kind": "implementation_workflow_handoff",
|
|
120
|
-
"first_slice_goal": "Bootstrap the refocus regression fixture from a fresh explicit startup-plan preview.",
|
|
121
|
-
"first_slice_non_goals": [],
|
|
122
|
-
"implementation_surfaces": [
|
|
123
|
-
"scripts/refocus-test.sh"
|
|
124
|
-
],
|
|
125
|
-
"verification_commands": [
|
|
126
|
-
"npm run refocus-test"
|
|
127
|
-
],
|
|
128
|
-
"why_this_slice_first": "The refocus regression fixture needs canonical state before active-workflow routing can be exercised.",
|
|
129
|
-
"task_type": "completion-workflow",
|
|
130
|
-
"evaluation_profile": "completion-rubric-v1",
|
|
131
|
-
"why_cook_now": "The active-workflow refocus regression needs a fresh explicit startup-plan preview."
|
|
50
|
+
bootstrap_active_workflow() {
|
|
51
|
+
local repo_root="$1"
|
|
52
|
+
local session_path="$2"
|
|
53
|
+
local bootstrap_discussion="$3"
|
|
54
|
+
local generated_handoff="$4"
|
|
55
|
+
|
|
56
|
+
mkdir -p "$repo_root"
|
|
57
|
+
cd "$repo_root"
|
|
58
|
+
git init -q
|
|
59
|
+
write_session "$session_path" "$repo_root" "$bootstrap_discussion"
|
|
60
|
+
|
|
61
|
+
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
62
|
+
PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$generated_handoff" \
|
|
63
|
+
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
64
|
+
pi --session "$session_path" -e "$PKG_ROOT" -p "/cook" \
|
|
65
|
+
>"$TMPDIR/bootstrap.out" 2>"$TMPDIR/bootstrap.err"
|
|
66
|
+
|
|
67
|
+
for file in .agent/profile.json .agent/state.json .agent/startup-plan.json .agent/startup-plan.md .agent/plan.json .agent/active-slice.json .agent/verification-evidence.json; do
|
|
68
|
+
[[ -f "$file" ]] || { echo "missing canonical bootstrap file: $file" >&2; exit 1; }
|
|
69
|
+
done
|
|
132
70
|
}
|
|
133
|
-
messages = [
|
|
134
|
-
{"role": "user", "content": "Prepare the refocus regression fixture and tell me when it is ready for /cook."},
|
|
135
|
-
{"role": "assistant", "content": "The refocus regression fixture is ready for /cook.\n\n```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```"},
|
|
136
|
-
]
|
|
137
|
-
print(json.dumps(messages, ensure_ascii=False))
|
|
138
|
-
PY
|
|
139
|
-
)"
|
|
140
|
-
write_session_messages "$BOOTSTRAP_SESSION" "$TMPDIR" "$BOOTSTRAP_MESSAGES"
|
|
141
|
-
|
|
142
|
-
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
143
|
-
pi --session "$BOOTSTRAP_SESSION" -e "$PKG_ROOT" -p "/cook" >"$TMPDIR/pi-completion-refocus-bootstrap.out" 2>"$TMPDIR/pi-completion-refocus-bootstrap.err" &
|
|
144
|
-
PI_PID=$!
|
|
145
|
-
for _ in $(seq 1 60); do
|
|
146
|
-
if [[ -f .agent/profile.json && -f .agent/state.json && -f .agent/plan.json && -f .agent/active-slice.json ]]; then
|
|
147
|
-
break
|
|
148
|
-
fi
|
|
149
|
-
sleep 1
|
|
150
|
-
done
|
|
151
|
-
if [[ ! -f .agent/profile.json || ! -f .agent/state.json || ! -f .agent/plan.json || ! -f .agent/active-slice.json ]]; then
|
|
152
|
-
echo "completion bootstrap did not materialize canonical files in time" >&2
|
|
153
|
-
cat "$TMPDIR/pi-completion-refocus-bootstrap.err" >&2 || true
|
|
154
|
-
kill "$PI_PID" >/dev/null 2>&1 || true
|
|
155
|
-
wait "$PI_PID" >/dev/null 2>&1 || true
|
|
156
|
-
exit 1
|
|
157
|
-
fi
|
|
158
|
-
kill "$PI_PID" >/dev/null 2>&1 || true
|
|
159
|
-
wait "$PI_PID" >/dev/null 2>&1 || true
|
|
160
71
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
state = json.loads(Path('.agent/state.json').read_text())
|
|
165
|
-
print(state['mission_anchor'])
|
|
166
|
-
PY
|
|
167
|
-
)"
|
|
168
|
-
|
|
169
|
-
INLINE_REJECTION_ROUTING="$TMPDIR/inline-arg-routing.json"
|
|
170
|
-
INLINE_REJECTION_PROPOSAL="$TMPDIR/inline-arg-proposal.json"
|
|
171
|
-
INLINE_REJECTION_CHOOSER="$TMPDIR/inline-arg-chooser.json"
|
|
172
|
-
INLINE_REJECTION_BASELINE="$TMPDIR/inline-arg-before.json"
|
|
173
|
-
python3 - "$INLINE_REJECTION_BASELINE" <<'PY'
|
|
72
|
+
snapshot_tracked() {
|
|
73
|
+
local baseline_path="$1"
|
|
74
|
+
python3 - "$baseline_path" <<'PY'
|
|
174
75
|
import json
|
|
175
76
|
import sys
|
|
176
77
|
from pathlib import Path
|
|
@@ -179,421 +80,246 @@ tracked = [
|
|
|
179
80
|
Path('.agent/mission.md'),
|
|
180
81
|
Path('.agent/profile.json'),
|
|
181
82
|
Path('.agent/state.json'),
|
|
83
|
+
Path('.agent/startup-plan.json'),
|
|
84
|
+
Path('.agent/startup-plan.md'),
|
|
182
85
|
Path('.agent/plan.json'),
|
|
183
86
|
Path('.agent/active-slice.json'),
|
|
184
87
|
Path('.agent/verification-evidence.json'),
|
|
185
88
|
]
|
|
186
89
|
Path(sys.argv[1]).write_text(json.dumps({path.name: path.read_text() for path in tracked}, indent=2) + '\n')
|
|
187
90
|
PY
|
|
91
|
+
}
|
|
188
92
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$INLINE_REJECTION_CHOOSER" \
|
|
192
|
-
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
193
|
-
pi -e "$PKG_ROOT" -p "/cook replacement mission that should stay in the main chat" \
|
|
194
|
-
>"$TMPDIR/pi-completion-refocus-inline-arg.out" 2>"$TMPDIR/pi-completion-refocus-inline-arg.err"
|
|
195
|
-
|
|
196
|
-
python3 - "$TMPDIR/pi-completion-refocus-inline-arg.out" "$TMPDIR/pi-completion-refocus-inline-arg.err" "$INLINE_REJECTION_ROUTING" "$INLINE_REJECTION_PROPOSAL" "$INLINE_REJECTION_CHOOSER" "$INITIAL_MISSION" "$INLINE_REJECTION_BASELINE" <<'PY'
|
|
197
|
-
import json
|
|
198
|
-
import sys
|
|
199
|
-
from pathlib import Path
|
|
200
|
-
|
|
201
|
-
output = Path(sys.argv[1]).read_text() + Path(sys.argv[2]).read_text()
|
|
202
|
-
routing = Path(sys.argv[3])
|
|
203
|
-
proposal = Path(sys.argv[4])
|
|
204
|
-
chooser = Path(sys.argv[5])
|
|
205
|
-
initial_mission = sys.argv[6]
|
|
206
|
-
before = json.loads(Path(sys.argv[7]).read_text())
|
|
207
|
-
tracked = [
|
|
208
|
-
Path('.agent/mission.md'),
|
|
209
|
-
Path('.agent/profile.json'),
|
|
210
|
-
Path('.agent/state.json'),
|
|
211
|
-
Path('.agent/plan.json'),
|
|
212
|
-
Path('.agent/active-slice.json'),
|
|
213
|
-
Path('.agent/verification-evidence.json'),
|
|
214
|
-
]
|
|
215
|
-
current_state = json.loads(before['state.json'])
|
|
216
|
-
assert current_state['mission_anchor'] == initial_mission, 'active /cook inline-args rejection should start from the current mission anchor'
|
|
217
|
-
assert not routing.exists(), 'active /cook inline-args rejection should not run active-workflow routing'
|
|
218
|
-
assert not proposal.exists(), 'active /cook inline-args rejection should not open final startup-plan confirmation'
|
|
219
|
-
assert not chooser.exists(), 'active /cook inline-args rejection should not open the existing-workflow chooser'
|
|
220
|
-
assert '/cook no longer accepts inline arguments.' in output, 'active /cook inline-args rejection should explain the bare-only entry contract'
|
|
221
|
-
after = {path.name: path.read_text() for path in tracked}
|
|
222
|
-
assert before == after, 'active /cook inline-args rejection should leave canonical files unchanged'
|
|
223
|
-
PY
|
|
224
|
-
|
|
225
|
-
SESSION_INITIAL_REFOCUS="$TMPDIR/session-initial-bare-refocus.jsonl"
|
|
226
|
-
INITIAL_REFOCUS_ROUTING="$TMPDIR/initial-bare-refocus-routing.json"
|
|
227
|
-
INITIAL_REFOCUS_MESSAGES="$(python3 - <<'PY'
|
|
93
|
+
BOOTSTRAP_DISCUSSION=$'Prepare the active workflow fixture and keep the initial mission small and truthful.'
|
|
94
|
+
BOOTSTRAP_HANDOFF="$(python3 - <<'PY'
|
|
228
95
|
import json
|
|
229
96
|
capsule = {
|
|
230
97
|
"kind": "cook_handoff",
|
|
231
98
|
"source": "primary_agent",
|
|
232
|
-
"
|
|
233
|
-
"source_turn_id": "m0002",
|
|
234
|
-
"mission": "Remove completion status line, keep widget.",
|
|
99
|
+
"mission": "Maintain the active workflow fixture baseline.",
|
|
235
100
|
"scope": [
|
|
236
|
-
"
|
|
101
|
+
"Scaffold canonical completion files for the refocus regression fixture.",
|
|
102
|
+
"Keep the initial workflow ready for later replacement checks."
|
|
237
103
|
],
|
|
238
104
|
"constraints": [
|
|
239
|
-
"
|
|
105
|
+
"Use supported bare /cook startup only."
|
|
240
106
|
],
|
|
241
107
|
"acceptance": [
|
|
242
|
-
"
|
|
108
|
+
"Bootstrap canonical completion state for the refocus regression fixture.",
|
|
109
|
+
"Keep scripts/refocus-test.sh aligned with the shipped startup behavior."
|
|
243
110
|
],
|
|
244
111
|
"risks": [],
|
|
245
112
|
"notes": [
|
|
246
|
-
"
|
|
113
|
+
"Bootstrap from same-entry primary-agent startup-plan synthesis."
|
|
247
114
|
],
|
|
248
115
|
"handoff_kind": "implementation_workflow_handoff",
|
|
249
|
-
"first_slice_goal": "
|
|
116
|
+
"first_slice_goal": "Scaffold canonical files for the refocus regression fixture.",
|
|
250
117
|
"first_slice_non_goals": [],
|
|
251
|
-
"implementation_surfaces": [
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
"verification_commands": [
|
|
255
|
-
"npm run refocus-test"
|
|
256
|
-
],
|
|
257
|
-
"why_this_slice_first": "The fresh explicit startup-plan preview is the only supported replacement entry while a workflow is active.",
|
|
118
|
+
"implementation_surfaces": ["scripts/refocus-test.sh"],
|
|
119
|
+
"verification_commands": ["npm run refocus-test"],
|
|
120
|
+
"why_this_slice_first": "Canonical state must exist before refocus can be exercised.",
|
|
258
121
|
"task_type": "completion-workflow",
|
|
259
122
|
"evaluation_profile": "completion-rubric-v1",
|
|
260
|
-
"why_cook_now": "
|
|
123
|
+
"why_cook_now": "The fixture startup is concrete enough to begin workflow planning."
|
|
261
124
|
}
|
|
262
|
-
|
|
263
|
-
{"role": "user", "content": "The smoke-test workflow is active, but a different replacement workflow may now be ready."},
|
|
264
|
-
{"role": "assistant", "content": "Use this fresh explicit startup-plan preview if you want /cook to replace the active workflow.\n\n```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```"},
|
|
265
|
-
]
|
|
266
|
-
print(json.dumps(messages, ensure_ascii=False))
|
|
267
|
-
PY
|
|
268
|
-
)"
|
|
269
|
-
write_session_messages "$SESSION_INITIAL_REFOCUS" "$TMPDIR" "$INITIAL_REFOCUS_MESSAGES"
|
|
270
|
-
|
|
271
|
-
PI_COMPLETION_EXISTING_WORKFLOW_ACTION=refocus \
|
|
272
|
-
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
273
|
-
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$INITIAL_REFOCUS_ROUTING" \
|
|
274
|
-
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
275
|
-
pi --session "$SESSION_INITIAL_REFOCUS" -e "$PKG_ROOT" -p "/cook" \
|
|
276
|
-
>"$TMPDIR/pi-completion-refocus.out" 2>"$TMPDIR/pi-completion-refocus.err"
|
|
277
|
-
|
|
278
|
-
python3 - "$INITIAL_REFOCUS_ROUTING" <<'PY'
|
|
279
|
-
import json
|
|
280
|
-
import sys
|
|
281
|
-
from pathlib import Path
|
|
282
|
-
|
|
283
|
-
new_anchor = 'Remove completion status line, keep widget.'
|
|
284
|
-
expected_task_type = 'completion-workflow'
|
|
285
|
-
expected_eval_profile = 'completion-rubric-v1'
|
|
286
|
-
routing = json.loads(Path(sys.argv[1]).read_text())
|
|
287
|
-
mission_text = Path('.agent/mission.md').read_text()
|
|
288
|
-
profile = json.loads(Path('.agent/profile.json').read_text())
|
|
289
|
-
state = json.loads(Path('.agent/state.json').read_text())
|
|
290
|
-
plan = json.loads(Path('.agent/plan.json').read_text())
|
|
291
|
-
active = json.loads(Path('.agent/active-slice.json').read_text())
|
|
292
|
-
|
|
293
|
-
assert new_anchor in mission_text, '.agent/mission.md did not update to the refocused mission anchor'
|
|
294
|
-
assert profile['task_type'] == expected_task_type, 'profile.json task_type mismatch after refocus'
|
|
295
|
-
assert profile['evaluation_profile'] == expected_eval_profile, 'profile.json evaluation_profile mismatch after refocus'
|
|
296
|
-
assert state['mission_anchor'] == new_anchor, 'state.json mission_anchor mismatch after refocus'
|
|
297
|
-
assert state['task_type'] == expected_task_type, 'state.json task_type mismatch after refocus'
|
|
298
|
-
assert state['evaluation_profile'] == expected_eval_profile, 'state.json evaluation_profile mismatch after refocus'
|
|
299
|
-
assert state['advisory_startup_brief']['mission'] == new_anchor, 'refocus should preserve the confirmed startup plan as advisory intake'
|
|
300
|
-
assert plan['mission_anchor'] == new_anchor, 'plan.json mission_anchor mismatch after refocus'
|
|
301
|
-
assert plan['task_type'] == expected_task_type, 'plan.json task_type mismatch after refocus'
|
|
302
|
-
assert plan['evaluation_profile'] == expected_eval_profile, 'plan.json evaluation_profile mismatch after refocus'
|
|
303
|
-
assert active['mission_anchor'] == new_anchor, 'active-slice.json mission_anchor mismatch after refocus'
|
|
304
|
-
assert active['task_type'] == expected_task_type, 'active-slice.json task_type mismatch after refocus'
|
|
305
|
-
assert active['evaluation_profile'] == expected_eval_profile, 'active-slice.json evaluation_profile mismatch after refocus'
|
|
306
|
-
assert state['current_phase'] == 'reground', 'state.json current_phase should reset to reground after refocus'
|
|
307
|
-
assert state['requires_reground'] is True, 'state.json requires_reground should be true after refocus'
|
|
308
|
-
assert state['next_mandatory_role'] == 'completion-regrounder', 'next_mandatory_role should reset to completion-regrounder'
|
|
309
|
-
assert state['continuation_reason'].startswith('User refocused workflow via /cook:'), 'continuation_reason should record the refocus'
|
|
310
|
-
assert plan['plan_basis'] == 'user_refocus', 'plan.json plan_basis should be user_refocus after refocus'
|
|
311
|
-
assert active['status'] == 'idle', 'active-slice.json status should reset to idle after refocus'
|
|
312
|
-
assert routing['mode'] == 'bare', 'supported refocus should use bare active-workflow routing mode'
|
|
313
|
-
assert 'explicitGoal' not in routing, 'supported bare refocus should not expose removed explicit-goal shim fields'
|
|
314
|
-
assert 'explicitGoalProvided' not in routing, 'supported bare refocus should not expose removed explicit-goal shim fields'
|
|
315
|
-
assert routing['action'] == 'refocus', 'supported bare /cook should classify as refocus when a fresh explicit startup-plan preview proposes a different mission'
|
|
316
|
-
assert routing['reason'] == 'fresh_explicit_handoff', 'supported bare /cook should record the explicit-handoff replacement reason'
|
|
317
|
-
assert routing['proposedMissionAnchor'] == new_anchor, 'explicit handoff routing snapshot should expose the replacement mission anchor'
|
|
318
|
-
assert routing['proposalSource'] == 'handoff_capsule', 'explicit handoff routing snapshot should preserve the handoff source'
|
|
319
|
-
PY
|
|
320
|
-
|
|
321
|
-
UPDATED_MISSION="$(python3 - <<'PY'
|
|
322
|
-
import json
|
|
323
|
-
from pathlib import Path
|
|
324
|
-
state = json.loads(Path('.agent/state.json').read_text())
|
|
325
|
-
print(state['mission_anchor'])
|
|
125
|
+
print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
|
|
326
126
|
PY
|
|
327
127
|
)"
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
echo "expected mission anchor to change during supported bare refocus" >&2
|
|
331
|
-
exit 1
|
|
332
|
-
fi
|
|
333
|
-
|
|
334
|
-
# Fresh explicit startup-plan preview replacements must still reach the chooser and final Start/Cancel gate while the
|
|
335
|
-
# workflow is active.
|
|
336
|
-
BARE_REFOCUS_MISSION='Exercise explicit active-workflow replacement coverage.'
|
|
337
|
-
BARE_REFOCUS_MESSAGES="$(python3 - <<'PY'
|
|
128
|
+
REPLACEMENT_DISCUSSION=$'Switch the active workflow to the widget mission and keep the change confirm-first.'
|
|
129
|
+
REPLACEMENT_HANDOFF="$(python3 - <<'PY'
|
|
338
130
|
import json
|
|
339
131
|
capsule = {
|
|
340
132
|
"kind": "cook_handoff",
|
|
341
133
|
"source": "primary_agent",
|
|
342
|
-
"
|
|
343
|
-
"source_turn_id": "m0002",
|
|
344
|
-
"mission": "Exercise explicit active-workflow replacement coverage.",
|
|
134
|
+
"mission": "Remove the completion status line while keeping the completion widget.",
|
|
345
135
|
"scope": [
|
|
346
|
-
"
|
|
347
|
-
"Keep
|
|
136
|
+
"Replace the active fixture mission with the widget mission.",
|
|
137
|
+
"Keep refocus approval-only before canonical rewrite."
|
|
348
138
|
],
|
|
349
139
|
"constraints": [
|
|
350
|
-
"Do not
|
|
140
|
+
"Do not bypass the Start/Cancel gate."
|
|
351
141
|
],
|
|
352
142
|
"acceptance": [
|
|
353
|
-
"
|
|
143
|
+
"Rewrite canonical workflow state only after the replacement mission is approved.",
|
|
144
|
+
"Keep refocus regression coverage aligned with same-entry synthesis behavior."
|
|
145
|
+
],
|
|
146
|
+
"risks": [
|
|
147
|
+
"Do not leave the old mission partially active after refocus."
|
|
354
148
|
],
|
|
355
|
-
"risks": [],
|
|
356
149
|
"notes": [
|
|
357
|
-
"This replacement
|
|
150
|
+
"This replacement must come from same-entry primary-agent startup-plan synthesis."
|
|
358
151
|
],
|
|
359
152
|
"handoff_kind": "implementation_workflow_handoff",
|
|
360
|
-
"first_slice_goal": "
|
|
361
|
-
"first_slice_non_goals": [],
|
|
362
|
-
"implementation_surfaces": [
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
"verification_commands": [
|
|
366
|
-
"npm run refocus-test"
|
|
367
|
-
],
|
|
368
|
-
"why_this_slice_first": "The active workflow should only replace from a fresh explicit startup-plan preview.",
|
|
153
|
+
"first_slice_goal": "Rewrite canonical workflow state for the widget mission.",
|
|
154
|
+
"first_slice_non_goals": ["Do not start implementation before the refocus is approved."],
|
|
155
|
+
"implementation_surfaces": ["scripts/refocus-test.sh", ".agent/startup-plan.json"],
|
|
156
|
+
"verification_commands": ["npm run refocus-test"],
|
|
157
|
+
"why_this_slice_first": "The active workflow must be re-anchored before later role dispatch.",
|
|
369
158
|
"task_type": "completion-workflow",
|
|
370
159
|
"evaluation_profile": "completion-rubric-v1",
|
|
371
|
-
"why_cook_now": "
|
|
160
|
+
"why_cook_now": "A different workflow mission is now concrete enough to replace the active one."
|
|
372
161
|
}
|
|
373
|
-
|
|
374
|
-
{"role": "user", "content": "The current workflow is active, but there is a fresh explicit replacement handoff ready."},
|
|
375
|
-
{"role": "assistant", "content": "Use this fresh explicit startup-plan preview if you want /cook to replace the active workflow.\n\n```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```"},
|
|
376
|
-
]
|
|
377
|
-
print(json.dumps(messages, ensure_ascii=False))
|
|
162
|
+
print("```cook_handoff\n" + json.dumps(capsule, ensure_ascii=False, indent=2) + "\n```")
|
|
378
163
|
PY
|
|
379
164
|
)"
|
|
380
165
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
166
|
+
# Case 1: chooser cancel leaves canonical state untouched while still surfacing synthesized replacement routing.
|
|
167
|
+
ROOT_ONE="$TMPDIR/repo-one"
|
|
168
|
+
SESSION_ONE_BOOTSTRAP="$TMPDIR/session-one-bootstrap.jsonl"
|
|
169
|
+
SESSION_ONE_REFOCUS="$TMPDIR/session-one-refocus.jsonl"
|
|
170
|
+
ROUTING_ONE="$TMPDIR/routing-one.json"
|
|
171
|
+
CHOOSER_ONE="$TMPDIR/chooser-one.json"
|
|
172
|
+
PROPOSAL_ONE="$TMPDIR/proposal-one.json"
|
|
173
|
+
BASELINE_ONE="$TMPDIR/baseline-one.json"
|
|
174
|
+
bootstrap_active_workflow "$ROOT_ONE" "$SESSION_ONE_BOOTSTRAP" "$BOOTSTRAP_DISCUSSION" "$BOOTSTRAP_HANDOFF"
|
|
175
|
+
cd "$ROOT_ONE"
|
|
176
|
+
snapshot_tracked "$BASELINE_ONE"
|
|
177
|
+
write_session "$SESSION_ONE_REFOCUS" "$ROOT_ONE" "$REPLACEMENT_DISCUSSION"
|
|
178
|
+
|
|
179
|
+
PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$REPLACEMENT_HANDOFF" \
|
|
386
180
|
PI_COMPLETION_EXISTING_WORKFLOW_ACTION=cancel \
|
|
387
|
-
PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$BARE_CHOOSER_SNAPSHOT" \
|
|
388
|
-
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$BARE_ROUTING_CHOOSER_CANCEL" \
|
|
389
181
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
390
|
-
|
|
391
|
-
|
|
182
|
+
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$ROUTING_ONE" \
|
|
183
|
+
PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$CHOOSER_ONE" \
|
|
184
|
+
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$PROPOSAL_ONE" \
|
|
185
|
+
pi --session "$SESSION_ONE_REFOCUS" -e "$PKG_ROOT" -p "/cook" \
|
|
186
|
+
>"$TMPDIR/refocus-one.out" 2>"$TMPDIR/refocus-one.err"
|
|
392
187
|
|
|
393
|
-
python3 - "$
|
|
188
|
+
python3 - "$ROUTING_ONE" "$CHOOSER_ONE" "$PROPOSAL_ONE" "$BASELINE_ONE" "$TMPDIR/refocus-one.out" "$TMPDIR/refocus-one.err" <<'PY'
|
|
394
189
|
import json
|
|
395
190
|
import sys
|
|
396
191
|
from pathlib import Path
|
|
397
192
|
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
193
|
+
routing = json.loads(Path(sys.argv[1]).read_text())
|
|
194
|
+
chooser = json.loads(Path(sys.argv[2]).read_text())
|
|
195
|
+
proposal = Path(sys.argv[3])
|
|
196
|
+
before = json.loads(Path(sys.argv[4]).read_text())
|
|
197
|
+
output = Path(sys.argv[5]).read_text() + Path(sys.argv[6]).read_text()
|
|
198
|
+
tracked = [
|
|
199
|
+
Path('.agent/mission.md'),
|
|
200
|
+
Path('.agent/profile.json'),
|
|
201
|
+
Path('.agent/state.json'),
|
|
202
|
+
Path('.agent/startup-plan.json'),
|
|
203
|
+
Path('.agent/startup-plan.md'),
|
|
204
|
+
Path('.agent/plan.json'),
|
|
205
|
+
Path('.agent/active-slice.json'),
|
|
206
|
+
Path('.agent/verification-evidence.json'),
|
|
207
|
+
]
|
|
208
|
+
after = {path.name: path.read_text() for path in tracked}
|
|
406
209
|
|
|
407
|
-
assert
|
|
408
|
-
assert
|
|
409
|
-
assert
|
|
410
|
-
assert
|
|
411
|
-
assert
|
|
412
|
-
assert
|
|
413
|
-
assert
|
|
414
|
-
assert routing['reason'] == 'fresh_explicit_handoff', 'fresh explicit replacement handoff should record the explicit-handoff reason'
|
|
415
|
-
assert routing['currentMissionAnchor'] == updated_mission, 'explicit-handoff routing should keep the current mission anchor until the user approves replacement'
|
|
416
|
-
assert routing['proposedMissionAnchor'] == replacement_mission, 'explicit-handoff routing should expose the proposed replacement mission'
|
|
417
|
-
assert routing['proposalSource'] == 'handoff_capsule', 'explicit-handoff routing should preserve the handoff source'
|
|
418
|
-
assert chooser['title'].startswith('Existing completion workflow found'), 'bare chooser snapshot should describe the existing-workflow prompt'
|
|
419
|
-
assert chooser['choices'][0].startswith('Continue current workflow'), 'bare chooser should keep the continue option'
|
|
420
|
-
assert chooser['choices'][1].startswith('Start new workflow from explicit primary-agent startup plan'), 'bare chooser should offer the explicit-startup-plan replacement option'
|
|
421
|
-
assert 'Start/Cancel confirmation' in chooser['choices'][1], 'bare chooser should mention the approval-only replacement confirmation'
|
|
422
|
-
assert chooser['choices'][2].startswith('Cancel'), 'bare chooser should keep the cancel option'
|
|
423
|
-
assert 'Discuss changes in the main chat and rerun /cook.' in output, 'bare chooser cancel should redirect users back to the main chat and rerun /cook'
|
|
210
|
+
assert routing['action'] == 'refocus', routing
|
|
211
|
+
assert routing['reason'] == 'generated_replacement_startup_plan', routing
|
|
212
|
+
assert routing['proposedMissionAnchor'] == 'Remove the completion status line while keeping the completion widget.', routing
|
|
213
|
+
assert chooser['choices'][1].startswith('Start new workflow from same-entry primary-agent startup plan'), chooser
|
|
214
|
+
assert not proposal.exists(), 'chooser cancel should not open the final Start/Cancel proposal snapshot'
|
|
215
|
+
assert before == after, 'chooser cancel should leave canonical workflow files unchanged'
|
|
216
|
+
assert 'Cancelled existing workflow confirmation.' in output, output
|
|
424
217
|
PY
|
|
425
218
|
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
219
|
+
# Case 2: final Start/Cancel cancel still leaves canonical state untouched after chooser acceptance.
|
|
220
|
+
ROOT_TWO="$TMPDIR/repo-two"
|
|
221
|
+
SESSION_TWO_BOOTSTRAP="$TMPDIR/session-two-bootstrap.jsonl"
|
|
222
|
+
SESSION_TWO_REFOCUS="$TMPDIR/session-two-refocus.jsonl"
|
|
223
|
+
ROUTING_TWO="$TMPDIR/routing-two.json"
|
|
224
|
+
CHOOSER_TWO="$TMPDIR/chooser-two.json"
|
|
225
|
+
PROPOSAL_TWO="$TMPDIR/proposal-two.json"
|
|
226
|
+
BASELINE_TWO="$TMPDIR/baseline-two.json"
|
|
227
|
+
bootstrap_active_workflow "$ROOT_TWO" "$SESSION_TWO_BOOTSTRAP" "$BOOTSTRAP_DISCUSSION" "$BOOTSTRAP_HANDOFF"
|
|
228
|
+
cd "$ROOT_TWO"
|
|
229
|
+
snapshot_tracked "$BASELINE_TWO"
|
|
230
|
+
write_session "$SESSION_TWO_REFOCUS" "$ROOT_TWO" "$REPLACEMENT_DISCUSSION"
|
|
231
|
+
|
|
232
|
+
PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$REPLACEMENT_HANDOFF" \
|
|
431
233
|
PI_COMPLETION_EXISTING_WORKFLOW_ACTION=refocus \
|
|
432
234
|
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=cancel \
|
|
433
|
-
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$BARE_PROPOSAL_CANCEL" \
|
|
434
|
-
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$BARE_ROUTING_FINAL_CANCEL" \
|
|
435
235
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
436
|
-
|
|
437
|
-
|
|
236
|
+
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$ROUTING_TWO" \
|
|
237
|
+
PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$CHOOSER_TWO" \
|
|
238
|
+
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$PROPOSAL_TWO" \
|
|
239
|
+
pi --session "$SESSION_TWO_REFOCUS" -e "$PKG_ROOT" -p "/cook" \
|
|
240
|
+
>"$TMPDIR/refocus-two.out" 2>"$TMPDIR/refocus-two.err"
|
|
438
241
|
|
|
439
|
-
python3 - "$
|
|
242
|
+
python3 - "$ROUTING_TWO" "$CHOOSER_TWO" "$PROPOSAL_TWO" "$BASELINE_TWO" "$TMPDIR/refocus-two.out" "$TMPDIR/refocus-two.err" <<'PY'
|
|
440
243
|
import json
|
|
441
244
|
import sys
|
|
442
245
|
from pathlib import Path
|
|
443
246
|
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
assert proposal['source'] == 'handoff_capsule', 'final Start/Cancel cancel should preserve the explicit-handoff proposal source'
|
|
461
|
-
assert 'Discuss changes in the main chat and rerun /cook.' in output, 'final Start/Cancel cancel should redirect users back to the main chat and rerun /cook'
|
|
462
|
-
PY
|
|
463
|
-
|
|
464
|
-
SESSION_BARE_ACCEPT="$TMPDIR/session-bare-accept.jsonl"
|
|
465
|
-
BARE_ROUTING_ACCEPT="$TMPDIR/bare-routing-accept.json"
|
|
466
|
-
BARE_PROPOSAL_ACCEPT="$TMPDIR/bare-replacement-proposal-accept.json"
|
|
467
|
-
write_session_messages "$SESSION_BARE_ACCEPT" "$TMPDIR" "$BARE_REFOCUS_MESSAGES"
|
|
468
|
-
|
|
469
|
-
PI_COMPLETION_EXISTING_WORKFLOW_ACTION=refocus \
|
|
470
|
-
PI_COMPLETION_CONTEXT_PROPOSAL_ACTION=accept \
|
|
471
|
-
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$BARE_PROPOSAL_ACCEPT" \
|
|
472
|
-
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$BARE_ROUTING_ACCEPT" \
|
|
473
|
-
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
474
|
-
pi --session "$SESSION_BARE_ACCEPT" -e "$PKG_ROOT" -p "/cook" \
|
|
475
|
-
>"$TMPDIR/pi-completion-bare-accept.out" 2>"$TMPDIR/pi-completion-bare-accept.err"
|
|
476
|
-
|
|
477
|
-
python3 - "$BARE_PROPOSAL_ACCEPT" "$BARE_ROUTING_ACCEPT" <<'PY'
|
|
478
|
-
import json
|
|
479
|
-
import sys
|
|
480
|
-
from pathlib import Path
|
|
481
|
-
|
|
482
|
-
new_anchor = 'Exercise explicit active-workflow replacement coverage.'
|
|
483
|
-
expected_task_type = 'completion-workflow'
|
|
484
|
-
expected_eval_profile = 'completion-rubric-v1'
|
|
485
|
-
proposal = json.loads(Path(sys.argv[1]).read_text())
|
|
486
|
-
routing = json.loads(Path(sys.argv[2]).read_text())
|
|
487
|
-
mission_text = Path('.agent/mission.md').read_text()
|
|
488
|
-
profile = json.loads(Path('.agent/profile.json').read_text())
|
|
489
|
-
state = json.loads(Path('.agent/state.json').read_text())
|
|
490
|
-
plan = json.loads(Path('.agent/plan.json').read_text())
|
|
491
|
-
active = json.loads(Path('.agent/active-slice.json').read_text())
|
|
492
|
-
|
|
493
|
-
assert proposal['mission'] == new_anchor, 'accepted bare refocus should preserve the replacement proposal mission'
|
|
494
|
-
assert routing['mode'] == 'bare', 'accepted bare refocus should keep bare routing mode'
|
|
495
|
-
assert 'explicitGoal' not in routing, 'accepted bare refocus should not expose removed explicit-goal shim fields'
|
|
496
|
-
assert 'explicitGoalProvided' not in routing, 'accepted bare refocus should not expose removed explicit-goal shim fields'
|
|
497
|
-
assert routing['action'] == 'refocus', 'accepted bare refocus should keep the explicit-handoff refocus classification'
|
|
498
|
-
assert routing['reason'] == 'fresh_explicit_handoff', 'accepted bare refocus should keep the explicit-handoff reason'
|
|
499
|
-
assert routing['currentMissionAnchor'] == 'Remove completion status line, keep widget.', 'accepted bare refocus should expose the original mission until Start is accepted'
|
|
500
|
-
assert routing['proposalSource'] == 'handoff_capsule', 'accepted bare refocus should preserve the explicit-handoff source'
|
|
501
|
-
assert new_anchor in mission_text, '.agent/mission.md did not update to the bare refocus mission anchor'
|
|
502
|
-
assert profile['task_type'] == expected_task_type, 'profile.json task_type mismatch after bare refocus'
|
|
503
|
-
assert profile['evaluation_profile'] == expected_eval_profile, 'profile.json evaluation_profile mismatch after bare refocus'
|
|
504
|
-
assert state['mission_anchor'] == new_anchor, 'state.json mission_anchor mismatch after bare refocus'
|
|
505
|
-
assert state['task_type'] == expected_task_type, 'state.json task_type mismatch after bare refocus'
|
|
506
|
-
assert state['evaluation_profile'] == expected_eval_profile, 'state.json evaluation_profile mismatch after bare refocus'
|
|
507
|
-
assert state['advisory_startup_brief']['mission'] == new_anchor, 'bare refocus should preserve the confirmed startup plan as advisory intake'
|
|
508
|
-
assert plan['mission_anchor'] == new_anchor, 'plan.json mission_anchor mismatch after bare refocus'
|
|
509
|
-
assert plan['task_type'] == expected_task_type, 'plan.json task_type mismatch after bare refocus'
|
|
510
|
-
assert plan['evaluation_profile'] == expected_eval_profile, 'plan.json evaluation_profile mismatch after bare refocus'
|
|
511
|
-
assert active['mission_anchor'] == new_anchor, 'active-slice.json mission_anchor mismatch after bare refocus'
|
|
512
|
-
assert active['task_type'] == expected_task_type, 'active-slice.json task_type mismatch after bare refocus'
|
|
513
|
-
assert active['evaluation_profile'] == expected_eval_profile, 'active-slice.json evaluation_profile mismatch after bare refocus'
|
|
514
|
-
assert state['current_phase'] == 'reground', 'state.json current_phase should reset to reground after bare refocus'
|
|
515
|
-
assert state['requires_reground'] is True, 'state.json requires_reground should be true after bare refocus'
|
|
516
|
-
assert state['next_mandatory_role'] == 'completion-regrounder', 'next_mandatory_role should reset to completion-regrounder after bare refocus'
|
|
517
|
-
assert state['continuation_reason'].startswith('User refocused workflow via /cook:'), 'continuation_reason should record the bare refocus'
|
|
518
|
-
assert plan['plan_basis'] == 'user_refocus', 'plan.json plan_basis should be user_refocus after bare refocus'
|
|
519
|
-
assert active['status'] == 'idle', 'active-slice.json status should reset to idle after bare refocus'
|
|
520
|
-
PY
|
|
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."
|
|
247
|
+
routing = json.loads(Path(sys.argv[1]).read_text())
|
|
248
|
+
chooser = json.loads(Path(sys.argv[2]).read_text())
|
|
249
|
+
proposal = json.loads(Path(sys.argv[3]).read_text())
|
|
250
|
+
before = json.loads(Path(sys.argv[4]).read_text())
|
|
251
|
+
output = Path(sys.argv[5]).read_text() + Path(sys.argv[6]).read_text()
|
|
252
|
+
tracked = [
|
|
253
|
+
Path('.agent/mission.md'),
|
|
254
|
+
Path('.agent/profile.json'),
|
|
255
|
+
Path('.agent/state.json'),
|
|
256
|
+
Path('.agent/startup-plan.json'),
|
|
257
|
+
Path('.agent/startup-plan.md'),
|
|
258
|
+
Path('.agent/plan.json'),
|
|
259
|
+
Path('.agent/active-slice.json'),
|
|
260
|
+
Path('.agent/verification-evidence.json'),
|
|
261
|
+
]
|
|
262
|
+
after = {path.name: path.read_text() for path in tracked}
|
|
526
263
|
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
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 startup plan.",
|
|
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 startup plan 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```")
|
|
264
|
+
assert routing['action'] == 'refocus', routing
|
|
265
|
+
assert routing['reason'] == 'generated_replacement_startup_plan', routing
|
|
266
|
+
assert chooser['choices'][1].startswith('Start new workflow from same-entry primary-agent startup plan'), chooser
|
|
267
|
+
assert proposal['source'] == 'deferred_primary_agent_handoff', proposal
|
|
268
|
+
assert proposal['mission'] == 'Remove the completion status line while keeping the completion widget.', proposal
|
|
269
|
+
assert before == after, 'final Start/Cancel cancel should leave canonical workflow files unchanged'
|
|
270
|
+
assert 'Cancelled replacement workflow proposal.' in output, output
|
|
565
271
|
PY
|
|
566
|
-
)"
|
|
567
272
|
|
|
568
|
-
|
|
273
|
+
# Case 3: accepting the synthesized replacement rewrites canonical mission and startup plan.
|
|
274
|
+
ROOT_THREE="$TMPDIR/repo-three"
|
|
275
|
+
SESSION_THREE_BOOTSTRAP="$TMPDIR/session-three-bootstrap.jsonl"
|
|
276
|
+
SESSION_THREE_REFOCUS="$TMPDIR/session-three-refocus.jsonl"
|
|
277
|
+
ROUTING_THREE="$TMPDIR/routing-three.json"
|
|
278
|
+
CHOOSER_THREE="$TMPDIR/chooser-three.json"
|
|
279
|
+
PROPOSAL_THREE="$TMPDIR/proposal-three.json"
|
|
280
|
+
bootstrap_active_workflow "$ROOT_THREE" "$SESSION_THREE_BOOTSTRAP" "$BOOTSTRAP_DISCUSSION" "$BOOTSTRAP_HANDOFF"
|
|
281
|
+
cd "$ROOT_THREE"
|
|
282
|
+
write_session "$SESSION_THREE_REFOCUS" "$ROOT_THREE" "$REPLACEMENT_DISCUSSION"
|
|
283
|
+
|
|
284
|
+
PI_COMPLETION_PRIMARY_HANDOFF_OUTPUT="$REPLACEMENT_HANDOFF" \
|
|
569
285
|
PI_COMPLETION_EXISTING_WORKFLOW_ACTION=refocus \
|
|
570
286
|
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
287
|
PI_COMPLETION_SKIP_DRIVER_KICKOFF=1 \
|
|
574
|
-
|
|
575
|
-
|
|
288
|
+
PI_COMPLETION_TEST_ACTIVE_WORKFLOW_ROUTING_PATH="$ROUTING_THREE" \
|
|
289
|
+
PI_COMPLETION_TEST_EXISTING_WORKFLOW_CHOOSER_PATH="$CHOOSER_THREE" \
|
|
290
|
+
PI_COMPLETION_TEST_CONTEXT_PROPOSAL_PATH="$PROPOSAL_THREE" \
|
|
291
|
+
pi --session "$SESSION_THREE_REFOCUS" -e "$PKG_ROOT" -p "/cook" \
|
|
292
|
+
>"$TMPDIR/refocus-three.out" 2>"$TMPDIR/refocus-three.err"
|
|
576
293
|
|
|
577
|
-
python3 - "$
|
|
294
|
+
python3 - "$ROUTING_THREE" "$CHOOSER_THREE" "$PROPOSAL_THREE" "$TMPDIR/refocus-three.out" "$TMPDIR/refocus-three.err" <<'PY'
|
|
578
295
|
import json
|
|
579
296
|
import sys
|
|
580
297
|
from pathlib import Path
|
|
581
298
|
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
299
|
+
routing = json.loads(Path(sys.argv[1]).read_text())
|
|
300
|
+
chooser = json.loads(Path(sys.argv[2]).read_text())
|
|
301
|
+
proposal = json.loads(Path(sys.argv[3]).read_text())
|
|
302
|
+
output = Path(sys.argv[4]).read_text() + Path(sys.argv[5]).read_text()
|
|
585
303
|
state = json.loads(Path('.agent/state.json').read_text())
|
|
304
|
+
startup_plan = json.loads(Path('.agent/startup-plan.json').read_text())
|
|
305
|
+
startup_plan_md = Path('.agent/startup-plan.md').read_text()
|
|
586
306
|
plan = json.loads(Path('.agent/plan.json').read_text())
|
|
587
307
|
active = json.loads(Path('.agent/active-slice.json').read_text())
|
|
588
308
|
|
|
589
|
-
|
|
590
|
-
assert routing['action'] == 'refocus',
|
|
591
|
-
assert routing['reason'] == '
|
|
592
|
-
assert
|
|
593
|
-
assert
|
|
594
|
-
assert
|
|
595
|
-
assert
|
|
596
|
-
assert state['
|
|
309
|
+
mission = 'Remove the completion status line while keeping the completion widget.'
|
|
310
|
+
assert routing['action'] == 'refocus', routing
|
|
311
|
+
assert routing['reason'] == 'generated_replacement_startup_plan', routing
|
|
312
|
+
assert chooser['choices'][1].startswith('Start new workflow from same-entry primary-agent startup plan'), chooser
|
|
313
|
+
assert proposal['source'] == 'deferred_primary_agent_handoff', proposal
|
|
314
|
+
assert state['mission_anchor'] == mission, state
|
|
315
|
+
assert state['current_phase'] == 'reground', state
|
|
316
|
+
assert state['next_mandatory_role'] == 'completion-regrounder', state
|
|
317
|
+
assert startup_plan['mission_anchor'] == mission, startup_plan
|
|
318
|
+
assert startup_plan['source'] == 'deferred_primary_agent_handoff', startup_plan
|
|
319
|
+
assert '## Goal' in startup_plan_md and mission in startup_plan_md, startup_plan_md
|
|
320
|
+
assert plan['mission_anchor'] == mission, plan
|
|
321
|
+
assert active['mission_anchor'] == mission, active
|
|
322
|
+
assert 'Refocused completion mission from same-entry primary-agent startup plan' in output, output
|
|
597
323
|
PY
|
|
598
324
|
|
|
599
|
-
echo "refocus test passed: $
|
|
325
|
+
echo "refocus test passed: $PKG_ROOT"
|