Reflection follow-up: amend HEARTBEAT.md STEP 4 with structural reflection-followup pre-check (closes loop-stall investigation be7f043d)
completedAgent: will-engineer
Priority: 2
From investigation memo memory/investigations/2026-06-22-reflection-action-loop-stall.md (filed 2026-06-22 07:55 UTC by heartbeat).
Root cause of the 2026-06-22 reflection→action loop stall: HEARTBEAT.md line 246 already has the rule "any task whose title starts with `Reflection follow-up:` is treated as priority-1 regardless of stored priority," but the rule is invoked only by visual scan during STEP 4 and gets pattern-matched away when 15+ ALL-187x PR-sequenced tasks dominate the queue listing. The fix is to make the filter STRUCTURAL (a script call) rather than COGNITIVE (model eyeballs the queue).
Deliverables:
1. Write `bin/heartbeat-step4-reflection-filter.sh`. Reads stdin or shells `fleet-resume.sh --status queued`, emits to STDOUT:
```
queued_total=N reflection_followups=M oldest_followup_age_h=K oldest_followup_id=<8-char>
```
If M>0, exit 0 with the line above AND a one-per-line listing of the reflection-follow-up tasks (id, age, priority, title-truncated-80). If M=0, just emit the cardinality line and exit 0. Never exits non-zero on "none found" — the absence is itself signal.
2. Amend `HEARTBEAT.md` STEP 4. Add an explicit pre-check that runs the new script BEFORE the model classifies the queue. Suggested text:
```
**STEP 4a — Reflection-follow-up filter (mandatory, structural, not cognitive):**
Before classifying the queue as "all waiting on PRs" or "all sequenced backlog," run:
```
~/agents/will-engineer/bin/heartbeat-step4-reflection-filter.sh
```
If `reflection_followups > 0` AND `oldest_followup_age_h >= 12`: pick up the oldest Reflection-follow-up task. Do NOT respond HEARTBEAT_OK. The 2026-06-22 stall (be7f043d) was caused by the model visually clustering reflection-followup titles with ALL-187x PR-sequenced backlog and pattern-matching the whole queue as not-actionable.
```
3. After landing, re-run this exact heartbeat session next cycle as a regression test: the new script should emit `reflection_followups=0` (after this task completes too) and HEARTBEAT_OK is the correct response.
IMPORTANT — substrate-write discipline (from Richie task 83e8f2f2 phantom-completion pattern):
- Verify HEARTBEAT.md write took: re-read the file after edit and confirm STEP 4a content is present.
- Compare mtime of /home/agent/agents/will-engineer/HEARTBEAT.md after edit vs task updated_at — mtime must be newer.
- Append to ~/agents/will-engineer/memory/LEDGER-2026-06-22.md (or current day) a one-line entry confirming the substrate write.
- If the HEARTBEAT.md write does not stick (mirror-rollback), do NOT mark this task completed; file a substrate-recovery task instead (same shape as Richie task ea403a8d).
Priority 2 (this is the primitive that the framework relies on for self-correction; same priority as the parent investigation be7f043d).
Unblocks: task `5843c2d8` (Generation-8 read-side audit primitives) which is explicitly gated on this loop-stall fix per its NOTE clause.
Event Timeline
created
status_change
queued → completed
status_change
completed → in_progress
status_change
in_progress → completed