prizmkit 1.1.98 → 1.1.100

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.
Files changed (79) hide show
  1. package/bundled/VERSION.json +3 -3
  2. package/bundled/dev-pipeline/README.md +5 -5
  3. package/bundled/dev-pipeline/launch-bugfix-daemon.sh +1 -1
  4. package/bundled/dev-pipeline/launch-feature-daemon.sh +1 -1
  5. package/bundled/dev-pipeline/launch-refactor-daemon.sh +1 -1
  6. package/bundled/dev-pipeline/lib/common.sh +244 -25
  7. package/bundled/dev-pipeline/reset-bug.sh +32 -2
  8. package/bundled/dev-pipeline/reset-feature.sh +32 -2
  9. package/bundled/dev-pipeline/reset-refactor.sh +32 -2
  10. package/bundled/dev-pipeline/run-bugfix.sh +133 -18
  11. package/bundled/dev-pipeline/run-feature.sh +134 -18
  12. package/bundled/dev-pipeline/run-refactor.sh +133 -18
  13. package/bundled/dev-pipeline/scripts/check-session-status.py +74 -1
  14. package/bundled/dev-pipeline/scripts/continuation.py +374 -0
  15. package/bundled/dev-pipeline/scripts/detect-stuck.py +5 -5
  16. package/bundled/dev-pipeline/scripts/generate-bootstrap-prompt.py +29 -35
  17. package/bundled/dev-pipeline/scripts/generate-bugfix-prompt.py +19 -25
  18. package/bundled/dev-pipeline/scripts/generate-refactor-prompt.py +19 -25
  19. package/bundled/dev-pipeline/scripts/init-bugfix-pipeline.py +1 -1
  20. package/bundled/dev-pipeline/scripts/init-pipeline.py +1 -1
  21. package/bundled/dev-pipeline/scripts/init-refactor-pipeline.py +1 -1
  22. package/bundled/dev-pipeline/scripts/parse-stream-progress.py +146 -16
  23. package/bundled/dev-pipeline/scripts/update-bug-status.py +220 -13
  24. package/bundled/dev-pipeline/scripts/update-feature-status.py +244 -18
  25. package/bundled/dev-pipeline/scripts/update-refactor-status.py +220 -13
  26. package/bundled/dev-pipeline/templates/agent-prompts/dev-implement.md +1 -1
  27. package/bundled/dev-pipeline/templates/bootstrap-tier1.md +2 -2
  28. package/bundled/dev-pipeline/templates/bootstrap-tier2.md +3 -3
  29. package/bundled/dev-pipeline/templates/bootstrap-tier3.md +3 -3
  30. package/bundled/dev-pipeline/templates/bugfix-bootstrap-prompt.md +1 -1
  31. package/bundled/dev-pipeline/templates/refactor-bootstrap-prompt.md +3 -3
  32. package/bundled/dev-pipeline/templates/sections/log-size-awareness.md +31 -66
  33. package/bundled/dev-pipeline/templates/session-status-schema.json +1 -1
  34. package/bundled/dev-pipeline/tests/conftest.py +1 -0
  35. package/bundled/dev-pipeline/tests/test_auto_skip.py +518 -8
  36. package/bundled/dev-pipeline/tests/test_generate_bootstrap_prompt.py +103 -0
  37. package/bundled/dev-pipeline/tests/test_generate_bugfix_prompt.py +60 -0
  38. package/bundled/dev-pipeline/tests/test_generate_refactor_prompt.py +43 -0
  39. package/bundled/dev-pipeline-windows/lib/common.ps1 +172 -10
  40. package/bundled/dev-pipeline-windows/lib/pipeline.ps1 +95 -11
  41. package/bundled/dev-pipeline-windows/lib/reset.ps1 +34 -0
  42. package/bundled/dev-pipeline-windows/reset-bug.ps1 +1 -0
  43. package/bundled/dev-pipeline-windows/reset-feature.ps1 +1 -0
  44. package/bundled/dev-pipeline-windows/reset-refactor.ps1 +1 -0
  45. package/bundled/dev-pipeline-windows/scripts/check-session-status.py +74 -1
  46. package/bundled/dev-pipeline-windows/scripts/continuation.py +374 -0
  47. package/bundled/dev-pipeline-windows/scripts/detect-stuck.py +5 -5
  48. package/bundled/dev-pipeline-windows/scripts/generate-bootstrap-prompt.py +29 -35
  49. package/bundled/dev-pipeline-windows/scripts/generate-bugfix-prompt.py +20 -25
  50. package/bundled/dev-pipeline-windows/scripts/generate-refactor-prompt.py +20 -25
  51. package/bundled/dev-pipeline-windows/scripts/init-bugfix-pipeline.py +1 -1
  52. package/bundled/dev-pipeline-windows/scripts/init-pipeline.py +1 -1
  53. package/bundled/dev-pipeline-windows/scripts/init-refactor-pipeline.py +1 -1
  54. package/bundled/dev-pipeline-windows/scripts/parse-stream-progress.py +146 -16
  55. package/bundled/dev-pipeline-windows/scripts/update-bug-status.py +220 -13
  56. package/bundled/dev-pipeline-windows/scripts/update-feature-status.py +244 -18
  57. package/bundled/dev-pipeline-windows/scripts/update-refactor-status.py +220 -13
  58. package/bundled/dev-pipeline-windows/templates/agent-prompts/dev-implement.md +1 -1
  59. package/bundled/dev-pipeline-windows/templates/bootstrap-tier1.md +2 -2
  60. package/bundled/dev-pipeline-windows/templates/bootstrap-tier2.md +3 -3
  61. package/bundled/dev-pipeline-windows/templates/bootstrap-tier3.md +3 -3
  62. package/bundled/dev-pipeline-windows/templates/bugfix-bootstrap-prompt.md +1 -1
  63. package/bundled/dev-pipeline-windows/templates/refactor-bootstrap-prompt.md +3 -3
  64. package/bundled/dev-pipeline-windows/templates/sections/log-size-awareness.md +31 -68
  65. package/bundled/dev-pipeline-windows/templates/session-status-schema.json +1 -1
  66. package/bundled/skills/_metadata.json +1 -1
  67. package/bundled/skills/bugfix-pipeline-launcher/SKILL.md +2 -2
  68. package/bundled/skills/feature-pipeline-launcher/SKILL.md +2 -2
  69. package/bundled/skills/recovery-workflow/SKILL.md +2 -2
  70. package/bundled/skills/recovery-workflow/evals/evals.json +2 -2
  71. package/bundled/skills/refactor-pipeline-launcher/SKILL.md +2 -2
  72. package/bundled/skills-windows/bugfix-pipeline-launcher/SKILL.md +2 -2
  73. package/bundled/skills-windows/feature-pipeline-launcher/SKILL.md +2 -2
  74. package/bundled/skills-windows/recovery-workflow/SKILL.md +2 -2
  75. package/bundled/skills-windows/recovery-workflow/evals/evals.json +2 -2
  76. package/bundled/skills-windows/refactor-pipeline-launcher/SKILL.md +2 -2
  77. package/package.json +1 -1
  78. package/bundled/dev-pipeline/scripts/monitor-log.sh +0 -104
  79. package/bundled/dev-pipeline-windows/scripts/monitor-log.ps1 +0 -102
