@ai-dev-methodologies/rlp-desk 0.3.6 → 0.4.0

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.
@@ -55,6 +55,7 @@ HEARTBEAT_STALE_THRESHOLD="${HEARTBEAT_STALE_THRESHOLD:-120}"
55
55
  MAX_RESTARTS="${MAX_RESTARTS:-3}"
56
56
  IDLE_NUDGE_THRESHOLD="${IDLE_NUDGE_THRESHOLD:-30}"
57
57
  MAX_NUDGES="${MAX_NUDGES:-3}"
58
+ WITH_SELF_VERIFICATION="${WITH_SELF_VERIFICATION:-0}"
58
59
 
59
60
  # --- Engine Selection ---
60
61
  WORKER_ENGINE="${WORKER_ENGINE:-claude}" # claude|codex
@@ -69,6 +70,13 @@ CODEX_BIN="" # resolved by check_dependencies when engine=codex
69
70
  VERIFY_MODE="${VERIFY_MODE:-per-us}" # per-us|batch
70
71
  VERIFY_CONSENSUS="${VERIFY_CONSENSUS:-0}" # 0|1
71
72
  CONSENSUS_SCOPE="${CONSENSUS_SCOPE:-all}" # all|final-only
73
+ CB_THRESHOLD="${CB_THRESHOLD:-3}" # consecutive failures before BLOCKED (default: 3)
74
+ # Effective CB threshold: doubled when consensus mode active (AC2 auto-double)
75
+ if [[ "${VERIFY_CONSENSUS:-0}" = "1" ]]; then
76
+ EFFECTIVE_CB_THRESHOLD=$(( CB_THRESHOLD * 2 ))
77
+ else
78
+ EFFECTIVE_CB_THRESHOLD=$CB_THRESHOLD
79
+ fi
72
80
 
73
81
  # --- Derived Paths ---
74
82
  DESK="$ROOT/.claude/ralph-desk"
@@ -89,6 +97,7 @@ STATUS_FILE="$LOGS_DIR/status.json"
89
97
  SESSION_CONFIG="$LOGS_DIR/session-config.json"
90
98
  WORKER_HEARTBEAT="$LOGS_DIR/worker-heartbeat.json"
91
99
  VERIFIER_HEARTBEAT="$LOGS_DIR/verifier-heartbeat.json"
100
+ COST_LOG="$LOGS_DIR/cost-log.jsonl"
92
101
 
93
102
  # --- Session Naming ---
94
103
  TIMESTAMP=$(date +%Y%m%d-%H%M%S)
@@ -105,6 +114,8 @@ CONSECUTIVE_FAILURES=0
105
114
  PREV_CONTEXT_HASH=""
106
115
  ITERATION=0
107
116
  START_TIME=$(date +%s)
117
+ BASELINE_COMMIT="" # git HEAD at campaign start (captured before loop)
118
+ CAMPAIGN_REPORT_GENERATED=0 # guard against double-generation in cleanup trap
108
119
  VERIFIED_US="" # comma-separated list of verified US IDs (per-us mode)
109
120
  CONSENSUS_ROUND=0 # current consensus round for current US
110
121
  US_LIST="" # comma-separated US IDs from PRD (per-us mode)
