prizmkit 1.0.85 → 1.0.87

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.
@@ -1,5 +1,5 @@
1
1
  {
2
- "frameworkVersion": "1.0.85",
3
- "bundledAt": "2026-03-22T07:41:52.990Z",
4
- "bundledFrom": "cf22ce6"
2
+ "frameworkVersion": "1.0.87",
3
+ "bundledAt": "2026-03-22T10:36:51.328Z",
4
+ "bundledFrom": "35c970f"
5
5
  }
@@ -9,6 +9,7 @@
9
9
  # Functions:
10
10
  # branch_create — Create and checkout a new branch
11
11
  # branch_return — Checkout back to original branch
12
+ # branch_merge — Merge dev branch into original and optionally push
12
13
  #
13
14
  # Environment:
14
15
  # DEV_BRANCH — Optional custom branch name override
@@ -74,3 +75,55 @@ branch_return() {
74
75
  log_info "Returned to branch: $original_branch"
75
76
  return 0
76
77
  }
78
+
79
+ # branch_merge <project_root> <dev_branch> <original_branch> [auto_push]
80
+ #
81
+ # Merges dev_branch into original_branch, then optionally pushes.
82
+ # Steps:
83
+ # 1. Checkout original_branch
84
+ # 2. Merge dev_branch (fast-forward when possible)
85
+ # 3. Push to remote if auto_push == "1"
86
+ # 4. Delete dev_branch (local only, it's been merged)
87
+ #
88
+ # Returns 0 on success, 1 on failure.
89
+ branch_merge() {
90
+ local project_root="$1"
91
+ local dev_branch="$2"
92
+ local original_branch="$3"
93
+ local auto_push="${4:-0}"
94
+
95
+ # Step 1: Checkout original branch
96
+ if ! git -C "$project_root" checkout "$original_branch" 2>/dev/null; then
97
+ log_error "Failed to checkout $original_branch for merge"
98
+ return 1
99
+ fi
100
+
101
+ # Step 2: Merge dev branch
102
+ log_info "Merging $dev_branch into $original_branch..."
103
+ if ! git -C "$project_root" merge "$dev_branch" 2>&1; then
104
+ log_error "Merge failed — resolve conflicts manually:"
105
+ log_error " git checkout $original_branch && git merge $dev_branch"
106
+ # Return to dev branch so state is not lost
107
+ git -C "$project_root" merge --abort 2>/dev/null || true
108
+ git -C "$project_root" checkout "$dev_branch" 2>/dev/null || true
109
+ return 1
110
+ fi
111
+
112
+ log_success "Merged $dev_branch into $original_branch"
113
+
114
+ # Step 3: Push if AUTO_PUSH enabled
115
+ if [[ "$auto_push" == "1" ]]; then
116
+ log_info "Pushing $original_branch to remote..."
117
+ if git -C "$project_root" push 2>/dev/null; then
118
+ log_success "Pushed $original_branch to remote"
119
+ else
120
+ log_warn "Push failed — run 'git push' manually"
121
+ fi
122
+ fi
123
+
124
+ # Step 4: Delete merged dev branch
125
+ git -C "$project_root" branch -d "$dev_branch" 2>/dev/null && \
126
+ log_info "Deleted merged branch: $dev_branch" || true
127
+
128
+ return 0
129
+ }
@@ -328,21 +328,50 @@ fi
328
328
 
329
329
  SESSION_STATUS_FILE="$SESSION_DIR/session-status.json"
330
330
 
331
+ # ── Determine session outcome from observable signals ──────────────
332
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
333
+
331
334
  if [[ $EXIT_CODE -eq 124 ]]; then
332
335
  log_warn "Session timed out after ${SESSION_TIMEOUT}s"
333
336
  SESSION_STATUS="timed_out"
334
- elif [[ -f "$SESSION_STATUS_FILE" ]]; then
335
- SESSION_STATUS=$(python3 "$SCRIPTS_DIR/check-session-status.py" \
336
- --status-file "$SESSION_STATUS_FILE" 2>/dev/null) || SESSION_STATUS="crashed"
337
- else
338
- log_warn "Session ended without status file"
337
+ elif [[ $EXIT_CODE -ne 0 ]]; then
338
+ log_warn "Session exited with code $EXIT_CODE"
339
339
  SESSION_STATUS="crashed"
340
+ else
341
+ # Exit code 0 — check if the session produced commits
342
+ SESSION_START_ISO=$(python3 -c "
343
+ import os, sys
344
+ from datetime import datetime, timezone
345
+ p = sys.argv[1]
346
+ if os.path.isdir(p):
347
+ ts = os.path.getctime(p)
348
+ print(datetime.fromtimestamp(ts, tz=timezone.utc).strftime('%Y-%m-%dT%H:%M:%SZ'))
349
+ else:
350
+ print('')
351
+ " "$SESSION_DIR" 2>/dev/null) || SESSION_START_ISO=""
352
+
353
+ HAS_COMMITS=""
354
+ if [[ -n "$SESSION_START_ISO" ]] && git -C "$PROJECT_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
355
+ HAS_COMMITS=$(git -C "$PROJECT_ROOT" log --since="$SESSION_START_ISO" --oneline --grep="$BUG_ID" 2>/dev/null | head -1)
356
+ fi
357
+
358
+ if [[ -n "$HAS_COMMITS" ]]; then
359
+ SESSION_STATUS="success"
360
+ else
361
+ UNCOMMITTED=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null | head -1 || true)
362
+ if [[ -n "$UNCOMMITTED" ]]; then
363
+ log_warn "Session exited cleanly but produced no commits (uncommitted changes found)"
364
+ SESSION_STATUS="commit_missing"
365
+ else
366
+ log_warn "Session exited cleanly but produced no commits and no changes"
367
+ SESSION_STATUS="crashed"
368
+ fi
369
+ fi
340
370
  fi
341
371
 
372
+ # ── Post-success validation ──────────────────────────────────────────
342
373
  if [[ "$SESSION_STATUS" == "success" ]]; then
343
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
344
374
  if git -C "$PROJECT_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
345
- # Auto-commit any remaining dirty files produced during the session
346
375
  DIRTY_FILES=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null || true)
347
376
  if [[ -n "$DIRTY_FILES" ]]; then
348
377
  log_info "Auto-committing remaining session artifacts..."
@@ -350,11 +379,9 @@ if [[ "$SESSION_STATUS" == "success" ]]; then
350
379
  git -C "$PROJECT_ROOT" commit -m "chore($BUG_ID): include remaining session artifacts" 2>/dev/null || true
351
380
  fi
352
381
 
353
- # Re-check: if still dirty after auto-commit, flag as failed
354
382
  DIRTY_FILES=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null || true)
355
383
  if [[ -n "$DIRTY_FILES" ]]; then
356
- if [[ -n "$DIRTY_FILES" ]]; then
357
- log_error "Session reported success but git working tree is not clean."
384
+ log_error "Git working tree still not clean after auto-commit."
358
385
  echo "$DIRTY_FILES" | sed 's/^/ - /'
359
386
  SESSION_STATUS="failed"
360
387
  fi
@@ -340,21 +340,18 @@ fi
340
340
 
341
341
  SESSION_STATUS_FILE="$SESSION_DIR/session-status.json"
342
342
 
343
+ # ── Determine session outcome from observable signals ──────────────
344
+ PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
345
+
343
346
  if [[ $EXIT_CODE -eq 124 ]]; then
344
347
  log_warn "Session timed out after ${SESSION_TIMEOUT}s"
345
348
  SESSION_STATUS="timed_out"
