workflow-fix: parse_followup_note_field misses literal backslash-n notes
Highlight text on any card (body, plan, or an event) to anchor a comment, or leave a whole-task comment here. Mention @claude to summon a reply.
No comments yet.
Overview / Motivation
Auto-filed by the workflow-fix-on-bug protocol from a workflow-fix candidate raised on task #825 (emitting agent: issue-orchestrator, own observation).
Goal
Harden parse_followup_note_field to treat literal backslash-n escape
sequences as line separators so field-led follow-up notes posted with escaped
newlines still parse.
Workflow gap
- Bug observed:
epm:same-issue-followup-runmarkers v6/v7 on #825 (2026-07-08T00:50-00:51Z) carried literal\ntwo-char escape sequences instead of real newlines;parse_followup_note_field(note, "followup_label")returned'onpolicy-separator-control\\nsource:'instead of the label, sounrun_followup_labelsreported the completed round as UNRUN and the next/issue 825entry nearly re-dispatched a finished 4-GPU-h round (caught by the Step 0 stale-label disposition rule +followup_retro_close_evidence; retro-closed at v8). - Why it is a workflow gap: the parser already tolerates three note
shapes (line-initial one-per-line,
;-joined single-line, dash-bullet / bold variants — the #1090/#841 hardening) but not the escaped-newline shape a poster produces when a shell--note "...\n..."string is passed without interpretation. Round caps and label closure both silently undercount on this shape (the #1090 fu1 regression class), and the same miss affects every consumer:unrun_followup_labels,executing_followup_label, the cheap-band/expensive-band round caps, and the watcher's on-behalf run-marker post. - Confidence (emitter): high
Proposed change (candidate diff sketch — refine in planning)
def parse_followup_note_field(note: str, field: str) -> str | None:
+ # Notes occasionally arrive with literal backslash-n escapes instead of
+ # real newlines (shell --note strings; #825 v6/v7). Normalize them to
+ # newlines BEFORE line splitting so field-led parsing survives.
+ if "\\n" in note and "\n" not in note.replace("\\n", ""):
+ note = note.replace("\\n", "\n")
...existing line/`; `-join parsing unchanged...
(Planner refines the normalization predicate — e.g. unconditional
note.replace("\\n", "\n") pre-pass restricted to the field-scan copy, never
mutating stored state — plus a regression test pinning the #825 v6/v7 note
shape verbatim.)
Scope / surfaces
- Primary target:
src/explore_persona_space/task_workflow.py(parse_followup_note_field; check sibling helpersfollowup_label_groups/unrun_followup_labels/executing_followup_labelconsume the hardened parse transparently) - Tests:
tests/test_task_workflow*.py— add a literal-escape fixture from the #825 v6 note. - Grep the workflow surface for the pattern before editing
(
grep -rln 'parse_followup_note_field' .claude/ CLAUDE.md scripts/ src/explore_persona_space/task_workflow*.py) and update every hit; list them in the plan.
Constraints / invariants
- Workflow-surface only — never experiment code,
configs/, ortasks/. scripts/workflow_lint.py --check-askspasses; ruff on touched files passes; ifworkflow.yamlorCLAUDE.mdchange, they stay consistent with the rule file.- This session runs under
EPM_WORKFLOW_FIX_SESSION=1and carries aworkflow_fix_target:Provenance line — it MUST NOT auto-route any of its own subagents' workflow-fix candidates (recursion guard).
Provenance
- workflow_fix_target: src/explore_persona_space/task_workflow.py
- fingerprint: 5e09182a9dd2
target_file: src/explore_persona_space/task_workflow.py
bug_observed: epm:same-issue-followup-run markers v6/v7 on #825 carried literal backslash-n escapes; the label parse returned garbage and the completed round showed as unrun, nearly triggering a duplicate re-run
why_workflow_gap: parse_followup_note_field tolerates line-initial / ; -joined / dash-bullet note shapes but not escaped-newline notes, so label closure and round caps silently undercount on that shape
proposed_change: harden parse_followup_note_field to treat literal backslash-n escape sequences as line separators so field-led follow-up notes posted with escaped newlines still parse
diff_sketch: |
- if "\n" in note: normalize literal escapes to newlines in the field-scan
- copy before line splitting (parse-side only; stored notes untouched)
- regression test pinning the #825 v6/v7 note shape confidence: high related_task: #825