@@ -148,12 +159,28 @@ replace_worker_pane() {
148
159
  log " Replacing dead $role pane $old_pane..."
149
160
  tmux kill-pane -t "$old_pane" 2>/dev/null
150
161
 
151
- # Create fresh pane via split-window off leader (omc-teams kill-and-replace pattern)
162
+ # Create fresh pane maintaining original layout: worker(top-right) / verifier(bottom-right)
152
163
  local new_pane
153
- new_pane=$(tmux split-window -h -d -t "$LEADER_PANE" -P -F '#{pane_id}' -c "$ROOT")
164
+ if [[ "$role" == "verifier" ]]; then
165
+ # Verifier goes below worker: split vertically from worker pane
166
+ if tmux display-message -t "$WORKER_PANE" -p '#{pane_id}' &>/dev/null; then
167
+ new_pane=$(tmux split-window -v -d -t "$WORKER_PANE" -P -F '#{pane_id}' -c "$ROOT")
168
+ else
169
+ # Fallback: worker pane also dead, split horizontally from leader
170
+ new_pane=$(tmux split-window -h -d -t "$LEADER_PANE" -P -F '#{pane_id}' -c "$ROOT")
171
+ fi
172
+ else
173
+ # Worker goes above verifier: split vertically before verifier pane
174
+ if tmux display-message -t "$VERIFIER_PANE" -p '#{pane_id}' &>/dev/null; then
175
+ new_pane=$(tmux split-window -v -b -d -t "$VERIFIER_PANE" -P -F '#{pane_id}' -c "$ROOT")
176
+ else
177
+ # Fallback: verifier pane also dead, split horizontally from leader
178
+ new_pane=$(tmux split-window -h -d -t "$LEADER_PANE" -P -F '#{pane_id}' -c "$ROOT")
179
+ fi
180
+ fi
154
181
 
155
182
  log " New $role pane: $new_pane (replaced $old_pane)"
156
- log_debug "[EXEC] iter=$ITERATION pane_replaced=${role} old=$old_pane new=$new_pane"
183
+ log_debug "[FLOW] iter=$ITERATION pane_replaced=${role} old=$old_pane new=$new_pane"
157
184
 
158
185
  # Update session-config.json with new pane ID
159
186
  if [[ -f "$SESSION_CONFIG" ]]; then
@@ -300,15 +327,42 @@ create_session() {
300
327
 
301
328
  fi
302
329
 
330
+ # Set pane titles and enable border labels for visual distinction
331
+ local worker_label="Worker ($WORKER_ENGINE:$WORKER_MODEL)"
332
+ local verifier_label="Verifier ($VERIFIER_ENGINE:$VERIFIER_MODEL)"
333
+ [[ "$VERIFY_CONSENSUS" = "1" ]] && verifier_label="Verifier ($VERIFIER_ENGINE:$VERIFIER_MODEL + codex:$VERIFIER_CODEX_MODEL)"
334
+ tmux select-pane -t "$LEADER_PANE" -T "Leader" 2>/dev/null
335
+ tmux select-pane -t "$WORKER_PANE" -T "$worker_label" 2>/dev/null
336
+ tmux select-pane -t "$VERIFIER_PANE" -T "$verifier_label" 2>/dev/null
337
+ # Color-coded pane borders: green=leader, blue=worker, yellow=verifier
338
+ tmux set-option -p -t "$LEADER_PANE" pane-border-style "fg=green" 2>/dev/null
339
+ tmux set-option -p -t "$WORKER_PANE" pane-border-style "fg=blue" 2>/dev/null
340
+ tmux set-option -p -t "$VERIFIER_PANE" pane-border-style "fg=yellow" 2>/dev/null
341
+ # Show pane titles in border
342
+ tmux set-option pane-border-status top 2>/dev/null
343
+ tmux set-option pane-border-format "#{?pane_active,#[fg=white bold],#[fg=grey]} #{pane_title} " 2>/dev/null
344
+
303
345
  log " Leader pane: $LEADER_PANE"
304
346
  log " Worker pane: $WORKER_PANE"
305
347
  log " Verifier pane: $VERIFIER_PANE"
306
348
 
349
+ # AC12: Capture baseline commit before writing session config
350
+ BASELINE_COMMIT=$(git -C "$ROOT" rev-parse HEAD 2>/dev/null || echo "none")
351
+
352
+ # Truncate cost-log for fresh run (previous data in versioned campaign reports)
353
+ > "$COST_LOG"
354
+
355
+ # SV flag warning for tmux mode
356
+ if (( WITH_SELF_VERIFICATION )); then
357
+ log " NOTE: --with-self-verification recorded but SV report generation is Agent-mode only"
358
+ fi
359
+
307
360
  # Write session config (atomic write)
308
361
  echo '{
309
362
  "session_name": "'"$SESSION_NAME"'",
310
363
  "slug": "'"$SLUG"'",
311
364
  "created_at": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",
365
+ "baseline_commit": "'"$BASELINE_COMMIT"'",
312
366
  "panes": {
313
367
  "leader": "'"$LEADER_PANE"'",
314
368
  "worker": "'"$WORKER_PANE"'",
@@ -340,7 +394,10 @@ create_session() {
340
394
  "heartbeat_stale_threshold": '"$HEARTBEAT_STALE_THRESHOLD"',
341
395
  "max_restarts": '"$MAX_RESTARTS"',
342
396
  "idle_nudge_threshold": '"$IDLE_NUDGE_THRESHOLD"',
343
- "max_nudges": '"$MAX_NUDGES"'
397
+ "max_nudges": '"$MAX_NUDGES"',
398
+ "cb_threshold": '"$CB_THRESHOLD"',
399
+ "effective_cb_threshold": '"$EFFECTIVE_CB_THRESHOLD"',
400
+ "with_self_verification": '"$WITH_SELF_VERIFICATION"'
344
401
  }
345
402
  }' | atomic_write "$SESSION_CONFIG"
346
403
 
@@ -704,11 +761,15 @@ write_worker_trigger() {
704
761
  if [[ -n "$next_us" ]]; then
705
762
  echo ""
706
763
  echo "---"
707
- echo "## PER-US SCOPE LOCK (this iteration)"
764
+ echo "## PER-US SCOPE LOCK (this iteration) — OVERRIDES memory contract"
765
+ echo "**IGNORE the 'Next Iteration Contract' from memory if it references a different story.**"
766
+ echo "The Leader has determined that **${next_us}** is the next unverified story."
708
767
  echo "You MUST implement ONLY **${next_us}** in this iteration."
709
768
  echo "Do NOT implement any other user stories."
710
769
  echo "When done, signal verify with us_id=\"${next_us}\" (not \"ALL\")."
711
770
  echo "Signal format: {\"iteration\": N, \"status\": \"verify\", \"us_id\": \"${next_us}\", ...}"
771
+ echo ""
772
+ echo "**Update the campaign memory's 'Next Iteration Contract' to reflect ${next_us}.**"
712
773
  elif [[ -n "$VERIFIED_US" ]]; then
713
774
  # All individual US verified — this is the final full verify iteration
714
775
  echo ""
@@ -895,6 +956,7 @@ update_status() {
895
956
 
896
957
  echo '{
897
958
  "slug": "'"$SLUG"'",
959
+ "baseline_commit": "'"${BASELINE_COMMIT:-none}"'",
898
960
  "iteration": '"$ITERATION"',
899
961
  "max_iter": '"$MAX_ITER"',
900
962
  "phase": "'"$phase"'",
@@ -922,7 +984,20 @@ write_result_log() {
922
984
  local result_file="$LOGS_DIR/iter-$(printf '%03d' $iter).result.md"
923
985
 
924
986
  local git_diff=""
925
- git_diff=$(git diff --stat HEAD~1 HEAD 2>/dev/null || echo "(no git diff available)")
987
+ if git -C "$ROOT" rev-parse HEAD &>/dev/null; then
988
+ git_diff=$(git -C "$ROOT" diff --stat HEAD 2>/dev/null || echo "(no git diff available)")
989
+ else
990
+ git_diff="(no commits in repo — cannot diff)"
991
+ fi
992
+ # Include untracked new files in result log
993
+ local result_untracked
994
+ result_untracked=$(git -C "$ROOT" ls-files --others --exclude-standard 2>/dev/null | head -20)
995
+ if [[ -n "$result_untracked" ]]; then
996
+ git_diff="${git_diff}
997
+
998
+ Untracked new files:
999
+ ${result_untracked}"
1000
+ fi
926
1001
 
927
1002
  {
928
1003
  echo "# Iteration $iter Result"
@@ -941,6 +1016,168 @@ write_result_log() {
941
1016
  } | atomic_write "$result_file"
942
1017
  }
943
1018
 
1019
+ # --- step 7d: Archive iteration artifacts (done-claim + verdict) to logs/ ---
1020
+ archive_iter_artifacts() {
1021
+ local iter="$1"
1022
+ local iter_padded
1023
+ iter_padded=$(printf '%03d' "$iter")
1024
+ if [[ -f "$DONE_CLAIM_FILE" ]]; then
1025
+ cp "$DONE_CLAIM_FILE" "$LOGS_DIR/iter-${iter_padded}-done-claim.json" 2>/dev/null
1026
+ fi
1027
+ if [[ -f "$VERDICT_FILE" ]]; then
1028
+ cp "$VERDICT_FILE" "$LOGS_DIR/iter-${iter_padded}-verify-verdict.json" 2>/dev/null
1029
+ fi
1030
+ }
1031
+
1032
+ # --- AC5: Write per-iteration cost estimate to cost-log.jsonl ---
1033
+ write_cost_log() {
1034
+ local iter="$1"
1035
+ local iter_padded
1036
+ iter_padded=$(printf '%03d' "$iter")
1037
+
1038
+ local prompt_bytes=0 claim_bytes=0 verdict_bytes=0
1039
+ local worker_prompt_file="$LOGS_DIR/iter-${iter_padded}.worker-prompt.md"
1040
+ [[ -f "$worker_prompt_file" ]] && prompt_bytes=$(wc -c < "$worker_prompt_file" 2>/dev/null || echo 0)
1041
+ [[ -f "$DONE_CLAIM_FILE" ]] && claim_bytes=$(wc -c < "$DONE_CLAIM_FILE" 2>/dev/null || echo 0)
1042
+ [[ -f "$VERDICT_FILE" ]] && verdict_bytes=$(wc -c < "$VERDICT_FILE" 2>/dev/null || echo 0)
1043
+
1044
+ local estimated_tokens=$(( (prompt_bytes + claim_bytes + verdict_bytes) / 4 ))
1045
+
1046
+ echo '{"iteration":'"$iter"',"estimated_tokens":'"$estimated_tokens"',"token_source":"estimated","prompt_bytes":'"$prompt_bytes"',"claim_bytes":'"$claim_bytes"',"verdict_bytes":'"$verdict_bytes"',"timestamp":"'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'"}' >> "$COST_LOG"
1047
+ }
1048
+
1049
+ # --- AC4: Generate campaign-report.md on all terminal states ---
1050
+ generate_campaign_report() {
1051
+ # Guard: idempotent — only generate once per campaign run
1052
+ if (( CAMPAIGN_REPORT_GENERATED )); then return 0; fi
1053
+ CAMPAIGN_REPORT_GENERATED=1
1054
+
1055
+ local final_status="UNKNOWN"
1056
+ if [[ -f "$COMPLETE_SENTINEL" ]]; then final_status="COMPLETE"
1057
+ elif [[ -f "$BLOCKED_SENTINEL" ]]; then final_status="BLOCKED"
1058
+ else final_status="TIMEOUT"; fi
1059
+
1060
+ local report_file="$LOGS_DIR/campaign-report.md"
1061
+
1062
+ # AC9: Version existing report before writing new one
1063
+ if [[ -f "$report_file" ]]; then
1064
+ local v=1
1065
+ while [[ -f "${report_file%.md}-v${v}.md" ]]; do (( v++ )); done
1066
+ mv "$report_file" "${report_file%.md}-v${v}.md"
1067
+ fi
1068
+
1069
+ local end_time
1070
+ end_time=$(date +%s)
1071
+ local elapsed=$(( end_time - START_TIME ))
1072
+
1073
+ local baseline_commit_val="${BASELINE_COMMIT:-none}"
1074
+ local files_changed=""
1075
+ if [[ "$baseline_commit_val" != "none" ]]; then
1076
+ files_changed=$(git -C "$ROOT" diff --stat "${baseline_commit_val}" 2>/dev/null || echo "(git diff unavailable)")
1077
+ elif git -C "$ROOT" rev-parse HEAD &>/dev/null; then
1078
+ files_changed=$(git -C "$ROOT" diff --stat HEAD 2>/dev/null || echo "(git diff unavailable)")
1079
+ else
1080
+ files_changed="(no commits in repo — cannot diff)"
1081
+ fi
1082
+ # Include untracked new files
1083
+ local untracked
1084
+ untracked=$(git -C "$ROOT" ls-files --others --exclude-standard 2>/dev/null | head -20)
1085
+ if [[ -n "$untracked" ]]; then
1086
+ files_changed="${files_changed}
1087
+
1088
+ Untracked new files:
1089
+ ${untracked}"
1090
+ fi
1091
+
1092
+ local sv_summary=""
1093
+ if (( WITH_SELF_VERIFICATION )); then
1094
+ local sv_report
1095
+ sv_report=$(ls -t "$LOGS_DIR"/self-verification-report-*.md 2>/dev/null | head -1)
1096
+ if [[ -n "$sv_report" ]]; then
1097
+ sv_summary="See: $(basename "$sv_report")"
1098
+ else
1099
+ sv_summary="SV report generation requires Agent mode. Flag recorded in session-config."
1100
+ fi
1101
+ else
1102
+ sv_summary="N/A — --with-self-verification not enabled"
1103
+ fi
1104
+
1105
+ {
1106
+ echo "# Campaign Report: $SLUG"
1107
+ echo ""
1108
+ echo "Generated: $(date -u +%Y-%m-%dT%H:%M:%SZ) | Status: $final_status | Iterations: $ITERATION"
1109
+ echo ""
1110
+ echo "## Objective"
1111
+ local prd_file="$DESK/plans/prd-$SLUG.md"
1112
+ if [[ -f "$prd_file" ]]; then
1113
+ grep '^## Objective' -A3 "$prd_file" 2>/dev/null | tail -n +2 | head -3
1114
+ else
1115
+ echo "(PRD not found)"
1116
+ fi
1117
+ echo ""
1118
+ echo "## Execution Summary"
1119
+ echo "- Terminal state: $final_status"
1120
+ echo "- Iterations run: $ITERATION / $MAX_ITER"
1121
+ echo "- Elapsed: ${elapsed}s"
1122
+ echo "- Worker model: $WORKER_MODEL ($WORKER_ENGINE)"
1123
+ echo "- Verifier model: $VERIFIER_MODEL ($VERIFIER_ENGINE)"
1124
+ echo ""
1125
+ echo "## US Status"
1126
+ echo "- Verified: ${VERIFIED_US:-none}"
1127
+ echo "- Consecutive failures at end: $CONSECUTIVE_FAILURES"
1128
+ echo ""
1129
+ echo "## Verification Results"
1130
+ local ri=1
1131
+ while (( ri <= ITERATION )); do
1132
+ local iter_dc="$LOGS_DIR/iter-$(printf '%03d' $ri)-done-claim.json"
1133
+ if [[ -f "$iter_dc" ]]; then
1134
+ local us_id
1135
+ us_id=$(jq -r '.us_id // "unknown"' "$iter_dc" 2>/dev/null)
1136
+ echo "- $(basename "$iter_dc"): us_id=$us_id"
1137
+ fi
1138
+ (( ri++ ))
1139
+ done
1140
+ echo ""
1141
+ echo "## Issues Encountered"
1142
+ local fi_found=0
1143
+ local fi_i=1
1144
+ while (( fi_i <= ITERATION )); do
1145
+ local fix_f="$LOGS_DIR/iter-$(printf '%03d' $fi_i).fix-contract.md"
1146
+ if [[ -f "$fix_f" ]]; then
1147
+ echo "- $(basename "$fix_f")"
1148
+ fi_found=1
1149
+ fi
1150
+ (( fi_i++ ))
1151
+ done
1152
+ (( fi_found == 0 )) && echo "- None"
1153
+ echo ""
1154
+ echo "## Cost & Performance"
1155
+ if [[ -f "$COST_LOG" ]]; then
1156
+ local total_tokens=0
1157
+ while IFS= read -r line; do
1158
+ local t
1159
+ t=$(echo "$line" | jq -r '.estimated_tokens // 0' 2>/dev/null || echo 0)
1160
+ total_tokens=$(( total_tokens + t ))
1161
+ done < "$COST_LOG"
1162
+ echo "- Total estimated tokens: $total_tokens (source: estimated, tmux mode)"
1163
+ echo "- See: cost-log.jsonl for per-iteration breakdown"
1164
+ else
1165
+ echo "- No cost data available"
1166
+ fi
1167
+ echo ""
1168
+ echo "## SV Summary"
1169
+ echo "$sv_summary"
1170
+ echo ""
1171
+ echo "## Files Changed"
1172
+ echo '```'
1173
+ echo "$files_changed"
1174
+ echo '```'
1175
+ echo "Note: Files Changed may include pre-existing uncommitted changes if the campaign started in a dirty worktree."
1176
+ } | atomic_write "$report_file"
1177
+
1178
+ log "Campaign report written: $report_file"
1179
+ }
1180
+
944
1181
  # =============================================================================
945
1182
  # Sentinel Writers
946
1183
  # =============================================================================
@@ -1002,6 +1239,9 @@ cleanup() {
1002
1239
  setopt local_options nonomatch 2>/dev/null
1003
1240
  rm -f "$LOGS_DIR"/*.tmp.* "$MEMOS_DIR"/*.tmp.* 2>/dev/null
1004
1241
 
1242
+ # AC4: Generate campaign report on all terminal states (always-on)
1243
+ generate_campaign_report
1244
+
1005
1245
  # Print summary
1006
1246
  local end_time
1007
1247
  end_time=$(date +%s)
@@ -1018,13 +1258,13 @@ cleanup() {
1018
1258
  local end_ts=$(date +%s)
1019
1259
  local elapsed=$((end_ts - START_TIME))
1020
1260
 
1021
- log_debug "[EXEC] final status=$final_status iterations=$ITERATION elapsed=${elapsed}s"
1261
+ log_debug "[FLOW] final status=$final_status iterations=$ITERATION elapsed=${elapsed}s"
1022
1262
 
1023
1263
  # --- Validation ---
1024
- log_debug "[VALIDATE] === Execution Validation ==="
1264
+ log_debug "[FLOW] === Execution Validation ==="
1025
1265
 
1026
1266
  # 1. Did the correct verify mode run?
1027
- log_debug "[VALIDATE] verify_mode=$VERIFY_MODE configured=true"
1267
+ log_debug "[FLOW] verify_mode=$VERIFY_MODE configured=true"
1028
1268
 
1029
1269
  # 2. Per-US: were all US individually verified?
1030
1270
  if [[ "$VERIFY_MODE" = "per-us" ]]; then
@@ -1038,39 +1278,39 @@ cleanup() {
1038
1278
 
1039
1279
  if [[ "$final_status" = "COMPLETE" ]]; then
1040
1280
  if (( verified_count >= expected_count )); then
1041
- log_debug "[VALIDATE] per_us_coverage=PASS verified=$verified_count/$expected_count us=$VERIFIED_US"
1281
+ log_debug "[FLOW] per_us_coverage=PASS verified=$verified_count/$expected_count us=$VERIFIED_US"
1042
1282
  else
1043
- log_debug "[VALIDATE] per_us_coverage=FAIL verified=$verified_count/$expected_count expected=$expected_us got=$VERIFIED_US"
1283
+ log_debug "[FLOW] per_us_coverage=FAIL verified=$verified_count/$expected_count expected=$expected_us got=$VERIFIED_US"
1044
1284
  fi
1045
1285
  else
1046
- log_debug "[VALIDATE] per_us_coverage=INCOMPLETE verified=$verified_count/$expected_count status=$final_status"
1286
+ log_debug "[FLOW] per_us_coverage=INCOMPLETE verified=$verified_count/$expected_count status=$final_status"
1047
1287
  fi
1048
1288
  fi
1049
1289
 
1050
1290
  # 3. Consensus: were both engines used?
1051
1291
  if [[ "$VERIFY_CONSENSUS" = "1" ]]; then
1052
1292
  if [[ -n "${CLAUDE_VERDICT:-}" && -n "${CODEX_VERDICT:-}" ]]; then
1053
- log_debug "[VALIDATE] consensus=USED claude=$CLAUDE_VERDICT codex=$CODEX_VERDICT rounds=$CONSENSUS_ROUND"
1293
+ log_debug "[FLOW] consensus=USED claude=$CLAUDE_VERDICT codex=$CODEX_VERDICT rounds=$CONSENSUS_ROUND"
1054
1294
  else
1055
- log_debug "[VALIDATE] consensus=NOT_TRIGGERED claude=${CLAUDE_VERDICT:-none} codex=${CODEX_VERDICT:-none}"
1295
+ log_debug "[FLOW] consensus=NOT_TRIGGERED claude=${CLAUDE_VERDICT:-none} codex=${CODEX_VERDICT:-none}"
1056
1296
  fi
1057
1297
  fi
1058
1298
 
1059
1299
  # 4. Engine match: did the configured engines actually run?
1060
- local worker_dispatches=$(grep -c '\[EXEC\].*phase=worker.*dispatched=true' "$DEBUG_LOG" 2>/dev/null || echo 0)
1061
- local verifier_dispatches=$(grep -c '\[EXEC\].*phase=verifier.*dispatched=true' "$DEBUG_LOG" 2>/dev/null || echo 0)
1062
- log_debug "[VALIDATE] dispatches worker=$worker_dispatches verifier=$verifier_dispatches"
1300
+ local worker_dispatches=$(grep -c '\[FLOW\].*phase=worker.*dispatched=true' "$DEBUG_LOG" 2>/dev/null || echo 0)
1301
+ local verifier_dispatches=$(grep -c '\[FLOW\].*phase=verifier.*dispatched=true' "$DEBUG_LOG" 2>/dev/null || echo 0)
1302
+ log_debug "[FLOW] dispatches worker=$worker_dispatches verifier=$verifier_dispatches"
1063
1303
 
1064
1304
  # 5. Fix loops: how many fix contracts were generated?
1065
- local fix_count=$(grep -c '\[EXEC\].*phase=fix_loop' "$DEBUG_LOG" 2>/dev/null || echo 0)
1066
- log_debug "[VALIDATE] fix_loops=$fix_count consecutive_failures=$CONSECUTIVE_FAILURES"
1305
+ local fix_count=$(grep -c '\[DECIDE\].*phase=fix_loop' "$DEBUG_LOG" 2>/dev/null || echo 0)
1306
+ log_debug "[FLOW] fix_loops=$fix_count consecutive_failures=$CONSECUTIVE_FAILURES"
1067
1307
 
1068
1308
  # 6. Circuit breakers: any triggered?
1069
- local cb_count=$(grep -c '\[EXEC\].*circuit_breaker=' "$DEBUG_LOG" 2>/dev/null || echo 0)
1070
- log_debug "[VALIDATE] circuit_breakers_triggered=$cb_count"
1309
+ local cb_count=$(grep -c '\[GOV\].*circuit_breaker=' "$DEBUG_LOG" 2>/dev/null || echo 0)
1310
+ log_debug "[FLOW] circuit_breakers_triggered=$cb_count"
1071
1311
 
1072
1312
  # 7. Overall result
1073
- log_debug "[VALIDATE] result=$final_status iterations=$ITERATION elapsed=${elapsed}s verified_us=$VERIFIED_US"
1313
+ log_debug "[FLOW] result=$final_status iterations=$ITERATION elapsed=${elapsed}s verified_us=$VERIFIED_US"
1074
1314
  fi
1075
1315
 
1076
1316
  echo ""
@@ -1163,7 +1403,7 @@ poll_for_signal() {
1163
1403
  (( HEARTBEAT_STALE_COUNT++ ))
1164
1404
  # Circuit breaker: 3 consecutive heartbeat stale events
1165
1405
  if (( HEARTBEAT_STALE_COUNT >= 3 )); then
1166
- log_debug "[EXEC] iter=$ITERATION circuit_breaker=heartbeat_stale detail=\"3 consecutive heartbeat stale events\""
1406
+ log_debug "[GOV] iter=$ITERATION circuit_breaker=heartbeat_stale detail=\"3 consecutive heartbeat stale events\""
1167
1407
  log_error "Circuit breaker: 3 consecutive heartbeat stale events"
1168
1408
  return 1
1169
1409
  fi
@@ -1186,7 +1426,7 @@ poll_for_signal() {
1186
1426
  poll_capture=$(tmux capture-pane -t "$pane_id" -p 2>/dev/null)
1187
1427
  if echo "$poll_capture" | grep -q "Do you want to" 2>/dev/null; then
1188
1428
  log " Permission prompt detected during poll, auto-approving..."
1189
- log_debug "[EXEC] iter=$ITERATION permission_prompt_auto_approved=true"
1429
+ log_debug "[FLOW] iter=$ITERATION permission_prompt_auto_approved=true"
1190
1430
  tmux send-keys -t "$pane_id" Enter
1191
1431
  sleep 0.5
1192
1432
  fi
@@ -1362,9 +1602,9 @@ run_consensus_verification() {
1362
1602
  CLAUDE_VERDICT=""
1363
1603
  CODEX_VERDICT=""
1364
1604
 
1365
- while (( CONSENSUS_ROUND < 3 )); do
1605
+ while (( CONSENSUS_ROUND < 6 )); do
1366
1606
  (( CONSENSUS_ROUND++ ))
1367
- log " Consensus round $CONSENSUS_ROUND/3..."
1607
+ log " Consensus round $CONSENSUS_ROUND/6..."
1368
1608
 
1369
1609
  # Run claude verifier first
1370
1610
  if ! run_single_verifier "$iter" "claude" "$VERIFIER_MODEL" "-claude" "$claude_verdict_file"; then
@@ -1372,7 +1612,7 @@ run_consensus_verification() {
1372
1612
  return 1
1373
1613
  fi
1374
1614
  CLAUDE_VERDICT=$(jq -r '.verdict' "$claude_verdict_file" 2>/dev/null)
1375
- log_debug "[EXEC] iter=$iter phase=consensus_claude verdict=$CLAUDE_VERDICT model=$VERIFIER_MODEL"
1615
+ log_debug "[GOV] iter=$iter phase=consensus_claude verdict=$CLAUDE_VERDICT model=$VERIFIER_MODEL"
1376
1616
 
1377
1617
  # Run codex verifier second
1378
1618
  if ! run_single_verifier "$iter" "codex" "$VERIFIER_CODEX_MODEL" "-codex" "$codex_verdict_file"; then
@@ -1380,14 +1620,14 @@ run_consensus_verification() {
1380
1620
  return 1
1381
1621
  fi
1382
1622
  CODEX_VERDICT=$(jq -r '.verdict' "$codex_verdict_file" 2>/dev/null)
1383
- log_debug "[EXEC] iter=$iter phase=consensus_codex verdict=$CODEX_VERDICT model=$VERIFIER_CODEX_MODEL reasoning=$VERIFIER_CODEX_REASONING"
1623
+ log_debug "[GOV] iter=$iter phase=consensus_codex verdict=$CODEX_VERDICT model=$VERIFIER_CODEX_MODEL reasoning=$VERIFIER_CODEX_REASONING"
1384
1624
 
1385
1625
  log " Consensus: claude=$CLAUDE_VERDICT codex=$CODEX_VERDICT"
1386
1626
  local _combined_action="retry"
1387
1627
  if [[ "$CLAUDE_VERDICT" = "pass" && "$CODEX_VERDICT" = "pass" ]]; then _combined_action="pass"
1388
- elif (( CONSENSUS_ROUND >= 3 )); then _combined_action="blocked"
1628
+ elif (( CONSENSUS_ROUND >= 6 )); then _combined_action="blocked"
1389
1629
  fi
1390
- log_debug "[EXEC] iter=$iter phase=consensus round=$CONSENSUS_ROUND claude=$CLAUDE_VERDICT codex=$CODEX_VERDICT combined_action=$_combined_action"
1630
+ log_debug "[GOV] iter=$iter phase=consensus round=$CONSENSUS_ROUND claude=$CLAUDE_VERDICT codex=$CODEX_VERDICT combined_action=$_combined_action"
1391
1631
 
1392
1632
  # Both pass → success
1393
1633
  if [[ "$CLAUDE_VERDICT" = "pass" && "$CODEX_VERDICT" = "pass" ]]; then
@@ -1409,7 +1649,7 @@ run_consensus_verification() {
1409
1649
  fi
1410
1650
 
1411
1651
  # Consensus disagreement
1412
- log_debug "[EXEC] iter=$iter phase=consensus_disagreement round=$CONSENSUS_ROUND claude=$CLAUDE_VERDICT codex=$CODEX_VERDICT action=fix_contract"
1652
+ log_debug "[GOV] iter=$iter phase=consensus_disagreement round=$CONSENSUS_ROUND claude=$CLAUDE_VERDICT codex=$CODEX_VERDICT action=fix_contract"
1413
1653
 
1414
1654
  # NOTE: pre_existing_failure heuristic was removed (v0.3.5).
1415
1655
  # It used unreliable grep-in-description string matching to classify
@@ -1442,14 +1682,19 @@ run_consensus_verification() {
1442
1682
 
1443
1683
  # If this is not the last round, the caller will dispatch the Worker with the fix contract
1444
1684
  # For now, write a fail verdict so the main loop can handle the fix loop
1445
- if (( CONSENSUS_ROUND < 3 )); then
1446
- # Create a merged fail verdict for the main loop
1685
+ if (( CONSENSUS_ROUND < 6 )); then
1686
+ # Create a merged fail verdict for the main loop — include issues from BOTH verdicts
1687
+ local merged_issues="[]"
1688
+ local claude_issues codex_issues
1689
+ claude_issues=$(jq -c '[.issues[]? | . + {"source": "claude"}]' "$claude_verdict_file" 2>/dev/null || echo '[]')
1690
+ codex_issues=$(jq -c '[.issues[]? | . + {"source": "codex"}]' "$codex_verdict_file" 2>/dev/null || echo '[]')
1691
+ merged_issues=$(echo "$claude_issues $codex_issues" | jq -s 'add // []')
1447
1692
  {
1448
1693
  echo '{'
1449
1694
  echo ' "verdict": "fail",'
1450
1695
  echo ' "verified_at_utc": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",'
1451
- echo ' "summary": "Consensus disagreement (round '"$CONSENSUS_ROUND"'/3): claude='"$CLAUDE_VERDICT"' codex='"$CODEX_VERDICT"'",'
1452
- echo ' "issues": [],'
1696
+ echo ' "summary": "Consensus disagreement (round '"$CONSENSUS_ROUND"'/6): claude='"$CLAUDE_VERDICT"' codex='"$CODEX_VERDICT"'",'
1697
+ echo ' "issues": '"$merged_issues"','
1453
1698
  echo ' "recommended_state_transition": "continue",'
1454
1699
  echo ' "consensus": { "claude": "'"$CLAUDE_VERDICT"'", "codex": "'"$CODEX_VERDICT"'", "round": '"$CONSENSUS_ROUND"' }'
1455
1700
  echo '}'
@@ -1458,16 +1703,20 @@ run_consensus_verification() {
1458
1703
  fi
1459
1704
  done
1460
1705
 
1461
- # Max consensus rounds exceeded
1462
- log_error "Consensus failed after 3 rounds"
1706
+ # Max consensus rounds exceeded — include issues from both verdicts
1707
+ log_error "Consensus failed after 6 rounds"
1708
+ local final_claude_issues final_codex_issues final_merged_issues
1709
+ final_claude_issues=$(jq -c '[.issues[]? | . + {"source": "claude"}]' "$claude_verdict_file" 2>/dev/null || echo '[]')
1710
+ final_codex_issues=$(jq -c '[.issues[]? | . + {"source": "codex"}]' "$codex_verdict_file" 2>/dev/null || echo '[]')
1711
+ final_merged_issues=$(echo "$final_claude_issues $final_codex_issues" | jq -s 'add // []')
1463
1712
  {
1464
1713
  echo '{'
1465
1714
  echo ' "verdict": "fail",'
1466
1715
  echo ' "verified_at_utc": "'"$(date -u +%Y-%m-%dT%H:%M:%SZ)"'",'
1467
- echo ' "summary": "Consensus failed after 3 rounds: claude='"$CLAUDE_VERDICT"' codex='"$CODEX_VERDICT"'",'
1468
- echo ' "issues": [],'
1716
+ echo ' "summary": "Consensus failed after 6 rounds: claude='"$CLAUDE_VERDICT"' codex='"$CODEX_VERDICT"'",'
1717
+ echo ' "issues": '"$final_merged_issues"','
1469
1718
  echo ' "recommended_state_transition": "blocked",'
1470
- echo ' "consensus": { "claude": "'"$CLAUDE_VERDICT"'", "codex": "'"$CODEX_VERDICT"'", "round": 3 }'
1719
+ echo ' "consensus": { "claude": "'"$CLAUDE_VERDICT"'", "codex": "'"$CODEX_VERDICT"'", "round": 6 }'
1471
1720
  echo '}'
1472
1721
  } | atomic_write "$VERDICT_FILE"
1473
1722
  return 1
@@ -1509,6 +1758,15 @@ main() {
1509
1758
  fi
1510
1759
  mkdir -p "$LOGS_DIR" 2>/dev/null
1511
1760
 
1761
+ # --- AC7: debug.log versioning: rename existing debug.log before fresh run ---
1762
+ if (( DEBUG )) && [[ -f "$DEBUG_LOG" ]]; then
1763
+ local dbg_n=1
1764
+ while [[ -f "${DEBUG_LOG%.log}-v${dbg_n}.log" ]]; do
1765
+ (( dbg_n++ ))
1766
+ done
1767
+ mv "$DEBUG_LOG" "${DEBUG_LOG%.log}-v${dbg_n}.log"
1768
+ fi
1769
+
1512
1770
  # --- Startup ---
1513
1771
  log "Ralph Desk Tmux Runner starting..."
1514
1772
  log " Slug: $SLUG"
@@ -1531,10 +1789,11 @@ main() {
1531
1789
  fi
1532
1790
  local us_count=$(echo "$us_list" | tr ',' '\n' | grep -c 'US-')
1533
1791
 
1534
- log_debug "[PLAN] slug=$SLUG us_count=$us_count us_list=$us_list"
1535
- log_debug "[PLAN] worker_engine=$WORKER_ENGINE worker_model=$WORKER_MODEL"
1536
- log_debug "[PLAN] verifier_engine=$VERIFIER_ENGINE verifier_model=$VERIFIER_MODEL"
1537
- log_debug "[PLAN] verify_mode=$VERIFY_MODE consensus=$VERIFY_CONSENSUS consensus_scope=$CONSENSUS_SCOPE max_iter=$MAX_ITER"
1792
+ log_debug "[OPTION] slug=$SLUG us_count=$us_count us_list=$us_list"
1793
+ log_debug "[OPTION] worker_engine=$WORKER_ENGINE worker_model=$WORKER_MODEL"
1794
+ log_debug "[OPTION] verifier_engine=$VERIFIER_ENGINE verifier_model=$VERIFIER_MODEL"
1795
+ log_debug "[OPTION] verify_mode=$VERIFY_MODE consensus=$VERIFY_CONSENSUS consensus_scope=$CONSENSUS_SCOPE max_iter=$MAX_ITER"
1796
+ log_debug "[OPTION] cb_threshold=$CB_THRESHOLD effective_cb_threshold=$EFFECTIVE_CB_THRESHOLD iter_timeout=$ITER_TIMEOUT with_self_verification=$WITH_SELF_VERIFICATION debug=$DEBUG"
1538
1797
 
1539
1798
  if [[ "$VERIFY_MODE" = "per-us" ]]; then
1540
1799
  # Build expected flow
@@ -1543,13 +1802,13 @@ main() {
1543
1802
  expected_flow="${expected_flow}worker->verify($us)->"
1544
1803
  done
1545
1804
  expected_flow="${expected_flow}verify(ALL)->COMPLETE"
1546
- log_debug "[PLAN] expected_flow=$expected_flow"
1805
+ log_debug "[OPTION] expected_flow=$expected_flow"
1547
1806
  else
1548
- log_debug "[PLAN] expected_flow=worker(all)->verify(ALL)->COMPLETE"
1807
+ log_debug "[OPTION] expected_flow=worker(all)->verify(ALL)->COMPLETE"
1549
1808
  fi
1550
1809
 
1551
1810
  if [[ "$VERIFY_CONSENSUS" = "1" ]]; then
1552
- log_debug "[PLAN] consensus_flow=each_verify_runs_claude+codex_both_must_pass"
1811
+ log_debug "[OPTION] consensus_flow=each_verify_runs_claude+codex_both_must_pass"
1553
1812
  fi
1554
1813
  fi
1555
1814
 
@@ -1559,6 +1818,18 @@ main() {
1559
1818
  if [[ -f "$prd_file" ]]; then
1560
1819
  US_LIST=$(grep -oE 'US-[0-9]+' "$prd_file" | sort -u | tr '\n' ',' | sed 's/,$//')
1561
1820
  fi
1821
+
1822
+ # Initialize VERIFIED_US from memory's Completed Stories (carry over previous runs)
1823
+ local memory_file="$DESK/memos/${SLUG}-memory.md"
1824
+ if [[ -f "$memory_file" ]]; then
1825
+ local completed_us
1826
+ completed_us=$(sed -n '/^## Completed Stories$/,/^## /p' "$memory_file" 2>/dev/null | grep '^- US-' | sed 's/^- \(US-[0-9]*\):.*/\1/' | sort -u | tr '\n' ',' | sed 's/,$//')
1827
+ if [[ -n "$completed_us" ]]; then
1828
+ VERIFIED_US="$completed_us"
1829
+ log " Loaded completed stories from memory: $VERIFIED_US"
1830
+ log_debug "[FLOW] loaded_verified_us_from_memory=$VERIFIED_US"
1831
+ fi
1832
+ fi
1562
1833
  fi
1563
1834
 
1564
1835
  # Dependency checks
@@ -1592,7 +1863,7 @@ main() {
1592
1863
  ITER_START_TIME=$(date +%s)
1593
1864
  local _iter_contract=""
1594
1865
  _iter_contract=$(sed -n '/^## Next Iteration Contract$/,/^## /{ /^## Next/d; /^## [^N]/d; p; }' "$MEMORY_FILE" 2>/dev/null | head -1 | tr '\n' ' ')
1595
- log_debug "[EXEC] iter=$ITERATION start contract=\"${_iter_contract:-none}\""
1866
+ log_debug "[FLOW] iter=$ITERATION start contract=\"${_iter_contract:-none}\""
1596
1867
 
1597
1868
  # --- governance.md s7 step 1: Check sentinels ---
1598
1869
  if [[ -f "$COMPLETE_SENTINEL" ]]; then
@@ -1644,7 +1915,7 @@ main() {
1644
1915
  fi
1645
1916
  tmux send-keys -t "$WORKER_PANE" -l -- "$worker_launch"
1646
1917
  tmux send-keys -t "$WORKER_PANE" Enter
1647
- log_debug "[EXEC] iter=$ITERATION phase=worker engine=$WORKER_ENGINE model=$WORKER_MODEL dispatched=true"
1918
+ log_debug "[FLOW] iter=$ITERATION phase=worker engine=$WORKER_ENGINE model=$WORKER_MODEL dispatched=true"
1648
1919
 
1649
1920
  # Step 5b: Wait for claude TUI to be ready (tmux pattern)
1650
1921
  if ! wait_for_pane_ready "$WORKER_PANE" 30; then
@@ -1669,7 +1940,7 @@ main() {
1669
1940
  pane_check=$(tmux capture-pane -t "$WORKER_PANE" -p 2>/dev/null)
1670
1941
  if echo "$pane_check" | grep -qi "esc to interrupt\|thinking\|working\|kneading\|crunching\|clauding\|billowing\|brewing\|tinkering\|burrowing\|saut\|Exploring\|Running\|exec\|Explored" 2>/dev/null; then
1671
1942
  log_debug "Worker started working after $((submit_attempts + 1)) submit checks"
1672
- log_debug "[EXEC] iter=$ITERATION worker_submit_check=OK attempts=$((submit_attempts + 1))"
1943
+ log_debug "[FLOW] iter=$ITERATION worker_submit_check=OK attempts=$((submit_attempts + 1))"
1673
1944
  break
1674
1945
  fi
1675
1946
  # After 8 failed attempts, try C-u clear + re-type (omc-teams adaptive retry)
@@ -1687,7 +1958,7 @@ main() {
1687
1958
  done
1688
1959
  if (( submit_attempts >= 15 )); then
1689
1960
  log " WARNING: Could not confirm Worker started working after 15 attempts"
1690
- log_debug "[EXEC] iter=$ITERATION worker_submit_check=FAILED attempts=15"
1961
+ log_debug "[FLOW] iter=$ITERATION worker_submit_check=FAILED attempts=15"
1691
1962
  fi
1692
1963
 
1693
1964
  # --- governance.md s7 step 5+6: Poll for Worker completion ---
@@ -1696,7 +1967,7 @@ main() {
1696
1967
  while (( ! worker_poll_done )); do
1697
1968
  if poll_for_signal "$SIGNAL_FILE" "$WORKER_HEARTBEAT" "$WORKER_PANE" "$worker_launch" "Worker"; then
1698
1969
  worker_poll_done=1
1699
- log_debug "[EXEC] iter=$ITERATION poll_signal_received=true"
1970
+ log_debug "[FLOW] iter=$ITERATION poll_signal_received=true"
1700
1971
  else
1701
1972
  # Check if Worker is still actively running (not stuck)
1702
1973
  local worker_cmd
@@ -1706,41 +1977,41 @@ main() {
1706
1977
  local iter_elapsed=$(( $(date +%s) - ITER_START_TIME ))
1707
1978
  if (( iter_elapsed >= HARD_CEILING )); then
1708
1979
  log_error "Worker hit hard ceiling (${HARD_CEILING}s = 3x iter_timeout). Killing iteration."
1709
- log_debug "[EXEC] iter=$ITERATION hard_ceiling_hit=true elapsed=${iter_elapsed}s ceiling=${HARD_CEILING}s process=$worker_cmd"
1980
+ log_debug "[GOV] iter=$ITERATION hard_ceiling_hit=true elapsed=${iter_elapsed}s ceiling=${HARD_CEILING}s process=$worker_cmd"
1710
1981
  tmux send-keys -t "$WORKER_PANE" C-c 2>/dev/null
1711
1982
  sleep 1
1712
- WORKER_PANE=$(replace_worker_pane "$WORKER_PANE" "worker")
1713
- update_status "worker" "hard_timeout"
1714
- worker_poll_done=1
1715
- break
1983
+ write_blocked_sentinel "Worker hit hard ceiling (${HARD_CEILING}s). Pane preserved for inspection."
1984
+ update_status "blocked" "hard_timeout"
1985
+ return 1
1716
1986
  fi
1717
1987
  log " Worker timed out but still active ($worker_cmd). Extending poll... (${iter_elapsed}s/${HARD_CEILING}s)"
1718
- log_debug "[EXEC] iter=$ITERATION timeout_active=true process=$worker_cmd elapsed=${iter_elapsed}s ceiling=${HARD_CEILING}s"
1719
- log_debug "[EXEC] iter=$ITERATION poll_extended=true worker_cmd=$worker_cmd"
1988
+ log_debug "[GOV] iter=$ITERATION timeout_active=true process=$worker_cmd elapsed=${iter_elapsed}s ceiling=${HARD_CEILING}s"
1989
+ log_debug "[FLOW] iter=$ITERATION poll_extended=true worker_cmd=$worker_cmd"
1720
1990
  update_status "worker" "slow"
1721
1991
  # Loop continues — re-poll same iteration
1722
1992
  else
1723
1993
  # Worker is truly dead/stuck
1724
1994
  (( MONITOR_FAILURE_COUNT++ ))
1725
- log_debug "[EXEC] iter=$ITERATION monitor_failure=$MONITOR_FAILURE_COUNT/3"
1995
+ log_debug "[GOV] iter=$ITERATION monitor_failure=$MONITOR_FAILURE_COUNT/3"
1726
1996
  if (( MONITOR_FAILURE_COUNT >= 3 )); then
1727
- log_debug "[EXEC] iter=$ITERATION circuit_breaker=monitor_failures detail=\"3 consecutive monitor failures\""
1997
+ log_debug "[GOV] iter=$ITERATION circuit_breaker=monitor_failures detail=\"3 consecutive monitor failures\""
1728
1998
  write_blocked_sentinel "3 consecutive monitor failures (worker not active)"
1729
1999
  update_status "blocked" "monitor_failures"
1730
2000
  return 1
1731
2001
  fi
1732
2002
  log " WARNING: Worker poll failed (monitor failure $MONITOR_FAILURE_COUNT/3)"
1733
2003
  update_status "worker" "poll_failed"
1734
- worker_poll_done=1 # exit poll loop, continue to next iteration
1735
- log_debug "[EXEC] iter=$ITERATION poll_worker_dead=true worker_cmd=$worker_cmd"
1736
- # Worker is truly dead/stuck kill and replace pane (omc-teams pattern)
1737
- WORKER_PANE=$(replace_worker_pane "$WORKER_PANE" "worker")
2004
+ log_debug "[FLOW] iter=$ITERATION poll_worker_dead=true worker_cmd=$worker_cmd"
2005
+ # Worker is truly dead/stuck — BLOCK and let user decide
2006
+ write_blocked_sentinel "Worker process dead/stuck (poll failed). Pane preserved for inspection."
2007
+ update_status "blocked" "worker_dead"
2008
+ return 1
1738
2009
  fi
1739
2010
  fi
1740
2011
  done
1741
2012
 
1742
2013
  if [[ ! -f "$SIGNAL_FILE" ]]; then
1743
- log_debug "[EXEC] iter=$ITERATION no_signal_after_poll=true continuing"
2014
+ log_debug "[FLOW] iter=$ITERATION no_signal_after_poll=true continuing"
1744
2015
  # No signal — monitor failure, go to next iteration
1745
2016
  continue
1746
2017
  fi
@@ -1759,7 +2030,7 @@ main() {
1759
2030
  # Read us_id early for EXEC logging (also used later in verify branch)
1760
2031
  local signal_us_id_early=""
1761
2032
  signal_us_id_early=$(jq -r '.us_id // empty' "$SIGNAL_FILE" 2>/dev/null)
1762
- log_debug "[EXEC] iter=$ITERATION phase=worker_signal status=$signal_status us_id=${signal_us_id_early:-none} summary=\"$signal_summary\""
2033
+ log_debug "[FLOW] iter=$ITERATION phase=worker_signal status=$signal_status us_id=${signal_us_id_early:-none} summary=\"$signal_summary\""
1763
2034
 
1764
2035
  case "$signal_status" in
1765
2036
  continue)
@@ -1827,7 +2098,7 @@ main() {
1827
2098
  fi
1828
2099
  tmux send-keys -t "$VERIFIER_PANE" -l -- "$verifier_launch"
1829
2100
  tmux send-keys -t "$VERIFIER_PANE" Enter
1830
- log_debug "[EXEC] iter=$ITERATION phase=verifier engine=$VERIFIER_ENGINE model=$VERIFIER_MODEL scope=${signal_us_id:-all} dispatched=true"
2101
+ log_debug "[FLOW] iter=$ITERATION phase=verifier engine=$VERIFIER_ENGINE model=$VERIFIER_MODEL scope=${signal_us_id:-all} dispatched=true"
1831
2102
 
1832
2103
  # Step 7b: Wait for TUI to be ready
1833
2104
  if ! wait_for_pane_ready "$VERIFIER_PANE" 30; then
@@ -1871,10 +2142,10 @@ main() {
1871
2142
  log " Polling for verify-verdict.json..."
1872
2143
  if ! poll_for_signal "$VERDICT_FILE" "$VERIFIER_HEARTBEAT" "$VERIFIER_PANE" "$verifier_launch" "Verifier"; then
1873
2144
  log_error "Verifier poll failed"
1874
- update_status "verifier" "poll_failed"
1875
- # Verifier is dead/stuck kill and replace pane (omc-teams pattern)
1876
- VERIFIER_PANE=$(replace_worker_pane "$VERIFIER_PANE" "verifier")
1877
- continue
2145
+ # Verifier is dead/stuck — BLOCK and let user decide
2146
+ write_blocked_sentinel "Verifier process dead/stuck (poll failed). Pane preserved for inspection."
2147
+ update_status "blocked" "verifier_dead"
2148
+ return 1
1878
2149
  fi
1879
2150
  fi
1880
2151
 
@@ -1889,7 +2160,7 @@ main() {
1889
2160
  log " Verifier: verdict=$verdict recommended=$recommended"
1890
2161
  log " Verifier summary: \"$verdict_summary\""
1891
2162
  local _issues_count=$(jq '.issues | length' "$VERDICT_FILE" 2>/dev/null || echo 0)
1892
- log_debug "[EXEC] iter=$ITERATION phase=verdict engine=$VERIFIER_ENGINE verdict=$verdict recommended=$recommended us_id=${signal_us_id:-all} issues=$_issues_count"
2163
+ log_debug "[GOV] iter=$ITERATION phase=verdict engine=$VERIFIER_ENGINE verdict=$verdict recommended=$recommended us_id=${signal_us_id:-all} issues=$_issues_count"
1893
2164
 
1894
2165
  case "$verdict" in
1895
2166
  pass)
@@ -1905,7 +2176,7 @@ main() {
1905
2176
  VERIFIED_US="$signal_us_id"
1906
2177
  fi
1907
2178
  log " US $signal_us_id verified. Verified so far: $VERIFIED_US"
1908
- log_debug "[EXEC] iter=$ITERATION verified_us_update=$signal_us_id verified_us_total=$VERIFIED_US"
2179
+ log_debug "[FLOW] iter=$ITERATION verified_us_update=$signal_us_id verified_us_total=$VERIFIED_US"
1909
2180
  update_status "verifier" "pass_us"
1910
2181
  # Worker will do next US on next iteration
1911
2182
  elif [[ "$recommended" == "complete" || "$signal_us_id" == "ALL" ]]; then
@@ -1940,13 +2211,13 @@ main() {
1940
2211
  jq -r '.next_iteration_contract // "Fix the issues listed above."' "$VERDICT_FILE" 2>/dev/null
1941
2212
  } | atomic_write "$fix_contract"
1942
2213
  log " Fix contract: $fix_contract"
1943
- log_debug "[EXEC] iter=$ITERATION phase=fix_loop trigger=$verdict consecutive_failures=$CONSECUTIVE_FAILURES fix_contract=$fix_contract"
2214
+ log_debug "[DECIDE] iter=$ITERATION phase=fix_loop trigger=$verdict consecutive_failures=$CONSECUTIVE_FAILURES fix_contract=$fix_contract"
1944
2215
 
1945
2216
  # Circuit breaker: consecutive failures
1946
- if (( CONSECUTIVE_FAILURES >= 3 )); then
1947
- log_debug "[EXEC] iter=$ITERATION circuit_breaker=consecutive_failures detail=\"3 consecutive verification failures\""
1948
- log_error "Circuit breaker: 3 consecutive verification failures"
1949
- write_blocked_sentinel "3 consecutive verification failures"
2217
+ if (( CONSECUTIVE_FAILURES >= EFFECTIVE_CB_THRESHOLD )); then
2218
+ log_debug "[GOV] iter=$ITERATION circuit_breaker=consecutive_failures detail=\"${EFFECTIVE_CB_THRESHOLD} consecutive verification failures\""
2219
+ log_error "Circuit breaker: ${EFFECTIVE_CB_THRESHOLD} consecutive verification failures"
2220
+ write_blocked_sentinel "${EFFECTIVE_CB_THRESHOLD} consecutive verification failures"
1950
2221
  update_status "blocked" "consecutive_failures"
1951
2222
  return 1
1952
2223
  fi
@@ -1985,12 +2256,18 @@ main() {
1985
2256
  ;;
1986
2257
  esac
1987
2258
 
2259
+ # --- step 7d: Archive iteration artifacts before cleanup ---
2260
+ archive_iter_artifacts "$ITERATION"
2261
+
2262
+ # --- AC5: Write per-iteration cost estimate ---
2263
+ write_cost_log "$ITERATION"
2264
+
1988
2265
  # --- governance.md s7 step 8: Write result log ---
1989
2266
  write_result_log "$ITERATION" "$signal_status"
1990
2267
 
1991
2268
  # --- governance.md s7 step 8: Circuit breaker - stale context check ---
1992
2269
  if ! check_stale_context; then
1993
- log_debug "[EXEC] iter=$ITERATION circuit_breaker=stale_context detail=\"context unchanged for 3 consecutive iterations\""
2270
+ log_debug "[GOV] iter=$ITERATION circuit_breaker=stale_context detail=\"context unchanged for 3 consecutive iterations\""
1994
2271
  write_blocked_sentinel "Context unchanged for 3 consecutive iterations (stale)"
1995
2272
  update_status "blocked" "stale_context"
1996
2273
  return 1
@@ -2002,6 +2279,7 @@ main() {
2002
2279
 
2003
2280
  # Max iterations reached
2004
2281
  log "Max iterations ($MAX_ITER) reached."
2282
+ generate_campaign_report # AC4: TIMEOUT terminal path
2005
2283
  update_status "timeout" "max_iter"
2006
2284
  return 1
2007
2285
  }