346
- elif [[ -f "$SESSION_STATUS_FILE" ]]; then
347
- SESSION_STATUS=$(python3 "$SCRIPTS_DIR/check-session-status.py" \
348
- --status-file "$SESSION_STATUS_FILE" 2>/dev/null) || SESSION_STATUS="crashed"
349
+ elif [[ $EXIT_CODE -ne 0 ]]; then
350
+ log_warn "Session exited with code $EXIT_CODE"
351
+ SESSION_STATUS="crashed"
349
352
  else
350
- # No session-status.json found. Check if session produced git commits
351
- # (e.g., context window exhausted after committing but before writing status).
352
- log_warn "Session ended without status file"
353
- PROJECT_ROOT_CHECK="$(cd "$SCRIPT_DIR/.." && pwd)"
354
- RECENT_FEATURE_COMMITS=""
355
- if git -C "$PROJECT_ROOT_CHECK" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
356
- # Use session directory creation time as lower bound for commit search
357
- SESSION_START_ISO=$(python3 -c "
353
+ # Exit code 0 check if the session produced commits
354
+ SESSION_START_ISO=$(python3 -c "
358
355
  import os, sys
359
356
  from datetime import datetime, timezone
360
357
  p = sys.argv[1]
@@ -364,25 +361,29 @@ if os.path.isdir(p):
364
361
  else:
365
362
  print('')
366
363
  " "$SESSION_DIR" 2>/dev/null) || SESSION_START_ISO=""
367
- if [[ -n "$SESSION_START_ISO" ]]; then
368
- RECENT_FEATURE_COMMITS=$(git -C "$PROJECT_ROOT_CHECK" log --since="$SESSION_START_ISO" --oneline --grep="$FEATURE_ID" 2>/dev/null | head -5)
369
- fi
364
+
365
+ HAS_COMMITS=""
366
+ if [[ -n "$SESSION_START_ISO" ]] && git -C "$PROJECT_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
367
+ HAS_COMMITS=$(git -C "$PROJECT_ROOT" log --since="$SESSION_START_ISO" --oneline --grep="$FEATURE_ID" 2>/dev/null | head -1)
370
368
  fi
371
369
 
372
- if [[ -n "$RECENT_FEATURE_COMMITS" ]]; then
373
- log_warn "Found commits from this session:"
374
- echo "$RECENT_FEATURE_COMMITS" | sed 's/^/ - /'
375
- log_warn "Treating as commit_missing (artifacts preserved for retry)"
376
- SESSION_STATUS="commit_missing"
370
+ if [[ -n "$HAS_COMMITS" ]]; then
371
+ SESSION_STATUS="success"
377
372
  else
378
- SESSION_STATUS="crashed"
373
+ UNCOMMITTED=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null | head -1 || true)
374
+ if [[ -n "$UNCOMMITTED" ]]; then
375
+ log_warn "Session exited cleanly but produced no commits (uncommitted changes found)"
376
+ SESSION_STATUS="commit_missing"
377
+ else
378
+ log_warn "Session exited cleanly but produced no commits and no changes"
379
+ SESSION_STATUS="crashed"
380
+ fi
379
381
  fi
380
382
  fi
381
383
 
384
+ # ── Post-success validation ──────────────────────────────────────────
382
385
  if [[ "$SESSION_STATUS" == "success" ]]; then
383
- PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
384
386
  if git -C "$PROJECT_ROOT" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
385
- # Auto-commit any remaining dirty files produced during the session
386
387
  DIRTY_FILES=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null || true)
387
388
  if [[ -n "$DIRTY_FILES" ]]; then
388
389
  log_info "Auto-committing remaining session artifacts..."
@@ -390,11 +391,9 @@ if [[ "$SESSION_STATUS" == "success" ]]; then
390
391
  git -C "$PROJECT_ROOT" commit -m "chore($FEATURE_ID): include remaining session artifacts" 2>/dev/null || true
391
392
  fi
392
393
 
393
- # Re-check: if still dirty after auto-commit, flag as failed
394
394
  DIRTY_FILES=$(git -C "$PROJECT_ROOT" status --porcelain 2>/dev/null || true)
395
395
  if [[ -n "$DIRTY_FILES" ]]; then
396
- if [[ -n "$DIRTY_FILES" ]]; then
397
- log_error "Session reported success but git working tree is not clean."
396
+ log_error "Git working tree still not clean after auto-commit."
398
397
  echo "$DIRTY_FILES" | sed 's/^/ - /'
399
398
  SESSION_STATUS="failed"
400
399
  fi