@@ -43,6 +43,8 @@ SESSION_STATUS_VALUES = [
43
43
  "crashed",
44
44
  "timed_out",
45
45
  "infra_error",
46
+ "context_overflow",
47
+ "stalled_context_continuation",
46
48
  "commit_missing",
47
49
  "docs_missing",
48
50
  "merge_conflict",
@@ -90,6 +92,12 @@ def parse_args():
90
92
  parser.add_argument("--max-retries", type=int, default=3, help="Maximum code retry count (default: 3)")
91
93
  parser.add_argument("--max-infra-retries", type=int, default=3, help="Maximum infrastructure retry count (default: 3)")
92
94
  parser.add_argument("--project-root", default=None, help="Project root directory. Required for 'clean' action.")
95
+ parser.add_argument("--active-dev-branch", default=None, help="Development branch preserved for continuation after context overflow.")
96
+ parser.add_argument("--base-branch", default=None, help="Original/base branch for continuation branch reuse.")
97
+ parser.add_argument("--last-fatal-error-code", default=None, help="Fatal runtime error code associated with continuation.")
98
+ parser.add_argument("--continuation-summary-path", default=None, help="Optional continuation summary artifact path.")
99
+ parser.add_argument("--no-progress-count", type=int, default=None, help="Consecutive context-overflow sessions without objective progress.")
100
+ parser.add_argument("--progress-fingerprint", default=None, help="JSON progress fingerprint captured after the session.")
93
101
  return parser.parse_args()
94
102
 
95
103
 
@@ -122,7 +130,7 @@ def load_refactor_status(state_dir, refactor_id):
122
130
  The 'status' field is NOT included — status lives exclusively
123
131
  in refactor-list.json.
124
132
  """
125
- status_path = os.path.join(state_dir, "refactors", refactor_id, "status.json")
133
+ status_path = os.path.join(state_dir, refactor_id, "status.json")
126
134
  if not os.path.isfile(status_path):
127
135
  return _default_status(refactor_id)
128
136
  data, err = load_json_file(status_path)
@@ -137,7 +145,7 @@ def save_refactor_status(state_dir, refactor_id, status_data):
137
145
  """Write the status.json for a refactor (runtime fields only)."""
138
146
  # Defensively strip status — it belongs in refactor-list.json
139
147
  status_data.pop("status", None)
140
- status_path = os.path.join(state_dir, "refactors", refactor_id, "status.json")
148
+ status_path = os.path.join(state_dir, refactor_id, "status.json")
141
149
  return write_json_file(status_path, status_data)
142
150
 
143
151
 
@@ -168,6 +176,128 @@ def update_refactor_in_list(refactor_list_path, refactor_id, new_status):
168
176
  return write_json_file(refactor_list_path, data)
169
177
 
170
178
 
179
+ CONTINUATION_PENDING_FIELDS = [
180
+ "active_dev_branch",
181
+ "base_branch",
182
+ "continuation_pending",
183
+ "continuation_reason",
184
+ "last_context_overflow_session_id",
185
+ "previous_session_id",
186
+ "last_fatal_error_code",
187
+ "continuation_summary_path",
188
+ "no_progress_count",
189
+ "last_progress_fingerprint",
190
+ "needs_attention",
191
+ "stalled_context_continuation",
192
+ "stalled_reason",
193
+ ]
194
+
195
+ CONTINUATION_COUNTER_FIELDS = [
196
+ "context_overflow_count",
197
+ "continuation_count",
198
+ ]
199
+
200
+
201
+ def has_pending_continuation_metadata(status_data):
202
+ """Return True when runtime state still has pending continuation metadata."""
203
+ return any(key in status_data for key in CONTINUATION_PENDING_FIELDS)
204
+
205
+
206
+ def clear_pending_continuation_metadata(status_data):
207
+ """Clear branch/pending continuation fields while preserving observability counters."""
208
+ for key in CONTINUATION_PENDING_FIELDS:
209
+ status_data.pop(key, None)
210
+
211
+
212
+ def reset_continuation_metadata(status_data):
213
+ """Clear all continuation runtime metadata, including manual-reset counters."""
214
+ clear_pending_continuation_metadata(status_data)
215
+ for key in CONTINUATION_COUNTER_FIELDS:
216
+ status_data.pop(key, None)
217
+
218
+
219
+ STALL_REASON = "context_overflow_without_git_checkpoint_or_artifact_progress"
220
+
221
+
222
+ def _load_progress_fingerprint(raw):
223
+ if not raw:
224
+ return None
225
+ try:
226
+ return json.loads(raw)
227
+ except (TypeError, ValueError):
228
+ return {"unparsed": str(raw)}
229
+
230
+
231
+ def _set_continuation_common(status_data, args, session_id):
232
+ if args.active_dev_branch:
233
+ status_data["active_dev_branch"] = args.active_dev_branch
234
+ if args.base_branch:
235
+ status_data["base_branch"] = args.base_branch
236
+ status_data["last_context_overflow_session_id"] = session_id
237
+ status_data["previous_session_id"] = session_id
238
+ status_data["last_fatal_error_code"] = args.last_fatal_error_code or "context_overflow"
239
+ if args.continuation_summary_path:
240
+ status_data["continuation_summary_path"] = args.continuation_summary_path
241
+ else:
242
+ status_data.pop("continuation_summary_path", None)
243
+ if args.no_progress_count is not None:
244
+ status_data["no_progress_count"] = max(0, args.no_progress_count)
245
+ fingerprint = _load_progress_fingerprint(args.progress_fingerprint)
246
+ if fingerprint is not None:
247
+ status_data["last_progress_fingerprint"] = fingerprint
248
+ status_data["last_infra_error_session_id"] = None
249
+ status_data["resume_from_phase"] = None
250
+ if session_id:
251
+ status_data["last_session_id"] = session_id
252
+
253
+
254
+ def set_context_overflow_continuation_metadata(status_data, args, session_id):
255
+ """Record continuation metadata for a context-overflow outcome in status.json."""
256
+ status_data["context_overflow_count"] = status_data.get("context_overflow_count", 0) + 1
257
+ status_data["continuation_count"] = status_data.get("continuation_count", 0) + 1
258
+ status_data["continuation_pending"] = True
259
+ status_data["continuation_reason"] = "context_overflow"
260
+ status_data.pop("needs_attention", None)
261
+ status_data.pop("stalled_context_continuation", None)
262
+ status_data.pop("stalled_reason", None)
263
+ _set_continuation_common(status_data, args, session_id)
264
+
265
+
266
+ def set_stalled_context_continuation_metadata(status_data, args, session_id):
267
+ """Record no-progress context-overflow stall without consuming retry budgets."""
268
+ status_data["context_overflow_count"] = status_data.get("context_overflow_count", 0) + 1
269
+ status_data["continuation_count"] = status_data.get("continuation_count", 0) + 1
270
+ _set_continuation_common(status_data, args, session_id)
271
+ status_data["continuation_pending"] = False
272
+ status_data["continuation_reason"] = STALL_REASON
273
+ status_data["needs_attention"] = True
274
+ status_data["stalled_context_continuation"] = True
275
+ status_data["stalled_reason"] = STALL_REASON
276
+ if args.no_progress_count is None or args.no_progress_count < 2:
277
+ status_data["no_progress_count"] = 2
278
+
279
+
280
+ def continuation_metadata_summary(status_data):
281
+ """Return additive continuation fields for CLI JSON outputs."""
282
+ return {
283
+ "active_dev_branch": status_data.get("active_dev_branch"),
284
+ "base_branch": status_data.get("base_branch"),
285
+ "continuation_pending": status_data.get("continuation_pending", False),
286
+ "continuation_reason": status_data.get("continuation_reason"),
287
+ "last_context_overflow_session_id": status_data.get("last_context_overflow_session_id"),
288
+ "last_fatal_error_code": status_data.get("last_fatal_error_code"),
289
+ "previous_session_id": status_data.get("previous_session_id"),
290
+ "context_overflow_count": status_data.get("context_overflow_count", 0),
291
+ "continuation_count": status_data.get("continuation_count", 0),
292
+ "no_progress_count": status_data.get("no_progress_count", 0),
293
+ "last_progress_fingerprint": status_data.get("last_progress_fingerprint"),
294
+ "needs_attention": status_data.get("needs_attention", False),
295
+ "stalled_context_continuation": status_data.get("stalled_context_continuation", False),
296
+ "stalled_reason": status_data.get("stalled_reason"),
297
+ "continuation_summary_path": status_data.get("continuation_summary_path"),
298
+ }
299
+
300
+
171
301
  # ---------------------------------------------------------------------------
172
302
  # Action: get_next
173
303
  # ---------------------------------------------------------------------------
@@ -275,6 +405,7 @@ def action_get_next(refactor_list_data, state_dir):
275
405
  "infra_error_count": chosen_status_data.get("infra_error_count", 0),
276
406
  "resume_from_phase": chosen_status_data.get("resume_from_phase", None),
277
407
  }
408
+ result.update(continuation_metadata_summary(chosen_status_data))
278
409
  print(json.dumps(result, indent=2, ensure_ascii=False))
279
410
 
280
411
 
@@ -298,12 +429,15 @@ def action_update(args, refactor_list_path, state_dir):
298
429
 
299
430
  rs = load_refactor_status(state_dir, refactor_id)
300
431
 
432
+ current_list_status = get_refactor_status_from_list(refactor_list_path, refactor_id)
433
+
301
434
  # Track what status we write to refactor-list.json
302
- new_status = get_refactor_status_from_list(refactor_list_path, refactor_id)
435
+ new_status = current_list_status
303
436
 
304
437
  if session_status == "success":
305
438
  rs["infra_error_count"] = 0
306
439
  rs["last_infra_error_session_id"] = None
440
+ clear_pending_continuation_metadata(rs)
307
441
  new_status = "completed"
308
442
  rs["resume_from_phase"] = None
309
443
  err = update_refactor_in_list(refactor_list_path, refactor_id, "completed")
@@ -335,7 +469,7 @@ def action_update(args, refactor_list_path, state_dir):
335
469
  rs["infra_error_count"] = infra_error_count
336
470
  rs["last_infra_error_session_id"] = session_id
337
471
  rs["max_infra_retries"] = max_infra_retries
338
- rs["degraded_reason"] = "infra_error"
472
+ rs["degraded_reason"] = session_status
339
473
  if session_id:
340
474
  rs["last_session_id"] = session_id
341
475
  rs["resume_from_phase"] = None
@@ -347,6 +481,23 @@ def action_update(args, refactor_list_path, state_dir):
347
481
  else:
348
482
  new_status = "pending"
349
483
 
484
+ err = update_refactor_in_list(refactor_list_path, refactor_id, new_status)
485
+ if err:
486
+ error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
487
+ return
488
+ elif session_status == "context_overflow":
489
+ # Context overflow is continuation state, not code or infra retry state.
490
+ set_context_overflow_continuation_metadata(rs, args, session_id)
491
+ new_status = "in_progress"
492
+ if current_list_status != "in_progress":
493
+ err = update_refactor_in_list(refactor_list_path, refactor_id, "in_progress")
494
+ if err:
495
+ error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
496
+ return
497
+ elif session_status == "stalled_context_continuation":
498
+ # No-progress context-overflow stall pauses automation without consuming retry budgets.
499
+ set_stalled_context_continuation_metadata(rs, args, session_id)
500
+ new_status = "failed"
350
501
  err = update_refactor_in_list(refactor_list_path, refactor_id, new_status)
351
502
  if err:
352
503
  error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
@@ -415,6 +566,14 @@ def action_update(args, refactor_list_path, state_dir):
415
566
  summary["restart_policy"] = "infra_retry"
416
567
  summary["infra_error_count"] = rs.get("infra_error_count", 0)
417
568
  summary["artifacts_preserved"] = True
569
+ elif session_status == "context_overflow":
570
+ summary["restart_policy"] = "context_overflow_continuation"
571
+ summary.update(continuation_metadata_summary(rs))
572
+ summary["artifacts_preserved"] = True
573
+ elif session_status == "stalled_context_continuation":
574
+ summary["restart_policy"] = "needs_attention"
575
+ summary.update(continuation_metadata_summary(rs))
576
+ summary["artifacts_preserved"] = True
418
577
  elif session_status != "success":
419
578
  summary["restart_policy"] = "full_restart"
420
579
  summary["cleanup_performed"] = cleaned
@@ -442,7 +601,7 @@ def cleanup_refactor_artifacts(state_dir, refactor_id, project_root=None):
442
601
  cleaned = []
443
602
 
444
603
  # 1) Remove all session history
445
- sessions_dir = os.path.join(state_dir, "refactors", refactor_id, "sessions")
604
+ sessions_dir = os.path.join(state_dir, refactor_id, "sessions")
446
605
  sessions_deleted = 0
447
606
  if os.path.isdir(sessions_dir):
448
607
  for entry in os.listdir(sessions_dir):
@@ -453,7 +612,7 @@ def cleanup_refactor_artifacts(state_dir, refactor_id, project_root=None):
453
612
  cleaned.append("Deleted {} session(s) from {}".format(sessions_deleted, sessions_dir))
454
613
 
455
614
  # 2) Remove transient files under refactor dir (keep status.json)
456
- refactor_dir = os.path.join(state_dir, "refactors", refactor_id)
615
+ refactor_dir = os.path.join(state_dir, refactor_id)
457
616
  if os.path.isdir(refactor_dir):
458
617
  for entry in os.listdir(refactor_dir):
459
618
  if entry == "status.json" or entry == "sessions":
@@ -481,9 +640,47 @@ def cleanup_refactor_artifacts(state_dir, refactor_id, project_root=None):
481
640
  return cleaned
482
641
 
483
642
 
643
+ def _resolve_project_file(project_root, path):
644
+ if not path:
645
+ return None
646
+ if os.path.isabs(path):
647
+ target = os.path.abspath(path)
648
+ else:
649
+ target = os.path.abspath(os.path.join(project_root, path))
650
+ root = os.path.abspath(project_root)
651
+ try:
652
+ rel = os.path.relpath(target, root)
653
+ except ValueError:
654
+ return None
655
+ if rel == os.pardir or rel.startswith(os.pardir + os.sep):
656
+ return None
657
+ return target
658
+
659
+
660
+ def cleanup_continuation_artifacts(project_root, status_data, candidate_paths=None):
661
+ """Delete durable continuation handoff files for a manual clean reset."""
662
+ candidates = []
663
+ if isinstance(status_data, dict):
664
+ candidates.append(status_data.get("continuation_summary_path"))
665
+ candidates.extend(candidate_paths or [])
666
+
667
+ cleaned = []
668
+ seen = set()
669
+ for candidate in candidates:
670
+ target = _resolve_project_file(project_root, candidate)
671
+ if not target or target in seen:
672
+ continue
673
+ seen.add(target)
674
+ if os.path.basename(target) != "continuation-summary.md":
675
+ continue
676
+ if os.path.isfile(target):
677
+ os.remove(target)
678
+ cleaned.append("Deleted continuation artifact {}".format(target))
679
+ return cleaned
680
+
681
+
484
682
  def load_session_status(state_dir, refactor_id, session_id):
485
- session_status_path = os.path.join(
486
- state_dir, "refactors", refactor_id, "sessions",
683
+ session_status_path = os.path.join(state_dir, refactor_id, "sessions",
487
684
  session_id, "session-status.json"
488
685
  )
489
686
  data, err = load_json_file(session_status_path)
@@ -757,6 +954,7 @@ def action_reset(args, refactor_list_path, state_dir):
757
954
  rs["sessions"] = []
758
955
  rs["last_session_id"] = None
759
956
  rs["resume_from_phase"] = None
957
+ reset_continuation_metadata(rs)
760
958
  rs["updated_at"] = now_iso()
761
959
 
762
960
  err = save_refactor_status(state_dir, refactor_id, rs)
@@ -797,7 +995,7 @@ def action_clean(args, refactor_list_path, state_dir):
797
995
  cleaned = []
798
996
 
799
997
  # 1. Delete session history
800
- sessions_dir = os.path.join(state_dir, "refactors", refactor_id, "sessions")
998
+ sessions_dir = os.path.join(state_dir, refactor_id, "sessions")
801
999
  sessions_deleted = 0
802
1000
  if os.path.isdir(sessions_dir):
803
1001
  for entry in os.listdir(sessions_dir):
@@ -824,12 +1022,19 @@ def action_clean(args, refactor_list_path, state_dir):
824
1022
  old_status = get_refactor_status_from_list(refactor_list_path, refactor_id)
825
1023
  old_retry = rs.get("retry_count", 0)
826
1024
 
1025
+ continuation_candidates = [
1026
+ os.path.join(".prizmkit", "refactor", refactor_id, "continuation-summary.md"),
1027
+ os.path.join(".prizmkit", "specs", refactor_id, "continuation-summary.md"),
1028
+ ]
1029
+ cleaned.extend(cleanup_continuation_artifacts(project_root, rs, continuation_candidates))
1030
+
827
1031
  rs["retry_count"] = 0
828
1032
  rs["infra_error_count"] = 0
829
1033
  rs["last_infra_error_session_id"] = None
830
1034
  rs["sessions"] = []
831
1035
  rs["last_session_id"] = None
832
1036
  rs["resume_from_phase"] = None
1037
+ reset_continuation_metadata(rs)
833
1038
  rs["updated_at"] = now_iso()
834
1039
 
835
1040
  err = save_refactor_status(state_dir, refactor_id, rs)
@@ -905,10 +1110,11 @@ def action_start(args, refactor_list_path, state_dir):
905
1110
  error_out("Failed to save refactor status: {}".format(err))
906
1111
  return
907
1112
 
908
- err = update_refactor_in_list(refactor_list_path, refactor_id, "in_progress")
909
- if err:
910
- error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
911
- return
1113
+ if old_status != "in_progress":
1114
+ err = update_refactor_in_list(refactor_list_path, refactor_id, "in_progress")
1115
+ if err:
1116
+ error_out("Failed to update .prizmkit/plans/refactor-list.json: {}".format(err))
1117
+ return
912
1118
 
913
1119
  result = {
914
1120
  "action": "start",
@@ -1060,6 +1266,7 @@ def action_unskip(args, refactor_list_path, state_dir):
1060
1266
  rs["sessions"] = []
1061
1267
  rs["last_session_id"] = None
1062
1268
  rs["resume_from_phase"] = None
1269
+ reset_continuation_metadata(rs)
1063
1270
  rs["updated_at"] = now_iso()
1064
1271
  save_refactor_status(state_dir, rid, rs)
1065
1272
 
@@ -35,7 +35,7 @@ Test command:
35
35
  Known baseline failures:
36
36
  `{{BASELINE_FAILURES}}`
37
37
 
38
- If plan.md has more than 5 tasks, run `/compact` after completing every 3 tasks to manage context budget. If `/compact` is unavailable, continue without it.
38
+ If plan.md has more than 5 tasks, update durable checkpoints/artifacts after every 3 tasks, minimize output, and rely on runner continuation if context overflow occurs. In an interactive Claude Code session operated manually outside the headless pipeline, `/compact` may be used as an optional convenience only.
39
39
 
40
40
  ## Required Outputs
41
41
 
@@ -12,7 +12,7 @@ You are the **session orchestrator**. Implement Feature {{FEATURE_ID}}: "{{FEATU
12
12
 
13
13
  **CRITICAL**: You MUST NOT exit until ALL work is complete and committed.
14
14
 
15
- **Tier 1 — Single Agent**: You handle everything directly. No normal work subagents; the log-size monitor is the only allowed persistent background subagent. No TeamCreate.
15
+ **Tier 1 — Single Agent**: You handle everything directly. No normal work subagents. No TeamCreate.
16
16
 
17
17
  ### Feature Description
18
18
 
@@ -179,7 +179,7 @@ You know this project's tech stack. Identify ALL test commands that apply (e.g.,
179
179
  - Runs tests using `TEST_CMD` after each task
180
180
  - Writes '## Implementation Log' to `context-snapshot.md`
181
181
 
182
- **3b-compact.** Context management — if plan.md has more than 5 tasks, run `/compact` after completing every 3 tasks during implementation. This prevents context window exhaustion in long sessions. If `/compact` is not available (non-Claude CLI), skip this step.
182
+ **3b-checkpoint.** Context management — if plan.md has more than 5 tasks, update durable checkpoints/artifacts after every 3 tasks, minimize output, and continue. If context overflow occurs in a headless run, the runner starts a fresh continuation session from those checkpoints and artifacts. In an interactive Claude Code session operated manually outside the headless pipeline, `/compact` may be used as an optional convenience only.
183
183
 
184
184
  **3c.** After implement completes, verify:
185
185
  1. All tasks in plan.md are `[x]`
@@ -10,7 +10,7 @@
10
10
 
11
11
  You are the **session orchestrator**. Implement Feature {{FEATURE_ID}}: "{{FEATURE_TITLE}}".
12
12
 
13
- **CRITICAL**: You MUST NOT exit until ALL work is complete and committed. When you spawn normal work subagents, wait for each to finish (run_in_background=false). The log-size monitor is the only allowed persistent background subagent.
13
+ **CRITICAL**: You MUST NOT exit until ALL work is complete and committed. When you spawn normal work subagents, wait for each to finish (run_in_background=false).
14
14
 
15
15
  **Tier 2 — Dual Agent**: You handle context + planning directly. Then spawn Dev and Reviewer subagents. Spawn Dev and Reviewer agents via the Agent tool.
16
16
 
@@ -265,7 +265,7 @@ Prompt:
265
265
  > ⚠️ DO NOT re-read source files already listed in Section 4 File Manifest unless you need implementation detail beyond the interface summary.
266
266
  > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` for full context.
267
267
  > 2. Run `/prizmkit-implement` to execute the tasks in plan.md. Run tests with: `{{TEST_CMD}}`. Known baseline failures (pre-existing, not your fault): `{{BASELINE_FAILURES}}`.
268
- > 3. If plan.md has more than 5 tasks: run `/compact` after completing every 3 tasks to manage context budget. If `/compact` is unavailable, continue without it.
268
+ > 3. If plan.md has more than 5 tasks: update durable checkpoints/artifacts after every 3 tasks, minimize output, and rely on runner continuation if context overflow occurs. In an interactive Claude Code session operated manually outside the headless pipeline, `/compact` may be used as an optional convenience only.
269
269
  > 4. After implement completes, verify the '## Implementation Log' section was written to context-snapshot.md.
270
270
  > 5. Do NOT execute any git commands (no git add/commit/reset/push).
271
271
  > Do NOT exit until all tasks are [x] and the '## Implementation Log' section is written in context-snapshot.md."
@@ -702,7 +702,7 @@ Remove-Item -Force -ErrorAction SilentlyContinue .prizmkit/specs/{{FEATURE_SLUG}
702
702
  - Build context-snapshot.md FIRST; all subagents read it instead of re-reading source files
703
703
  - context-snapshot.md is append-only: orchestrator writes Sections 1-4, Dev appends Implementation Log, Reviewer appends Review Notes
704
704
  - Gate checks enforce Implementation Log and Review Notes are written before proceeding
705
- - Do NOT use `run_in_background=true` when spawning normal work subagents; the log-size monitor is the only allowed persistent background subagent
705
+ - Do NOT use `run_in_background=true` when spawning normal work subagents; headless recovery is handled by runner continuation from durable checkpoints/artifacts
706
706
  - `/prizmkit-committer` is mandatory, and must not be replaced with manual git commit commands
707
707
  - Do NOT run `git add`/`git commit` during Phase 1-5 — all changes are committed once in Phase 6
708
708
  - If any files remain after the commit, amend the existing commit — do NOT create a follow-up commit
@@ -10,7 +10,7 @@
10
10
 
11
11
  You are the **session orchestrator**. Implement Feature {{FEATURE_ID}}: "{{FEATURE_TITLE}}".
12
12
 
13
- **CRITICAL**: You MUST NOT exit until ALL work is complete and committed. When you spawn normal work subagents, wait for each to finish (run_in_background=false). The log-size monitor is the only allowed persistent background subagent. Do NOT spawn work agents in background and exit — that kills the session.
13
+ **CRITICAL**: You MUST NOT exit until ALL work is complete and committed. When you spawn normal work subagents, wait for each to finish (run_in_background=false). Do NOT spawn work agents in background and exit — that kills the session.
14
14
 
15
15
  **Tier 3 — Full Team**: For complex features, use the full pipeline (Phase 0–6) with Dev + Reviewer agents spawned via the Agent tool.
16
16
 
@@ -320,7 +320,7 @@ Prompt:
320
320
  > ⚠️ DO NOT re-read source files already listed in Section 4 File Manifest unless you need implementation detail beyond the interface summary.
321
321
  > 1. Read `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` for full context.
322
322
  > 2. Run `/prizmkit-implement` to execute the tasks in plan.md. Run tests with: `{{TEST_CMD}}`. Known baseline failures (pre-existing, not your fault): `{{BASELINE_FAILURES}}`.
323
- > 3. If plan.md has more than 5 tasks: run `/compact` after completing every 3 tasks to manage context budget. If `/compact` is unavailable, continue without it.
323
+ > 3. If plan.md has more than 5 tasks: update durable checkpoints/artifacts after every 3 tasks, minimize output, and rely on runner continuation if context overflow occurs. In an interactive Claude Code session operated manually outside the headless pipeline, `/compact` may be used as an optional convenience only.
324
324
  > 4. After implement completes, verify the '## Implementation Log' section was written to context-snapshot.md.
325
325
  > 5. Do NOT execute any git commands (no git add/commit/reset/push).
326
326
  > Do NOT exit until all tasks are [x] and the '## Implementation Log' section is written in context-snapshot.md."
@@ -783,7 +783,7 @@ Remove-Item -Force -ErrorAction SilentlyContinue .prizmkit/specs/{{FEATURE_SLUG}
783
783
  - Tier 3: full team — Dev (implementation) → Reviewer (review) — spawn agents directly via Agent tool
784
784
  - context-snapshot.md is append-only: orchestrator writes Sections 1-4, Dev appends Implementation Log, Reviewer appends Review Notes
785
785
  - Gate checks enforce Implementation Log and Review Notes are written before proceeding
786
- - Do NOT use `run_in_background=true` when spawning normal work agents; the log-size monitor is the only allowed persistent background subagent
786
+ - Do NOT use `run_in_background=true` when spawning normal work agents; headless recovery is handled by runner continuation from durable checkpoints/artifacts
787
787
  - Commit phase must use `/prizmkit-committer`; do NOT replace with manual git commit commands
788
788
  - Do NOT run `git add`/`git commit` during Phase 1-5 — all changes are committed once in Phase 6
789
789
  - If any files remain after the commit, amend the existing commit — do NOT create a follow-up commit
@@ -13,7 +13,7 @@ You are the **bug fix session agent**. Fix Bug {{BUG_ID}}: "{{BUG_TITLE}}".
13
13
 
14
14
  **CRITICAL**: You MUST NOT exit until ALL work is complete and committed.
15
15
 
16
- **SUBAGENT LIFECYCLE**: The log-size monitor is the only allowed persistent background subagent. Any normal work subagent must be awaited with `run_in_background=false`.
16
+ **SUBAGENT LIFECYCLE**: Any normal work subagent must be awaited with `run_in_background=false`. Do not spawn persistent background subagents for headless recovery.
17
17
 
18
18
  **NON-INTERACTIVE MODE**: There is NO human on the other end. NEVER ask for user confirmation, NEVER wait for user input. Make decisions autonomously and move forward.
19
19
 
@@ -12,7 +12,7 @@
12
12
 
13
13
  You are the **refactor session orchestrator**. Execute Refactor {{REFACTOR_ID}}: "{{REFACTOR_TITLE}}".
14
14
 
15
- **CRITICAL SESSION LIFECYCLE RULE**: You MUST NOT exit until ALL work is complete and session-status.json is written. When you spawn normal work subagents, you MUST **wait for each to finish** (run_in_background=false) before proceeding. The log-size monitor is the only allowed persistent background subagent. Do NOT spawn a work agent in the background and exit — that kills the session.
15
+ **CRITICAL SESSION LIFECYCLE RULE**: You MUST NOT exit until ALL work is complete and session-status.json is written. When you spawn normal work subagents, you MUST **wait for each to finish** (run_in_background=false) before proceeding. Do NOT spawn a work agent in the background and exit — that kills the session.
16
16
 
17
17
  **NON-INTERACTIVE MODE**: You are running in headless non-interactive mode. There is NO human on the other end. NEVER ask for user confirmation, NEVER wait for user input, NEVER use interactive prompts (e.g. "Would you like me to…"). If a skill has an interactive step (e.g. offer remediation, ask for approval), skip it and proceed autonomously. Make decisions based on the data available and move forward.
18
18
 
@@ -185,7 +185,7 @@ Evidence must cover affected UI render, primary user interactions, behavior-sens
185
185
 
186
186
  {{END_IF_BROWSER_INTERACTION}}
187
187
 
188
- 7. If the refactor involves multiple files: run `/compact` after completing half the tasks to free context budget. If `/compact` is unavailable, continue without it.
188
+ 7. If the refactor involves multiple files: update durable checkpoints/artifacts at the midpoint, minimize output, and rely on runner continuation if context overflow occurs. In an interactive Claude Code session operated manually outside the headless pipeline, `/compact` may be used as an optional convenience only.
189
189
  8. After all tasks complete, run the full test suite one final time
190
190
  "
191
191
  - **Wait for Dev to return**
@@ -337,4 +337,4 @@ Write to: `{{SESSION_STATUS_PATH}}`
337
337
  - **Commit with** `refactor(<scope>):` prefix, NOT `feat:` or `fix:`
338
338
  - **Run full retrospective** (Job 1 + Job 2) — refactoring changes code structure
339
339
  - ALWAYS write session-status.json before exiting
340
- - Do NOT use `run_in_background=true` when spawning normal work agents; the log-size monitor is the only allowed persistent background subagent
340
+ - Do NOT use `run_in_background=true` when spawning normal work agents; headless recovery is handled by runner continuation from durable checkpoints/artifacts
@@ -1,78 +1,41 @@
1
- ## Session Log Budget Monitoring (PROACTIVE)
1
+ ## Session Log Budget Awareness (CHECKPOINT GUIDANCE)
2
2
 
3
- Your session log grows with every tool call and subagent spawn.
4
- To prevent context exhaustion, **spawn a background monitoring subagent at session start**.
3
+ Your session log grows with every tool call and agent interaction. Use this
4
+ section as passive checkpoint guidance only; do not spawn a background helper for
5
+ log-size checks.
5
6
 
6
- ### How to Set Up the Monitor
7
+ ### Checkpoint Before Large Work Batches
7
8
 
8
- 1. **AS THE VERY FIRST ACTION** (before Phase 0), spawn a monitoring subagent
9
- with `run_in_background: true` and this task:
9
+ - `MAX_LOG_SIZE` controls whether this advisory section is included. It is not a
10
+ runtime recovery mechanism.
11
+ - Before major phases or large task batches, update durable artifacts that a
12
+ continuation session can trust: plan/task checkboxes, context snapshots,
13
+ implementation or review notes, workflow checkpoints, session status, and test
14
+ reports where applicable.
15
+ - Keep command output small. Capture large outputs to temporary files and read
16
+ only filtered summaries needed for the current decision.
17
+ - Prefer already-built context snapshots and manifests over broad source-file
18
+ re-reads.
10
19
 
11
- ```
12
- Run this command and keep it running:
13
- $psHost = if (Get-Command pwsh -ErrorAction SilentlyContinue) { 'pwsh' } else { 'powershell.exe' }
14
- & $psHost -NoProfile -File {{LOG_MONITOR_SCRIPT}} {{SESSION_LOG_PATH}} {{MAX_LOG_SIZE}} {{LOG_MONITOR_POLL_INTERVAL}} {{LOG_MONITOR_STATUS_FILE}} {{LOG_MONITOR_BASELINE_FILE}}
15
- ```
20
+ ### Headless Recovery Source of Truth
16
21
 
17
- The subagent MUST use `run_in_background: true`. It writes a JSON status
18
- file every {{LOG_MONITOR_POLL_INTERVAL}} seconds.
22
+ - Headless recovery must rely on durable checkpoints and artifacts, not an
23
+ interactive slash command.
24
+ - If context overflow still occurs, the runner detects the overflow and starts a
25
+ fresh continuation session from checkpoint files and durable artifacts.
26
+ - Durable checkpoint files and artifacts are the source of truth for what was
27
+ completed, what remains, and the tests or review gates already run.
19
28
 
20
- 2. **BEFORE EACH MAJOR PHASE** (Phase 0, 1, 2, ...), read the status:
29
+ ### Interactive Claude Code Note
21
30
 
22
- ```powershell
23
- if (Test-Path {{LOG_MONITOR_STATUS_FILE}}) { Get-Content {{LOG_MONITOR_STATUS_FILE}} } else { '{"status":"OK"}' }
24
- ```
25
-
26
- The status file contains structured diagnostics:
27
-
28
- ```json
29
- {
30
- "status": "OK | COMPACT_NEEDED",
31
- "total_bytes": <current session.log size>,
32
- "baseline_bytes": <size after last /compact>,
33
- "effective_bytes": <total - baseline, incremental growth>,
34
- "threshold_bytes": <{{MAX_LOG_SIZE}}>,
35
- "overage_bytes": <effective - threshold, 0 when OK>,
36
- "usage_pct": <effective / threshold * 100>
37
- }
38
- ```
39
-
40
- Extract fields for decision-making:
41
- ```powershell
42
- $data = Get-Content {{LOG_MONITOR_STATUS_FILE}} | ConvertFrom-Json
43
- $status = $data.status
44
- $effective = $data.effective_bytes
45
- $overage = $data.overage_bytes
46
- $usage = $data.usage_pct
47
- ```
48
-
49
- 3. **On COMPACT_NEEDED** (effective_bytes > {{MAX_LOG_SIZE}} bytes, {{MAX_LOG_SIZE_HUMAN}}):
50
- - Check `overage_bytes` to decide urgency:
51
- - **Minor overage** (< 512KB): complete the current sub-step, update durable workflow checkpoint artifacts, write baseline, `/compact`
52
- - **Major overage** (>= 512KB): update durable workflow checkpoint artifacts, write baseline, `/compact` — do NOT start new work
53
- - Write baseline before `/compact`:
54
- ```powershell
55
- (Get-Item {{SESSION_LOG_PATH}}).Length | Out-File -NoNewline {{LOG_MONITOR_BASELINE_FILE}}
56
- ```
57
- - Execute `/compact`
58
- - Continue the workflow after `/compact`; re-read this status file before the next major phase
59
-
60
- ### How the Baseline Prevents Infinite Compaction Loops
61
-
62
- - Before the first `/compact`: baseline = 0, effective = full log size → triggers when log exceeds threshold
63
- - After `/compact`: baseline = current log size, effective ≈ 0 → status resets to OK
64
- - The monitor only triggers again when **new** log growth since the last compact exceeds the threshold
65
- - Each `/compact` resets the baseline, breaking the infinite loop
31
+ - `/compact` may help when a human is manually operating an interactive Claude
32
+ Code session.
33
+ - `/compact` is optional interactive convenience only. It must not be required
34
+ for headless recovery and must not be delegated to a background helper.
66
35
 
67
36
  ### Log Growth Reduction Tips
68
37
 
69
- - **Re-read context-snapshot.md instead of source files** already in context
70
- - **Filter command output** pipe to `Select-Object -Last 20` or `Select-String`, never full output
71
- - **Limit subagent prompts** shorter, focused prompts = shorter transcripts
72
- - **Checkpoint often** update durable workflow checkpoint artifacts before `/compact`
73
-
74
- ### What Survives
75
-
76
- - All git commits are permanent
77
- - The workflow checkpoint is preserved and auto-resumed
78
- - `/compact` compresses context without losing progress
38
+ - Reuse context-snapshot.md instead of re-reading files already summarized there.
39
+ - Filter command output before loading it into context.
40
+ - Keep agent prompts focused and avoid unnecessary transcript expansion.
41
+ - Checkpoint often so automatic continuation can resume from durable state.
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "status": {
17
17
  "type": "string",
18
- "enum": ["success", "partial", "failed", "commit_missing", "docs_missing", "merge_conflict"]
18
+ "enum": ["success", "partial", "failed", "commit_missing", "docs_missing", "merge_conflict", "context_overflow"]
19
19
  },
20
20
  "completed_phases": {
21
21
  "type": "array",
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.1.98",
2
+ "version": "1.1.100",
3
3
  "skills": {
4
4
  "prizm-kit": {
5
5
  "description": "Full-lifecycle dev toolkit. Covers spec-driven development, Prizm context docs, code quality, debugging, deployment, and knowledge management.",
@@ -245,9 +245,9 @@ Detect user intent from their message, then follow the corresponding workflow:
245
245
  4. **For per-bug session logs** (when user asks about a specific bug):
246
246
  ```bash
247
247
  # Check bug status for last session ID
248
- cat .prizmkit/state/bugfix/bugs/<BUG_ID>/status.json 2>/dev/null
248
+ cat .prizmkit/state/bugfix/<BUG_ID>/status.json 2>/dev/null
249
249
  # Then tail that bug's session log
250
- tail -100 .prizmkit/state/bugfix/bugs/<BUG_ID>/sessions/<SESSION_ID>/logs/session.log
250
+ tail -100 .prizmkit/state/bugfix/<BUG_ID>/sessions/<SESSION_ID>/logs/session.log
251
251
  ```
252
252
 
253
253
  ---
@@ -285,9 +285,9 @@ Detect user intent from their message, then follow the corresponding workflow:
285
285
  4. **For per-feature session logs** (when user asks about a specific feature):
286
286
  ```bash
287
287
  # Check feature status for last session ID
288
- cat .prizmkit/state/features/features/<FEATURE_ID>/status.json 2>/dev/null
288
+ cat .prizmkit/state/features/<FEATURE_ID>/status.json 2>/dev/null
289
289
  # Then tail that feature's session log
290
- tail -100 .prizmkit/state/features/features/<FEATURE_ID>/sessions/<SESSION_ID>/logs/session.log
290
+ tail -100 .prizmkit/state/features/<FEATURE_ID>/sessions/<SESSION_ID>/logs/session.log
291
291
  ```
292
292
 
293
293
  ---