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
@@ -42,6 +42,8 @@ SESSION_STATUS_VALUES = [
42
42
  "crashed",
43
43
  "timed_out",
44
44
  "infra_error",
45
+ "context_overflow",
46
+ "stalled_context_continuation",
45
47
  "commit_missing",
46
48
  "docs_missing",
47
49
  "merge_conflict",
@@ -78,6 +80,12 @@ def parse_args():
78
80
  parser.add_argument("--max-retries", type=int, default=3, help="Maximum code retry count (default: 3)")
79
81
  parser.add_argument("--max-infra-retries", type=int, default=3, help="Maximum infrastructure retry count (default: 3)")
80
82
  parser.add_argument("--project-root", default=None, help="Project root directory. Required for 'clean' action.")
83
+ parser.add_argument("--active-dev-branch", default=None, help="Development branch preserved for continuation after context overflow.")
84
+ parser.add_argument("--base-branch", default=None, help="Original/base branch for continuation branch reuse.")
85
+ parser.add_argument("--last-fatal-error-code", default=None, help="Fatal runtime error code associated with continuation.")
86
+ parser.add_argument("--continuation-summary-path", default=None, help="Optional continuation summary artifact path.")
87
+ parser.add_argument("--no-progress-count", type=int, default=None, help="Consecutive context-overflow sessions without objective progress.")
88
+ parser.add_argument("--progress-fingerprint", default=None, help="JSON progress fingerprint captured after the session.")
81
89
  return parser.parse_args()
82
90
 
83
91
 
@@ -92,7 +100,7 @@ def load_bug_status(state_dir, bug_id):
92
100
  The 'status' field is NOT included — status lives exclusively
93
101
  in bug-fix-list.json.
94
102
  """
95
- status_path = os.path.join(state_dir, "bugs", bug_id, "status.json")
103
+ status_path = os.path.join(state_dir, bug_id, "status.json")
96
104
  if not os.path.isfile(status_path):
97
105
  now = now_iso()
98
106
  return {
@@ -133,7 +141,7 @@ def save_bug_status(state_dir, bug_id, status_data):
133
141
  """Write the status.json for a bug (runtime fields only)."""
134
142
  # Defensively strip status — it belongs in bug-fix-list.json
135
143
  status_data.pop("status", None)
136
- status_path = os.path.join(state_dir, "bugs", bug_id, "status.json")
144
+ status_path = os.path.join(state_dir, bug_id, "status.json")
137
145
  return write_json_file(status_path, status_data)
138
146
 
139
147
 
@@ -164,6 +172,128 @@ def update_bug_in_list(bug_list_path, bug_id, new_status):
164
172
  return write_json_file(bug_list_path, data)
165
173
 
166
174
 
175
+ CONTINUATION_PENDING_FIELDS = [
176
+ "active_dev_branch",
177
+ "base_branch",
178
+ "continuation_pending",
179
+ "continuation_reason",
180
+ "last_context_overflow_session_id",
181
+ "previous_session_id",
182
+ "last_fatal_error_code",
183
+ "continuation_summary_path",
184
+ "no_progress_count",
185
+ "last_progress_fingerprint",
186
+ "needs_attention",
187
+ "stalled_context_continuation",
188
+ "stalled_reason",
189
+ ]
190
+
191
+ CONTINUATION_COUNTER_FIELDS = [
192
+ "context_overflow_count",
193
+ "continuation_count",
194
+ ]
195
+
196
+
197
+ def has_pending_continuation_metadata(status_data):
198
+ """Return True when runtime state still has pending continuation metadata."""
199
+ return any(key in status_data for key in CONTINUATION_PENDING_FIELDS)
200
+
201
+
202
+ def clear_pending_continuation_metadata(status_data):
203
+ """Clear branch/pending continuation fields while preserving observability counters."""
204
+ for key in CONTINUATION_PENDING_FIELDS:
205
+ status_data.pop(key, None)
206
+
207
+
208
+ def reset_continuation_metadata(status_data):
209
+ """Clear all continuation runtime metadata, including manual-reset counters."""
210
+ clear_pending_continuation_metadata(status_data)
211
+ for key in CONTINUATION_COUNTER_FIELDS:
212
+ status_data.pop(key, None)
213
+
214
+
215
+ STALL_REASON = "context_overflow_without_git_checkpoint_or_artifact_progress"
216
+
217
+
218
+ def _load_progress_fingerprint(raw):
219
+ if not raw:
220
+ return None
221
+ try:
222
+ return json.loads(raw)
223
+ except (TypeError, ValueError):
224
+ return {"unparsed": str(raw)}
225
+
226
+
227
+ def _set_continuation_common(status_data, args, session_id):
228
+ if args.active_dev_branch:
229
+ status_data["active_dev_branch"] = args.active_dev_branch
230
+ if args.base_branch:
231
+ status_data["base_branch"] = args.base_branch
232
+ status_data["last_context_overflow_session_id"] = session_id
233
+ status_data["previous_session_id"] = session_id
234
+ status_data["last_fatal_error_code"] = args.last_fatal_error_code or "context_overflow"
235
+ if args.continuation_summary_path:
236
+ status_data["continuation_summary_path"] = args.continuation_summary_path
237
+ else:
238
+ status_data.pop("continuation_summary_path", None)
239
+ if args.no_progress_count is not None:
240
+ status_data["no_progress_count"] = max(0, args.no_progress_count)
241
+ fingerprint = _load_progress_fingerprint(args.progress_fingerprint)
242
+ if fingerprint is not None:
243
+ status_data["last_progress_fingerprint"] = fingerprint
244
+ status_data["last_infra_error_session_id"] = None
245
+ status_data["resume_from_phase"] = None
246
+ if session_id:
247
+ status_data["last_session_id"] = session_id
248
+
249
+
250
+ def set_context_overflow_continuation_metadata(status_data, args, session_id):
251
+ """Record continuation metadata for a context-overflow outcome in status.json."""
252
+ status_data["context_overflow_count"] = status_data.get("context_overflow_count", 0) + 1
253
+ status_data["continuation_count"] = status_data.get("continuation_count", 0) + 1
254
+ status_data["continuation_pending"] = True
255
+ status_data["continuation_reason"] = "context_overflow"
256
+ status_data.pop("needs_attention", None)
257
+ status_data.pop("stalled_context_continuation", None)
258
+ status_data.pop("stalled_reason", None)
259
+ _set_continuation_common(status_data, args, session_id)
260
+
261
+
262
+ def set_stalled_context_continuation_metadata(status_data, args, session_id):
263
+ """Record no-progress context-overflow stall without consuming retry budgets."""
264
+ status_data["context_overflow_count"] = status_data.get("context_overflow_count", 0) + 1
265
+ status_data["continuation_count"] = status_data.get("continuation_count", 0) + 1
266
+ _set_continuation_common(status_data, args, session_id)
267
+ status_data["continuation_pending"] = False
268
+ status_data["continuation_reason"] = STALL_REASON
269
+ status_data["needs_attention"] = True
270
+ status_data["stalled_context_continuation"] = True
271
+ status_data["stalled_reason"] = STALL_REASON
272
+ if args.no_progress_count is None or args.no_progress_count < 2:
273
+ status_data["no_progress_count"] = 2
274
+
275
+
276
+ def continuation_metadata_summary(status_data):
277
+ """Return additive continuation fields for CLI JSON outputs."""
278
+ return {
279
+ "active_dev_branch": status_data.get("active_dev_branch"),
280
+ "base_branch": status_data.get("base_branch"),
281
+ "continuation_pending": status_data.get("continuation_pending", False),
282
+ "continuation_reason": status_data.get("continuation_reason"),
283
+ "last_context_overflow_session_id": status_data.get("last_context_overflow_session_id"),
284
+ "last_fatal_error_code": status_data.get("last_fatal_error_code"),
285
+ "previous_session_id": status_data.get("previous_session_id"),
286
+ "context_overflow_count": status_data.get("context_overflow_count", 0),
287
+ "continuation_count": status_data.get("continuation_count", 0),
288
+ "no_progress_count": status_data.get("no_progress_count", 0),
289
+ "last_progress_fingerprint": status_data.get("last_progress_fingerprint"),
290
+ "needs_attention": status_data.get("needs_attention", False),
291
+ "stalled_context_continuation": status_data.get("stalled_context_continuation", False),
292
+ "stalled_reason": status_data.get("stalled_reason"),
293
+ "continuation_summary_path": status_data.get("continuation_summary_path"),
294
+ }
295
+
296
+
167
297
  # ---------------------------------------------------------------------------
168
298
  # Action: get_next
169
299
  # ---------------------------------------------------------------------------
@@ -244,6 +374,7 @@ def action_get_next(bug_list_data, state_dir):
244
374
  "infra_error_count": chosen_status_data.get("infra_error_count", 0),
245
375
  "resume_from_phase": chosen_status_data.get("resume_from_phase", None),
246
376
  }
377
+ result.update(continuation_metadata_summary(chosen_status_data))
247
378
  print(json.dumps(result, indent=2, ensure_ascii=False))
248
379
 
249
380
 
@@ -267,12 +398,15 @@ def action_update(args, bug_list_path, state_dir):
267
398
 
268
399
  bs = load_bug_status(state_dir, bug_id)
269
400
 
401
+ current_list_status = get_bug_status_from_list(bug_list_path, bug_id)
402
+
270
403
  # Track what status we write to bug-fix-list.json
271
- new_status = get_bug_status_from_list(bug_list_path, bug_id)
404
+ new_status = current_list_status
272
405
 
273
406
  if session_status == "success":
274
407
  bs["infra_error_count"] = 0
275
408
  bs["last_infra_error_session_id"] = None
409
+ clear_pending_continuation_metadata(bs)
276
410
  new_status = "completed"
277
411
  bs["resume_from_phase"] = None
278
412
  err = update_bug_in_list(bug_list_path, bug_id, "completed")
@@ -304,7 +438,7 @@ def action_update(args, bug_list_path, state_dir):
304
438
  bs["infra_error_count"] = infra_error_count
305
439
  bs["last_infra_error_session_id"] = session_id
306
440
  bs["max_infra_retries"] = max_infra_retries
307
- bs["degraded_reason"] = "infra_error"
441
+ bs["degraded_reason"] = session_status
308
442
  if session_id:
309
443
  bs["last_session_id"] = session_id
310
444
  bs["resume_from_phase"] = None
@@ -316,6 +450,23 @@ def action_update(args, bug_list_path, state_dir):
316
450
  else:
317
451
  new_status = "pending"
318
452
 
453
+ err = update_bug_in_list(bug_list_path, bug_id, new_status)
454
+ if err:
455
+ error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
456
+ return
457
+ elif session_status == "context_overflow":
458
+ # Context overflow is continuation state, not code or infra retry state.
459
+ set_context_overflow_continuation_metadata(bs, args, session_id)
460
+ new_status = "in_progress"
461
+ if current_list_status != "in_progress":
462
+ err = update_bug_in_list(bug_list_path, bug_id, "in_progress")
463
+ if err:
464
+ error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
465
+ return
466
+ elif session_status == "stalled_context_continuation":
467
+ # No-progress context-overflow stall pauses automation without consuming retry budgets.
468
+ set_stalled_context_continuation_metadata(bs, args, session_id)
469
+ new_status = "needs_info"
319
470
  err = update_bug_in_list(bug_list_path, bug_id, new_status)
320
471
  if err:
321
472
  error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
@@ -375,6 +526,14 @@ def action_update(args, bug_list_path, state_dir):
375
526
  summary["restart_policy"] = "infra_retry"
376
527
  summary["infra_error_count"] = bs.get("infra_error_count", 0)
377
528
  summary["artifacts_preserved"] = True
529
+ elif session_status == "context_overflow":
530
+ summary["restart_policy"] = "context_overflow_continuation"
531
+ summary.update(continuation_metadata_summary(bs))
532
+ summary["artifacts_preserved"] = True
533
+ elif session_status == "stalled_context_continuation":
534
+ summary["restart_policy"] = "needs_attention"
535
+ summary.update(continuation_metadata_summary(bs))
536
+ summary["artifacts_preserved"] = True
378
537
  elif session_status != "success":
379
538
  summary["restart_policy"] = "full_restart"
380
539
  summary["cleanup_performed"] = cleaned
@@ -402,7 +561,7 @@ def cleanup_bug_artifacts(state_dir, bug_id, project_root=None):
402
561
  cleaned = []
403
562
 
404
563
  # 1) Remove all session history
405
- sessions_dir = os.path.join(state_dir, "bugs", bug_id, "sessions")
564
+ sessions_dir = os.path.join(state_dir, bug_id, "sessions")
406
565
  sessions_deleted = 0
407
566
  if os.path.isdir(sessions_dir):
408
567
  for entry in os.listdir(sessions_dir):
@@ -413,7 +572,7 @@ def cleanup_bug_artifacts(state_dir, bug_id, project_root=None):
413
572
  cleaned.append("Deleted {} session(s) from {}".format(sessions_deleted, sessions_dir))
414
573
 
415
574
  # 2) Remove transient files under bug dir (keep status.json)
416
- bug_dir = os.path.join(state_dir, "bugs", bug_id)
575
+ bug_dir = os.path.join(state_dir, bug_id)
417
576
  if os.path.isdir(bug_dir):
418
577
  for entry in os.listdir(bug_dir):
419
578
  if entry == "status.json" or entry == "sessions":
@@ -445,9 +604,47 @@ def cleanup_bug_artifacts(state_dir, bug_id, project_root=None):
445
604
  return cleaned
446
605
 
447
606
 
607
+ def _resolve_project_file(project_root, path):
608
+ if not path:
609
+ return None
610
+ if os.path.isabs(path):
611
+ target = os.path.abspath(path)
612
+ else:
613
+ target = os.path.abspath(os.path.join(project_root, path))
614
+ root = os.path.abspath(project_root)
615
+ try:
616
+ rel = os.path.relpath(target, root)
617
+ except ValueError:
618
+ return None
619
+ if rel == os.pardir or rel.startswith(os.pardir + os.sep):
620
+ return None
621
+ return target
622
+
623
+
624
+ def cleanup_continuation_artifacts(project_root, status_data, candidate_paths=None):
625
+ """Delete durable continuation handoff files for a manual clean reset."""
626
+ candidates = []
627
+ if isinstance(status_data, dict):
628
+ candidates.append(status_data.get("continuation_summary_path"))
629
+ candidates.extend(candidate_paths or [])
630
+
631
+ cleaned = []
632
+ seen = set()
633
+ for candidate in candidates:
634
+ target = _resolve_project_file(project_root, candidate)
635
+ if not target or target in seen:
636
+ continue
637
+ seen.add(target)
638
+ if os.path.basename(target) != "continuation-summary.md":
639
+ continue
640
+ if os.path.isfile(target):
641
+ os.remove(target)
642
+ cleaned.append("Deleted continuation artifact {}".format(target))
643
+ return cleaned
644
+
645
+
448
646
  def load_session_status(state_dir, bug_id, session_id):
449
- session_status_path = os.path.join(
450
- state_dir, "bugs", bug_id, "sessions",
647
+ session_status_path = os.path.join(state_dir, bug_id, "sessions",
451
648
  session_id, "session-status.json"
452
649
  )
453
650
  data, err = load_json_file(session_status_path)
@@ -609,6 +806,7 @@ def action_reset(args, bug_list_path, state_dir):
609
806
  bs["sessions"] = []
610
807
  bs["last_session_id"] = None
611
808
  bs["resume_from_phase"] = None
809
+ reset_continuation_metadata(bs)
612
810
  bs["updated_at"] = now_iso()
613
811
 
614
812
  err = save_bug_status(state_dir, bug_id, bs)
@@ -649,7 +847,7 @@ def action_clean(args, bug_list_path, state_dir):
649
847
  cleaned = []
650
848
 
651
849
  # 1. Delete session history
652
- sessions_dir = os.path.join(state_dir, "bugs", bug_id, "sessions")
850
+ sessions_dir = os.path.join(state_dir, bug_id, "sessions")
653
851
  sessions_deleted = 0
654
852
  if os.path.isdir(sessions_dir):
655
853
  for entry in os.listdir(sessions_dir):
@@ -680,12 +878,19 @@ def action_clean(args, bug_list_path, state_dir):
680
878
  old_status = get_bug_status_from_list(bug_list_path, bug_id)
681
879
  old_retry = bs.get("retry_count", 0)
682
880
 
881
+ continuation_candidates = [
882
+ os.path.join(".prizmkit", "bugfix", bug_id, "continuation-summary.md"),
883
+ os.path.join(".prizmkit", "specs", bug_id, "continuation-summary.md"),
884
+ ]
885
+ cleaned.extend(cleanup_continuation_artifacts(project_root, bs, continuation_candidates))
886
+
683
887
  bs["retry_count"] = 0
684
888
  bs["infra_error_count"] = 0
685
889
  bs["last_infra_error_session_id"] = None
686
890
  bs["sessions"] = []
687
891
  bs["last_session_id"] = None
688
892
  bs["resume_from_phase"] = None
893
+ reset_continuation_metadata(bs)
689
894
  bs["updated_at"] = now_iso()
690
895
 
691
896
  err = save_bug_status(state_dir, bug_id, bs)
@@ -761,10 +966,11 @@ def action_start(args, bug_list_path, state_dir):
761
966
  error_out("Failed to save bug status: {}".format(err))
762
967
  return
763
968
 
764
- err = update_bug_in_list(bug_list_path, bug_id, "in_progress")
765
- if err:
766
- error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
767
- return
969
+ if old_status != "in_progress":
970
+ err = update_bug_in_list(bug_list_path, bug_id, "in_progress")
971
+ if err:
972
+ error_out("Failed to update .prizmkit/plans/bug-fix-list.json: {}".format(err))
973
+ return
768
974
 
769
975
  result = {
770
976
  "action": "start",
@@ -854,6 +1060,7 @@ def action_unskip(args, bug_list_path, state_dir):
854
1060
  bs["sessions"] = []
855
1061
  bs["last_session_id"] = None
856
1062
  bs["resume_from_phase"] = None
1063
+ reset_continuation_metadata(bs)
857
1064
  bs["updated_at"] = now_iso()
858
1065
  save_bug_status(state_dir, bid, bs)
859
1066