@@ -164,26 +164,51 @@ spawn_and_wait_session() {
164
164
  log_info "Session log: $final_lines lines, $((final_size / 1024))KB"
165
165
  fi
166
166
 
167
- # Check session outcome
168
- local session_status_file="$session_dir/session-status.json"
167
+ # ── Determine session outcome from observable signals ──────────────
169
168
  local session_status
169
+ local project_root
170
+ project_root="$(cd "$SCRIPT_DIR/.." && pwd)"
170
171
 
171
172
  if [[ $exit_code -eq 124 ]]; then
172
173
  log_warn "Session timed out after ${SESSION_TIMEOUT}s"
173
174
  session_status="timed_out"
174
- elif [[ -f "$session_status_file" ]]; then
175
- session_status=$(python3 "$SCRIPTS_DIR/check-session-status.py" \
176
- --status-file "$session_status_file" 2>/dev/null) || session_status="crashed"
177
- else
178
- log_warn "Session ended without status file — treating as crashed"
175
+ elif [[ $exit_code -ne 0 ]]; then
176
+ log_warn "Session exited with code $exit_code"
179
177
  session_status="crashed"
178
+ else
179
+ # Exit code 0 — check if the session actually produced commits
180
+ local session_start_iso=""
181
+ session_start_iso=$(python3 -c "
182
+ import json, sys, os
183
+ p = os.path.join(sys.argv[1], 'current-session.json')
184
+ if os.path.isfile(p):
185
+ with open(p) as f: print(json.load(f).get('started_at', ''))
186
+ else: print('')
187
+ " "$STATE_DIR" 2>/dev/null) || session_start_iso=""
188
+
189
+ local has_commits=""
190
+ if [[ -n "$session_start_iso" ]] && git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
191
+ has_commits=$(git -C "$project_root" log --since="$session_start_iso" --oneline --grep="$bug_id" 2>/dev/null | head -1)
192
+ fi
193
+
194
+ if [[ -n "$has_commits" ]]; then
195
+ session_status="success"
196
+ else
197
+ local uncommitted=""
198
+ uncommitted=$(git -C "$project_root" status --porcelain 2>/dev/null | head -1 || true)
199
+ if [[ -n "$uncommitted" ]]; then
200
+ log_warn "Session exited cleanly but produced no commits (uncommitted changes found)"
201
+ session_status="commit_missing"
202
+ else
203
+ log_warn "Session exited cleanly but produced no commits and no changes"
204
+ session_status="crashed"
205
+ fi
206
+ fi
180
207
  fi
181
208
 
209
+ # ── Post-success validation ──────────────────────────────────────────
182
210
  if [[ "$session_status" == "success" ]]; then
183
- local project_root
184
- project_root="$(cd "$SCRIPT_DIR/.." && pwd)"
185
211
  if git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
186
- # Auto-commit any remaining dirty files produced during the session
187
212
  local dirty_files=""
188
213
  dirty_files=$(git -C "$project_root" status --porcelain 2>/dev/null || true)
189
214
  if [[ -n "$dirty_files" ]]; then
@@ -192,10 +217,9 @@ spawn_and_wait_session() {
192
217
  git -C "$project_root" commit -m "chore($bug_id): include remaining session artifacts" 2>/dev/null || true
193
218
  fi
194
219
 
195
- # Re-check: if still dirty after auto-commit, flag as failed
196
220
  dirty_files=$(git -C "$project_root" status --porcelain 2>/dev/null || true)
197
221
  if [[ -n "$dirty_files" ]]; then
198
- log_error "Session reported success but git working tree is not clean."
222
+ log_error "Git working tree still not clean after auto-commit."
199
223
  echo "$dirty_files" | sed 's/^/ - /'
200
224
  session_status="failed"
201
225
  fi
@@ -444,12 +468,13 @@ sys.exit(1)
444
468
  "$bootstrap_prompt" "$session_dir" 999
445
469
  local session_status="$_SPAWN_RESULT"
446
470
 
447
- # Auto-push after successful session
448
- if [[ "$session_status" == "success" && "$AUTO_PUSH" == "1" ]]; then
449
- local _proj_root
450
- _proj_root="$(cd "$SCRIPT_DIR/.." && pwd)"
451
- log_info "AUTO_PUSH enabled; pushing to remote..."
452
- git -C "$_proj_root" push -u origin "$_DEV_BRANCH_NAME" 2>/dev/null || log_warn "Auto-push failed"
471
+ # Merge dev branch back to original on success
472
+ if [[ "$session_status" == "success" && -n "$_DEV_BRANCH_NAME" ]]; then
473
+ if branch_merge "$_proj_root" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
474
+ _DEV_BRANCH_NAME=""
475
+ else
476
+ log_warn "Auto-merge failed dev branch preserved: $_DEV_BRANCH_NAME"
477
+ fi
453
478
  fi
454
479
 
455
480
  echo ""
@@ -563,12 +588,18 @@ main() {
563
588
  log_success "════════════════════════════════════════════════════"
564
589
  log_success " All bugs processed! Bug fix pipeline finished."
565
590
  log_success " Total sessions: $session_count"
566
- if [[ -n "$_DEV_BRANCH_NAME" ]]; then
567
- log_success " Dev branch: $_DEV_BRANCH_NAME"
568
- log_success " Merge with: git checkout $_ORIGINAL_BRANCH && git merge $_DEV_BRANCH_NAME"
569
- fi
570
591
  log_success "════════════════════════════════════════════════════"
571
592
  rm -f "$STATE_DIR/current-session.json"
593
+
594
+ # Merge dev branch back to original
595
+ if [[ -n "$_DEV_BRANCH_NAME" ]]; then
596
+ if branch_merge "$_proj_root" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
597
+ _DEV_BRANCH_NAME=""
598
+ else
599
+ log_warn "Auto-merge failed — dev branch preserved: $_DEV_BRANCH_NAME"
600
+ log_warn "Merge manually: git checkout $_ORIGINAL_BRANCH && git merge $_DEV_BRANCH_NAME"
601
+ fi
602
+ fi
572
603
  break
573
604
  fi
574
605
 
@@ -641,14 +672,6 @@ os.replace(tmp, target)
641
672
  "$bug_id" "$bug_list" "$session_id" \
642
673
  "$bootstrap_prompt" "$session_dir" "$MAX_RETRIES"
643
674
 
644
- # Auto-push after successful session
645
- if [[ "$_SPAWN_RESULT" == "success" && "$AUTO_PUSH" == "1" ]]; then
646
- local _proj_root
647
- _proj_root="$(cd "$SCRIPT_DIR/.." && pwd)"
648
- log_info "AUTO_PUSH enabled; pushing to remote..."
649
- git -C "$_proj_root" push 2>/dev/null || log_warn "Auto-push failed"
650
- fi
651
-
652
675
  session_count=$((session_count + 1))
653
676
 
654
677
  log_info "Pausing 5s before next bug..."
@@ -184,24 +184,21 @@ spawn_and_wait_session() {
184
184
  log_info "Session log: $final_lines lines, $((final_size / 1024))KB"
185
185
  fi
186
186
 
187
- # Check session outcome
188
- local session_status_file="$session_dir/session-status.json"
187
+ # ── Determine session outcome from observable signals ──────────────
188
+ # No dependency on session-status.json — uses exit code, git commits,
189
+ # and working tree cleanliness as the single source of truth.
189
190
  local session_status
191
+ local project_root
192
+ project_root="$(cd "$SCRIPT_DIR/.." && pwd)"
190
193
 
191
194
  if [[ $exit_code -eq 124 ]]; then
192
195
  log_warn "Session timed out after ${SESSION_TIMEOUT}s"
193
196
  session_status="timed_out"
194
- elif [[ -f "$session_status_file" ]]; then
195
- session_status=$(python3 "$SCRIPTS_DIR/check-session-status.py" \
196
- --status-file "$session_status_file" 2>/dev/null) || session_status="crashed"
197
+ elif [[ $exit_code -ne 0 ]]; then
198
+ log_warn "Session exited with code $exit_code"
199
+ session_status="crashed"
197
200
  else
198
- # No session-status.json found. Before treating as crashed, check if the
199
- # session produced any git commits. If commits exist, the session likely
200
- # completed its work but terminated before writing session-status.json
201
- # (e.g., context window exhausted). Treat as commit_missing to preserve
202
- # artifacts instead of wiping everything via the crashed cleanup path.
203
- local project_root_check
204
- project_root_check="$(cd "$SCRIPT_DIR/.." && pwd)"
201
+ # Exit code 0 check if the session actually produced commits
205
202
  local session_start_iso=""
206
203
  session_start_iso=$(python3 -c "
207
204
  import json, sys, os
@@ -211,28 +208,32 @@ if os.path.isfile(p):
211
208
  else: print('')
212
209
  " "$STATE_DIR" 2>/dev/null) || session_start_iso=""
213
210
 
214
- local recent_feature_commits=""
215
- if [[ -n "$session_start_iso" ]] && git -C "$project_root_check" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
216
- recent_feature_commits=$(git -C "$project_root_check" log --since="$session_start_iso" --oneline --grep="$feature_id" 2>/dev/null | head -5)
211
+ local has_commits=""
212
+ if [[ -n "$session_start_iso" ]] && git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
213
+ has_commits=$(git -C "$project_root" log --since="$session_start_iso" --oneline --grep="$feature_id" 2>/dev/null | head -1)
217
214
  fi
218
215
 
219
- if [[ -n "$recent_feature_commits" ]]; then
220
- log_warn "Session ended without status file, but found commits from this session:"
221
- echo "$recent_feature_commits" | sed 's/^/ - /'
222
- log_warn "Treating as commit_missing (artifacts preserved for retry)"
223
- session_status="commit_missing"
216
+ if [[ -n "$has_commits" ]]; then
217
+ session_status="success"
224
218
  else
225
- log_warn "Session ended without status file treating as crashed"
226
- session_status="crashed"
219
+ # No commits found check if there are uncommitted changes (session
220
+ # did work but didn't commit, e.g. context window exhausted)
221
+ local uncommitted=""
222
+ uncommitted=$(git -C "$project_root" status --porcelain 2>/dev/null | head -1 || true)
223
+ if [[ -n "$uncommitted" ]]; then
224
+ log_warn "Session exited cleanly but produced no commits (uncommitted changes found)"
225
+ session_status="commit_missing"
226
+ else
227
+ log_warn "Session exited cleanly but produced no commits and no changes"
228
+ session_status="crashed"
229
+ fi
227
230
  fi
228
231
  fi
229
232
 
233
+ # ── Post-success validation ──────────────────────────────────────────
230
234
  if [[ "$session_status" == "success" ]]; then
231
- local project_root
232
- project_root="$(cd "$SCRIPT_DIR/.." && pwd)"
233
235
  if git -C "$project_root" rev-parse --is-inside-work-tree >/dev/null 2>&1; then
234
236
  # Auto-commit any remaining dirty files produced during the session
235
- # (pipeline state, runtime data, files the AI session missed)
236
237
  local dirty_files=""
237
238
  dirty_files=$(git -C "$project_root" status --porcelain 2>/dev/null || true)
238
239
  if [[ -n "$dirty_files" ]]; then
@@ -244,7 +245,7 @@ else: print('')
244
245
  # Re-check: if still dirty after auto-commit, flag as commit_missing
245
246
  dirty_files=$(git -C "$project_root" status --porcelain 2>/dev/null || true)
246
247
  if [[ -n "$dirty_files" ]]; then
247
- log_warn "Session reported success but git working tree is not clean."
248
+ log_warn "Git working tree still not clean after auto-commit."
248
249
  echo "$dirty_files" | sed 's/^/ - /'
249
250
  session_status="commit_missing"
250
251
  else
@@ -266,20 +267,6 @@ else: print('')
266
267
  fi
267
268
  fi
268
269
 
269
- # Persist final pipeline-resolved status back to session-status.json
270
- # only for post-check statuses introduced by the pipeline itself.
271
- if [[ -f "$session_status_file" && ( "$session_status" == "commit_missing" || "$session_status" == "docs_missing" ) ]]; then
272
- python3 -c "
273
- import json, sys
274
- p, st = sys.argv[1], sys.argv[2]
275
- with open(p, 'r', encoding='utf-8') as f:
276
- data = json.load(f)
277
- data['status'] = st
278
- with open(p, 'w', encoding='utf-8') as f:
279
- json.dump(data, f, indent=2, ensure_ascii=False)
280
- " "$session_status_file" "$session_status" >/dev/null 2>&1 || true
281
- fi
282
-
283
270
  log_info "Session result: $session_status"
284
271
 
285
272
  # Write lightweight session summary for post-session inspection
@@ -788,12 +775,13 @@ sys.exit(1)
788
775
  "$bootstrap_prompt" "$session_dir" 999 "$feature_model"
789
776
  local session_status="$_SPAWN_RESULT"
790
777
 
791
- # Auto-push after successful session
792
- if [[ "$session_status" == "success" && "$AUTO_PUSH" == "1" ]]; then
793
- local _proj_root
794
- _proj_root="$(cd "$SCRIPT_DIR/.." && pwd)"
795
- log_info "AUTO_PUSH enabled; pushing to remote..."
796
- git -C "$_proj_root" push -u origin "$_DEV_BRANCH_NAME" 2>/dev/null || log_warn "Auto-push failed"
778
+ # Merge dev branch back to original on success
779
+ if [[ "$session_status" == "success" && -n "$_DEV_BRANCH_NAME" ]]; then
780
+ if branch_merge "$_proj_root" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
781
+ _DEV_BRANCH_NAME=""
782
+ else
783
+ log_warn "Auto-merge failed dev branch preserved: $_DEV_BRANCH_NAME"
784
+ fi
797
785
  fi
798
786
 
799
787
  echo ""
@@ -981,12 +969,18 @@ for f in data.get('stuck_features', []):
981
969
  log_success "════════════════════════════════════════════════════"
982
970
  log_success " All features completed! Pipeline finished."
983
971
  log_success " Total sessions: $session_count"
984
- if [[ -n "$_DEV_BRANCH_NAME" ]]; then
985
- log_success " Dev branch: $_DEV_BRANCH_NAME"
986
- log_success " Merge with: git checkout $_ORIGINAL_BRANCH && git merge $_DEV_BRANCH_NAME"
987
- fi
988
972
  log_success "════════════════════════════════════════════════════"
989
973
  rm -f "$STATE_DIR/current-session.json"
974
+
975
+ # Merge dev branch back to original
976
+ if [[ -n "$_DEV_BRANCH_NAME" ]]; then
977
+ if branch_merge "$_proj_root" "$_DEV_BRANCH_NAME" "$_ORIGINAL_BRANCH" "$AUTO_PUSH"; then
978
+ _DEV_BRANCH_NAME=""
979
+ else
980
+ log_warn "Auto-merge failed — dev branch preserved: $_DEV_BRANCH_NAME"
981
+ log_warn "Merge manually: git checkout $_ORIGINAL_BRANCH && git merge $_DEV_BRANCH_NAME"
982
+ fi
983
+ fi
990
984
  break
991
985
  fi
992
986
 
@@ -1096,14 +1090,6 @@ os.replace(tmp, target)
1096
1090
  "$bootstrap_prompt" "$session_dir" "$MAX_RETRIES" "$feature_model"
1097
1091
  local session_status="$_SPAWN_RESULT"
1098
1092
 
1099
- # Auto-push after successful session
1100
- if [[ "$session_status" == "success" && "$AUTO_PUSH" == "1" ]]; then
1101
- local _proj_root
1102
- _proj_root="$(cd "$SCRIPT_DIR/.." && pwd)"
1103
- log_info "AUTO_PUSH enabled; pushing to remote..."
1104
- git -C "$_proj_root" push 2>/dev/null || log_warn "Auto-push failed"
1105
- fi
1106
-
1107
1093
  session_count=$((session_count + 1))
1108
1094
 
1109
1095
  # Brief pause before next iteration
@@ -11,7 +11,7 @@
11
11
 
12
12
  You are the **session orchestrator**. Implement Feature {{FEATURE_ID}}: "{{FEATURE_TITLE}}".
13
13
 
14
- **CRITICAL**: You MUST NOT exit until ALL work is complete and session-status.json is written.
14
+ **CRITICAL**: You MUST NOT exit until ALL work is complete and committed.
15
15
 
16
16
  **Tier 1 — Single Agent**: You handle everything directly. No subagents, no TeamCreate.
17
17
 
@@ -40,8 +40,7 @@ You are running in headless mode with a FINITE context window. Exceeding it will
40
40
  3. **Stay focused** — Do NOT explore code unrelated to this feature. No curiosity-driven reads.
41
41
  4. **One task at a time** — In Phase 3 (implement), complete and test one task before starting the next.
42
42
  5. **Minimize tool output** — When running commands, use `| head -20` or `| tail -20` to limit output. Never dump entire test suites or logs.
43
- 6. **Write session-status.json early** — Write a preliminary status file at the START of Phase 3, not just at the end.
44
- 7. **Incremental commits when possible** — If a feature has multiple independent tasks, commit after each completed task rather than one big commit at the end.
43
+ 6. **Incremental commits when possible** — If a feature has multiple independent tasks, commit after each completed task rather than one big commit at the end.
45
44
 
46
45
  ---
47
46
 
@@ -98,19 +97,7 @@ If plan.md missing, write it directly:
98
97
 
99
98
  **CP-1**: plan.md exists with Tasks section.
100
99
 
101
- ### Phase 3: Implement
102
-
103
- **Before starting implementation**, write a preliminary session-status.json to `{{SESSION_STATUS_PATH}}`:
104
- ```json
105
- {
106
- "status": "partial",
107
- "current_phase": 3,
108
- "feature_id": "{{FEATURE_ID}}",
109
- "session_id": "{{SESSION_ID}}",
110
- "started_at": "<current ISO timestamp>"
111
- }
112
- ```
113
- This ensures the pipeline sees a "partial" status even if the session crashes mid-implementation.
100
+ ### Phase 3: Implement + Test
114
101
 
115
102
  For each task in plan.md Tasks section:
116
103
  1. Read the relevant section from `context-snapshot.md` (no need to re-read individual files)
@@ -118,25 +105,23 @@ For each task in plan.md Tasks section:
118
105
  3. Run tests after each task
119
106
  3. Mark task `[x]` in plan.md Tasks section immediately
120
107
 
121
- After all tasks complete, append to `context-snapshot.md`:
108
+ After all tasks complete:
109
+ 1. Run the full test suite to ensure nothing is broken
110
+ 2. Verify each acceptance criterion from Section 1 of context-snapshot.md is met — check mentally, do NOT re-read files you already wrote
111
+ 3. If any criterion is not met, fix it now (max 2 fix rounds)
112
+
113
+ **CP-2**: All acceptance criteria met, all tests pass.
114
+
115
+ After verification, append to `context-snapshot.md`:
122
116
  ```
123
117
  ## Implementation Log
124
118
  Files changed/created: [list]
125
119
  Key decisions: [list]
126
120
  ```
127
121
 
128
- ### Phase 4: Code Review (mandatory)
129
-
130
- 1. Re-read acceptance criteria from Section 1 of context-snapshot.md
131
- 2. Run `/prizmkit-code-review` — verify all acceptance criteria, check code quality and correctness
132
- 3. Run the full test suite
133
- 4. If review uncovers issues, fix them (max 2 fix rounds)
134
-
135
- **CP-2**: All acceptance criteria met, tests pass, code review passed.
122
+ ### Phase 4: Architecture Sync & Commit
136
123
 
137
- ### Phase 4.5: Architecture Sync & Memory Sedimentation (mandatory before commit)
138
-
139
- Run `/prizmkit-retrospective` — maintains `.prizm-docs/` (architecture index) and platform memory files:
124
+ **4a.** Run `/prizmkit-retrospective` maintains `.prizm-docs/` (architecture index) and platform memory files:
140
125
  1. **Structural sync**: Use `git diff --cached --name-status` to locate changed modules, update KEY_FILES/INTERFACES/DEPENDENCIES/file counts in affected `.prizm-docs/` files
141
126
  2. **Architecture knowledge** (feature sessions only): Extract TRAPS/RULES from completed work into `.prizm-docs/`
142
127
  3. **Memory sedimentation** (feature sessions only): Sediment DECISIONS and interface conventions to platform memory file (`CLAUDE.md` for Claude Code, BOTH `CODEBUDDY.md` AND `memory/MEMORY.md` for CodeBuddy)
@@ -144,49 +129,11 @@ Run `/prizmkit-retrospective` — maintains `.prizm-docs/` (architecture index)
144
129
 
145
130
  Doc maintenance pass condition (pipeline-enforced): `.prizm-docs/` changed in the final commit.
146
131
 
147
- ### Phase 5: Session Status + Commit
148
-
149
- **5a. Write preliminary session-status.json** (safety net — ensures pipeline sees a status file even if session terminates during commit):
150
-
151
- Write to: `{{SESSION_STATUS_PATH}}`
152
-
153
- ```json
154
- {
155
- "session_id": "{{SESSION_ID}}",
156
- "feature_id": "{{FEATURE_ID}}",
157
- "feature_slug": "{{FEATURE_SLUG}}",
158
- "exec_tier": 1,
159
- "status": "partial",
160
- "completed_phases": [0, 1, 2, 3, 4],
161
- "current_phase": 5,
162
- "checkpoint_reached": "CP-2",
163
- "tasks_completed": 0,
164
- "tasks_total": 0,
165
- "errors": [],
166
- "can_resume": false,
167
- "resume_from_phase": null,
168
- "docs_maintained": true,
169
- "retrospective_done": true,
170
- "artifacts": {
171
- "context_snapshot_path": ".prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md",
172
- "plan_path": ".prizmkit/specs/{{FEATURE_SLUG}}/plan.md"
173
- },
174
- "git_commit": "",
175
- "timestamp": "<current ISO timestamp>"
176
- }
177
- ```
178
-
179
- **5b. Commit** — Run `/prizmkit-committer` → `feat({{FEATURE_ID}}): {{FEATURE_TITLE}}`, do NOT push
132
+ **4b. Commit** — Run `/prizmkit-committer` → `feat({{FEATURE_ID}}): {{FEATURE_TITLE}}`, do NOT push
180
133
  - MANDATORY: commit must be done via `/prizmkit-committer` skill. Do NOT run manual `git add`/`git commit` as a substitute.
181
134
  - Do NOT run `update-feature-status.py` here — the pipeline runner handles feature-list.json updates automatically after session exit.
182
135
 
183
- **5c. Update session-status.json to success** — After commit succeeds, update `{{SESSION_STATUS_PATH}}`:
184
- - Set `"status": "success"`
185
- - Set `"completed_phases": [0, 1, 2, 3, 4, 5]`
186
- - Set `"git_commit": "<actual commit hash from git log -1 --format=%H>"`
187
- - Set `"timestamp": "<current ISO timestamp>"`
188
-
189
- **5d. Final Clean Check** — Verify repository is clean:
136
+ **4c. Final Clean Check** — Verify repository is clean:
190
137
 
191
138
  ```bash
192
139
  git status --short
@@ -207,15 +154,13 @@ git commit -m "chore({{FEATURE_ID}}): include session artifacts"
207
154
  |----------|------|
208
155
  | Feature Artifacts Dir | `.prizmkit/specs/{{FEATURE_SLUG}}/` |
209
156
  | Context Snapshot | `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` |
210
- | Session Status Output | {{SESSION_STATUS_PATH}} |
211
157
  | Project Root | {{PROJECT_ROOT}} |
212
158
 
213
159
  ## Reminders
214
160
 
215
- - Tier 1: you handle everything directly — invoke skills yourself (no subagents needed for simple tasks)
216
- - MANDATORY skills: `/prizmkit-code-review`, `/prizmkit-retrospective`, `/prizmkit-committer` — never skip these
161
+ - Tier 1: you handle everything directly — no subagents needed
162
+ - MANDATORY skills: `/prizmkit-retrospective`, `/prizmkit-committer` — never skip these
217
163
  - Build context-snapshot.md FIRST; use it throughout instead of re-reading files
218
- - Session-status.json is written BEFORE commit (as partial), then updated to success AFTER commit — this prevents pipeline from treating a terminated session as crashed
219
164
  - `/prizmkit-committer` is mandatory — do NOT skip the commit phase, and do NOT replace it with manual git commit commands
220
165
  - Before exiting, commit your feature code via `/prizmkit-committer` — the pipeline runner auto-commits any remaining files after session exit
221
166
  - When staging leftover files in the final clean check, always use explicit file names — NEVER use `git add -A`
@@ -11,7 +11,7 @@
11
11
 
12
12
  You are the **session orchestrator**. Implement Feature {{FEATURE_ID}}: "{{FEATURE_TITLE}}".
13
13
 
14
- **CRITICAL**: You MUST NOT exit until ALL work is complete and session-status.json is written. When you spawn subagents, wait for each to finish (run_in_background=false).
14
+ **CRITICAL**: You MUST NOT exit until ALL work is complete and committed. When you spawn subagents, wait for each to finish (run_in_background=false).
15
15
 
16
16
  **Tier 2 — Dual Agent**: You handle context + planning directly. Then spawn Dev and Reviewer subagents. Spawn Dev and Reviewer agents via the Agent tool.
17
17
 
@@ -40,8 +40,7 @@ You are running in headless mode with a FINITE context window. Exceeding it will
40
40
  3. **Stay focused** — Do NOT explore code unrelated to this feature. No curiosity-driven reads.
41
41
  4. **One task at a time** — In Phase 3 (implement), complete and test one task before starting the next.
42
42
  5. **Minimize tool output** — When running commands, use `| head -20` or `| tail -20` to limit output. Never dump entire test suites or logs.
43
- 6. **Write session-status.json early** — Write a preliminary status file at the START of Phase 3, not just at the end.
44
- 7. **Incremental commits when possible** — If a feature has multiple independent tasks, commit after each completed task rather than one big commit at the end.
43
+ 6. **Incremental commits when possible** — If a feature has multiple independent tasks, commit after each completed task rather than one big commit at the end.
45
44
 
46
45
  ---
47
46
 
@@ -121,18 +120,6 @@ If either missing, write them yourself:
121
120
 
122
121
  ### Phase 3: Implement — Dev Subagent
123
122
 
124
- **Before spawning Dev**, write a preliminary session-status.json to `{{SESSION_STATUS_PATH}}`:
125
- ```json
126
- {
127
- "status": "partial",
128
- "current_phase": 3,
129
- "feature_id": "{{FEATURE_ID}}",
130
- "session_id": "{{SESSION_ID}}",
131
- "started_at": "<current ISO timestamp>"
132
- }
133
- ```
134
- This ensures the pipeline sees a "partial" status even if the session crashes mid-implementation.
135
-
136
123
  Spawn Dev subagent (Agent tool, subagent_type="prizm-dev-team-dev", run_in_background=false).
137
124
 
138
125
  Prompt:
@@ -160,7 +147,7 @@ grep -q "## Implementation Log" .prizmkit/specs/{{FEATURE_SLUG}}/context-snapsho
160
147
  ```
161
148
  If GATE:MISSING — send message to Dev (re-spawn if needed): "Write the '## Implementation Log' section to context-snapshot.md before I can proceed to review. Include: files changed/created, key decisions, deviations from plan, notable discoveries."
162
149
 
163
- ### Phase 4: Review — Reviewer Subagent
150
+ ### Phase 4: Review + Test — Reviewer Subagent
164
151
 
165
152
  Spawn Reviewer subagent (Agent tool, subagent_type="prizm-dev-team-reviewer", run_in_background=false).
166
153
 
@@ -172,7 +159,7 @@ Prompt:
172
159
  > - Section 4: File Manifest (original file structure)
173
160
  > - '## Implementation Log': what Dev changed, key decisions, discoveries
174
161
  > 2. Run prizmkit-code-review: spec compliance (against spec.md), code quality, correctness. Read ONLY files listed in Implementation Log.
175
- > 3. Write and execute integration tests covering all user stories from spec.md. Use `TEST_CMD=<TEST_CMD>` — do NOT try alternative test commands.
162
+ > 3. Run the full test suite using `TEST_CMD=<TEST_CMD>`. Write and execute integration tests covering all user stories.
176
163
  > 4. Append '## Review Notes' to context-snapshot.md: issues found (with severity), test results, final verdict.
177
164
  > Report verdict: PASS, PASS_WITH_WARNINGS, or NEEDS_FIXES."
178
165
 
@@ -189,9 +176,9 @@ If GATE:MISSING — send message to Reviewer (re-spawn if needed): "Write the '#
189
176
 
190
177
  **CP-2**: Tests pass, verdict is not NEEDS_FIXES.
191
178
 
192
- ### Phase 4.5: Architecture Sync & Memory Sedimentation (mandatory before commit)
179
+ ### Phase 5: Architecture Sync & Commit
193
180
 
194
- Run `/prizmkit-retrospective` — maintains `.prizm-docs/` (architecture index) and platform memory files:
181
+ **5a.** Run `/prizmkit-retrospective` — maintains `.prizm-docs/` (architecture index) and platform memory files:
195
182
  1. **Structural sync**: Use `git diff --cached --name-status` to locate changed modules, update KEY_FILES/INTERFACES/DEPENDENCIES/file counts in affected `.prizm-docs/` files
196
183
  2. **Architecture knowledge** (feature sessions only): Extract TRAPS/RULES from completed work into `.prizm-docs/`
197
184
  3. **Memory sedimentation** (feature sessions only): Sediment DECISIONS and interface conventions to platform memory file (`CLAUDE.md` for Claude Code, BOTH `CODEBUDDY.md` AND `memory/MEMORY.md` for CodeBuddy)
@@ -199,49 +186,11 @@ Run `/prizmkit-retrospective` — maintains `.prizm-docs/` (architecture index)
199
186
 
200
187
  Doc maintenance pass condition (pipeline-enforced): `.prizm-docs/` changed in the final commit.
201
188
 
202
- ### Phase 5: Session Status + Commit
203
-
204
- **5a. Write preliminary session-status.json** (safety net — ensures pipeline sees a status file even if session terminates during commit):
205
-
206
- Write to: `{{SESSION_STATUS_PATH}}`
207
-
208
- ```json
209
- {
210
- "session_id": "{{SESSION_ID}}",
211
- "feature_id": "{{FEATURE_ID}}",
212
- "feature_slug": "{{FEATURE_SLUG}}",
213
- "exec_tier": 2,
214
- "status": "partial",
215
- "completed_phases": [0, 1, 2, 3, 4],
216
- "current_phase": 5,
217
- "checkpoint_reached": "CP-2",
218
- "tasks_completed": 0,
219
- "tasks_total": 0,
220
- "errors": [],
221
- "can_resume": false,
222
- "resume_from_phase": null,
223
- "docs_maintained": true,
224
- "retrospective_done": true,
225
- "artifacts": {
226
- "context_snapshot_path": ".prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md",
227
- "plan_path": ".prizmkit/specs/{{FEATURE_SLUG}}/plan.md"
228
- },
229
- "git_commit": "",
230
- "timestamp": "<current ISO timestamp>"
231
- }
232
- ```
233
-
234
189
  **5b. Commit** — Run `/prizmkit-committer` → `feat({{FEATURE_ID}}): {{FEATURE_TITLE}}`, do NOT push
235
190
  - MANDATORY: commit must be done via `/prizmkit-committer` skill. Do NOT run manual `git add`/`git commit` as a substitute.
236
191
  - Do NOT run `update-feature-status.py` here — the pipeline runner handles feature-list.json updates automatically after session exit.
237
192
 
238
- **5c. Update session-status.json to success** — After commit succeeds, update `{{SESSION_STATUS_PATH}}`:
239
- - Set `"status": "success"`
240
- - Set `"completed_phases": [0, 1, 2, 3, 4, 5]`
241
- - Set `"git_commit": "<actual commit hash from git log -1 --format=%H>"`
242
- - Set `"timestamp": "<current ISO timestamp>"`
243
-
244
- **5d. Final Clean Check** — Verify repository is clean:
193
+ **5c. Final Clean Check** — Verify repository is clean:
245
194
 
246
195
  ```bash
247
196
  git status --short
@@ -264,17 +213,15 @@ git commit -m "chore({{FEATURE_ID}}): include session artifacts"
264
213
  | Context Snapshot | `.prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md` |
265
214
  | Dev Agent Def | {{DEV_SUBAGENT_PATH}} |
266
215
  | Reviewer Agent Def | {{REVIEWER_SUBAGENT_PATH}} |
267
- | Session Status Output | {{SESSION_STATUS_PATH}} |
268
216
  | Project Root | {{PROJECT_ROOT}} |
269
217
 
270
218
  ## Reminders
271
219
 
272
- - Tier 2: orchestrator builds context+plan, Dev implements, Reviewer reviews — use direct Agent spawn for agents
220
+ - Tier 2: orchestrator builds context+plan, Dev implements, Reviewer reviews+tests — use direct Agent spawn for agents
273
221
  - Build context-snapshot.md FIRST; all subagents read it instead of re-reading source files
274
222
  - context-snapshot.md is append-only: orchestrator writes Sections 1-4, Dev appends Implementation Log, Reviewer appends Review Notes
275
223
  - Gate checks enforce Implementation Log and Review Notes are written before proceeding
276
224
  - Do NOT use `run_in_background=true` when spawning subagents
277
- - Session-status.json is written BEFORE commit (as partial), then updated to success AFTER commit — this prevents pipeline from treating a terminated session as crashed
278
225
  - `/prizmkit-committer` is mandatory, and must not be replaced with manual git commit commands
279
226
  - Before exiting, commit your feature code via `/prizmkit-committer` — the pipeline runner auto-commits any remaining files after session exit
280
227
  - When staging leftover files in the final clean check, always use explicit file names — NEVER use `git add -A`
@@ -11,7 +11,7 @@
11
11
 
12
12
  You are the **session orchestrator**. Implement Feature {{FEATURE_ID}}: "{{FEATURE_TITLE}}".
13
13
 
14
- **CRITICAL**: You MUST NOT exit until ALL work is complete and session-status.json is written. When you spawn subagents, wait for each to finish (run_in_background=false). Do NOT spawn agents in background and exit — that kills the session.
14
+ **CRITICAL**: You MUST NOT exit until ALL work is complete and committed. When you spawn subagents, wait for each to finish (run_in_background=false). Do NOT spawn agents in background and exit — that kills the session.
15
15
 
16
16
  **Tier 3 — Full Team**: For complex features, use the full pipeline (Phase 0–6) with Dev + Reviewer agents spawned via the Agent tool.
17
17
 
@@ -61,8 +61,6 @@ tests/ — Validation + unit tests
61
61
  ### Version Isolation
62
62
 
63
63
  LLM context is frozen at prompt time. Modifying a skill source file during this session will NOT change the behavior of that skill within this session. The real risk is structural inconsistency.
64
-
65
- **When you modify any file in `dev-pipeline/scripts/`, `dev-pipeline/templates/`, or `core/skills/` that this pipeline actively uses**: set `reload_needed: true` in `session-status.json`. The pipeline runner will warn the operator after session completion.
66
64
  {{END_IF_MODE_SELF_EVOLVE}}
67
65
 
68
66
  ## ⚠️ Context Budget Rules (CRITICAL — read before any phase)
@@ -74,8 +72,7 @@ You are running in headless mode with a FINITE context window. Exceeding it will
74
72
  3. **Stay focused** — Do NOT explore code unrelated to this feature. No curiosity-driven reads.
75
73
  4. **One task at a time** — In Phase 4 (implement), complete and test one task before starting the next.
76
74
  5. **Minimize tool output** — When running commands, use `| head -20` or `| tail -20` to limit output. Never dump entire test suites or logs.
77
- 6. **Write session-status.json early** — Write a preliminary status file at the START of Phase 4, not just at the end.
78
- 7. **Incremental commits when possible** — If a feature has multiple independent tasks, commit after each completed task rather than one big commit at the end.
75
+ 6. **Incremental commits when possible** — If a feature has multiple independent tasks, commit after each completed task rather than one big commit at the end.
79
76
 
80
77
  ---
81
78
 
@@ -222,18 +219,6 @@ Wait for Reviewer to return.
222
219
 
223
220
  ### Phase 4: Implement — Dev Agent
224
221
 
225
- **Before spawning Dev**, write a preliminary session-status.json to `{{SESSION_STATUS_PATH}}`:
226
- ```json
227
- {
228
- "status": "partial",
229
- "current_phase": 4,
230
- "feature_id": "{{FEATURE_ID}}",
231
- "session_id": "{{SESSION_ID}}",
232
- "started_at": "<current ISO timestamp>"
233
- }
234
- ```
235
- This ensures the pipeline sees a "partial" status even if the session crashes mid-implementation.
236
-
237
222
  Before spawning Dev, check plan.md Tasks section:
238
223
  ```bash
239
224
  grep -c '^\- \[ \]' .prizmkit/specs/{{FEATURE_SLUG}}/plan.md 2>/dev/null || echo 0
@@ -291,7 +276,7 @@ Wait for Dev to return. **If Dev times out before all tasks are `[x]`**:
291
276
 
292
277
  All tasks `[x]`, tests pass.
293
278
 
294
- ### Phase 5: Review — Reviewer Agent
279
+ ### Phase 5: Review + Test — Reviewer Agent
295
280
 
296
281
  Spawn Reviewer agent (Agent tool, subagent_type="prizm-dev-team-reviewer", run_in_background=false).
297
282
 
@@ -315,7 +300,7 @@ Prompt:
315
300
  > - Section 4: File Manifest (original file structure)
316
301
  > - '## Implementation Log': what Dev changed, key decisions, discoveries
317
302
  > 2. Run prizmkit-code-review: spec compliance (against spec.md), code quality, correctness. Read ONLY files listed in Implementation Log.
318
- > 3. Write and execute integration tests covering all user stories from spec.md. Use `TEST_CMD=<TEST_CMD>` — do NOT try alternative test commands.
303
+ > 3. Run the full test suite using `TEST_CMD=<TEST_CMD>`. Write and execute integration tests covering all user stories from spec.md.
319
304
  > 4. Append '## Review Notes' to context-snapshot.md: issues found (with severity), test results, final verdict.
320
305
  > Report verdict: PASS, PASS_WITH_WARNINGS, or NEEDS_FIXES."
321
306
 
@@ -353,86 +338,34 @@ bash {{VALIDATOR_SCRIPTS_DIR}}/validate-framework.sh
353
338
 
354
339
  - If ALL steps pass → proceed with commit below.
355
340
  - If any step fails → fix the issue and re-run. Maximum 2 fix-and-retry rounds.
356
- - After 2 failed rounds → mark session as `framework_validation_failed`, write session-status.json, and exit.
357
-
358
- **reload_needed check**: Review the Implementation Log in context-snapshot.md. If ANY of these paths were modified:
359
- - `dev-pipeline/scripts/*.py` or `dev-pipeline/scripts/*.sh`
360
- - `dev-pipeline/templates/*.md`
361
- - `core/skills/` (any skill used by the pipeline)
362
-
363
- Then set `"reload_needed": true` in session-status.json.
341
+ - After 2 failed rounds → exit and let the pipeline runner handle the failure.
364
342
  {{END_IF_MODE_SELF_EVOLVE}}
365
343
 
366
344
  **For bug fixes**: run `/prizmkit-retrospective` for structural sync only (skip knowledge injection unless a new TRAPS was discovered). Use `fix(<scope>):` commit prefix.
367
345
 
368
- **7a.** Check if feature already committed:
346
+ **6a.** Check if feature already committed:
369
347
  ```bash
370
348
  git log --oneline | grep "{{FEATURE_ID}}" | head -3
371
349
  ```
372
- - If a commit for `{{FEATURE_ID}}` already exists → **skip 7c** (do NOT run /prizmkit-committer, do NOT run git reset, do NOT stage or unstage anything). Proceed directly to Step 3.
373
- - If no existing commit → proceed normally with 7a7c.
350
+ - If a commit for `{{FEATURE_ID}}` already exists → **skip 6c** (do NOT run /prizmkit-committer, do NOT run git reset, do NOT stage or unstage anything). Proceed directly to Final Clean Check.
351
+ - If no existing commit → proceed normally with 6a6c.
374
352
 
375
- **7b.** Run `/prizmkit-retrospective` (**before commit**, maintains `.prizm-docs/` architecture index and platform memory files):
353
+ **6b.** Run `/prizmkit-retrospective` (**before commit**, maintains `.prizm-docs/` architecture index and platform memory files):
376
354
  - **Structural sync**: update KEY_FILES/INTERFACES/DEPENDENCIES/file counts for changed modules
377
355
  - **Architecture knowledge** (feature sessions only): extract TRAPS, RULES from completed work into `.prizm-docs/`
378
356
  - **Memory sedimentation** (feature sessions only): sediment DECISIONS and interface conventions to platform memory file (`CLAUDE.md` for Claude Code, BOTH `CODEBUDDY.md` AND `memory/MEMORY.md` for CodeBuddy)
379
357
  - Stage all doc changes: `git add .prizm-docs/`
380
358
  - **For bug-fix sessions**: structural sync only, skip knowledge injection and memory sedimentation unless a genuinely new pitfall was discovered
381
359
 
382
- **7b-safety.** Write preliminary session-status.json (safety net ensures pipeline sees a status file even if session terminates during commit):
383
-
384
- Write to: `{{SESSION_STATUS_PATH}}`
385
-
386
- ```json
387
- {
388
- "session_id": "{{SESSION_ID}}",
389
- "feature_id": "{{FEATURE_ID}}",
390
- "feature_slug": "{{FEATURE_SLUG}}",
391
- "exec_tier": 3,
392
- "status": "partial",
393
- "completed_phases": [0, 1, 2, 3, 4, 5],
394
- "current_phase": 6,
395
- "checkpoint_reached": "CP-3",
396
- "tasks_completed": 0,
397
- "tasks_total": 0,
398
- "errors": [],
399
- "can_resume": false,
400
- "resume_from_phase": null,
401
- "docs_maintained": true,
402
- "retrospective_done": true,
403
- "artifacts": {
404
- "context_snapshot_path": ".prizmkit/specs/{{FEATURE_SLUG}}/context-snapshot.md",
405
- "spec_path": ".prizmkit/specs/{{FEATURE_SLUG}}/spec.md",
406
- "plan_path": ".prizmkit/specs/{{FEATURE_SLUG}}/plan.md"
407
- },
408
- "git_commit": "",
409
- "timestamp": "<current ISO timestamp>"
410
- }
411
- ```
412
-
413
- **7c.** Run `/prizmkit-committer` → `feat({{FEATURE_ID}}): {{FEATURE_TITLE}}`, do NOT push
414
-
415
- **7d.** MANDATORY: commit must be done via `/prizmkit-committer` skill. Do NOT run manual `git add`/`git commit` as a substitute.
416
-
417
- **7e.** Do NOT run `update-feature-status.py` here — the pipeline runner handles feature-list.json updates automatically after session exit.
418
-
419
- ---
420
-
421
- ## Step 3: Commit & Finalize Session Status
422
-
423
- **3a. Commit** — The commit was handled in Phase 6 (7c) above via `/prizmkit-committer`.
360
+ **6c.** Run `/prizmkit-committer` → `feat({{FEATURE_ID}}): {{FEATURE_TITLE}}`, do NOT push
424
361
 
425
- **3b. Update session-status.json to success** After commit succeeds, update `{{SESSION_STATUS_PATH}}`:
362
+ **6d.** MANDATORY: commit must be done via `/prizmkit-committer` skill. Do NOT run manual `git add`/`git commit` as a substitute.
426
363
 
427
- Update the file to reflect final success:
428
- - Set `"status": "success"`
429
- - Set `"completed_phases": [0, 1, 2, 3, 4, 5, 6]`
430
- - Set `"git_commit": "<actual commit hash from git log -1 --format=%H>"`
431
- - Set `"timestamp": "<current ISO timestamp>"`
364
+ **6e.** Do NOT run `update-feature-status.py` here — the pipeline runner handles feature-list.json updates automatically after session exit.
432
365
 
433
- ### Step 3.1: Final Clean Check (before exit)
366
+ ### Final Clean Check (before exit)
434
367
 
435
- After updating `session-status.json`, verify repository is clean:
368
+ Verify repository is clean:
436
369
 
437
370
  ```bash
438
371
  git status --short
@@ -456,17 +389,15 @@ git commit -m "chore({{FEATURE_ID}}): include session artifacts"
456
389
  | Team Config | `{{TEAM_CONFIG_PATH}}` |
457
390
  | Dev Agent Def | {{DEV_SUBAGENT_PATH}} |
458
391
  | Reviewer Agent Def | {{REVIEWER_SUBAGENT_PATH}} |
459
- | Session Status Output | {{SESSION_STATUS_PATH}} |
460
392
  | Project Root | {{PROJECT_ROOT}} |
461
393
  | Feature List Path | {{FEATURE_LIST_PATH}} |
462
394
 
463
395
  ## Reminders
464
396
 
465
- - Tier 3: full team — Dev (implementation) → Reviewer (review) — spawn agents directly via Agent tool
397
+ - Tier 3: full team — Dev (implementation) → Reviewer (review + test) — spawn agents directly via Agent tool
466
398
  - context-snapshot.md is append-only: orchestrator writes Sections 1-4, Dev appends Implementation Log, Reviewer appends Review Notes
467
399
  - Gate checks enforce Implementation Log and Review Notes are written before proceeding
468
400
  - Do NOT use `run_in_background=true` when spawning agents
469
- - ALWAYS write preliminary session-status.json BEFORE commit (as partial), then update to success AFTER commit — this prevents pipeline from treating a terminated session as crashed
470
401
  - Commit phase must use `/prizmkit-committer`; do NOT replace with manual git commit commands
471
402
  - Before exiting, commit your feature code via `/prizmkit-committer` — the pipeline runner auto-commits any remaining files after session exit
472
403
  - When staging leftover files in the final clean check, always use explicit file names — NEVER use `git add -A`
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.0.85",
2
+ "version": "1.0.87",
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.",
@@ -25,37 +25,16 @@ git status
25
25
  - If "nothing to commit, working tree clean": inform user and stop
26
26
  - If there are changes: proceed
27
27
 
28
- #### Step 2: Diff Analysis
29
- ```bash
30
- git diff HEAD
31
- ```
32
- Analyze:
33
- - Type: feat, fix, refactor, docs, test, chore, perf, style, ci, build
34
- - Scope: affected module name
35
- - Description: imperative mood summary
28
+ #### Step 2: Condense Commit
29
+ By consulting the primary agent or based on the existing context, condense this commit message.
36
30
 
37
31
  #### Step 3: Update CHANGELOG.md
38
32
  If CHANGELOG.md exists in the project root, append an entry following Keep a Changelog format under the `[Unreleased]` section. Match the existing style in the file.
39
33
 
40
34
  #### Step 4: Git Commit
41
-
42
- 4a. Safety check before staging:
43
35
  ```bash
44
- git diff --name-only
45
- git ls-files --others --exclude-standard
36
+ git add .
46
37
  ```
47
- Review the output for sensitive files. If any file matches these patterns, **STOP and warn the user**:
48
- - `.env`, `.env.*`
49
- - `*.key`, `*.pem`, `*.p12`
50
- - `credentials.*`, `*secret*`
51
- - `*.sqlite`, `*.db` (database files)
52
-
53
- 4b. Stage and commit:
54
- ```bash
55
- git add <specific-files>
56
- git diff --cached --name-only
57
- ```
58
- Stage files explicitly by name rather than using `git add -A`, which can accidentally include sensitive files or large binaries that appeared between the safety check and staging. Review staged file list one final time, then:
59
38
  ```bash
60
39
  git commit -m "<type>(<scope>): <description>"
61
40
  ```
@@ -72,19 +51,12 @@ Then verify working tree is clean:
72
51
  git status
73
52
  ```
74
53
  - If "nothing to commit, working tree clean": commit verified successfully, proceed
75
- - **Ignore `dev-pipeline/state/` files** — these are pipeline runtime artifacts written by the pipeline runner process, not part of your changes. They will always appear dirty during pipeline sessions.
76
- - If there are other uncommitted changes remaining (excluding `dev-pipeline/state/`): **STOP** and report what files were missed. Stage the missed files explicitly by name and create a new commit (do NOT amend the previous commit — amending risks destroying unrelated changes from prior commits)
77
54
 
78
55
  #### Step 6: Optional Push
79
56
  Ask user: "Push to remote?"
80
57
  - Yes: `git push`
81
58
  - No: Stop
82
59
 
83
- ### Error Handling
84
- - If git diff is empty but untracked files exist: run `git add -N .` first (respects .gitignore)
85
- - If CHANGELOG.md script fails: update manually or ask user
86
- - If sensitive files are detected during Step 4a safety check: warn user and do NOT stage them automatically
87
-
88
60
  ## Example
89
61
 
90
62
  **Feature commit:**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "prizmkit",
3
- "version": "1.0.85",
3
+ "version": "1.0.87",
4
4
  "description": "Create a new PrizmKit-powered project with clean initialization — no framework dev files, just what you need.",
5
5
  "type": "module",
6
6
  "bin": {