claim truncates a prose Status line, and the guard against it runs first
- Found: 2026-08-31 by frankA (Track A), claiming
feature-signal-siginfo-ucontext. Track T's file — not edited. - Not hypothetical. That ticket has no frontmatter
summary, so its body Status line was the only routing information a reader had.
Measured
$ tools/progress.sh claim feature-signal-siginfo-ucontext frankA
$ diff <(git show HEAD^:.../unfinished/<slug>.md) <(git show HEAD:.../working/<slug>.md)
-owner: claude-acp
+owner: frankA
-- **Status:** unfinished — items 1 (SA_SIGINFO/ucontext) and 3 (sigaltstack) DONE; item 4's compiler half done (__pxxSigNum), its RTL half is Track B. Items 2 (--threadsafe) and 5 (SIGPIPE) remain, plus parking the signal number on the other four targets.
+- **Status:** working
Restored by hand. Nothing warned; claim printed success.
The mechanism, and why it is worth more than a one-line fix
progress.py has two functions that write that bullet:
| pattern | guarded? | |
|---|---|---|
sync_status_to_folder :2676 |
^(\s*-\s*\*\*Status:\*\*\s*)(\w+)\s*$ |
yes — one bare word only |
set_field :2750 |
^(\s*-?\s*\*\*Status:\*\*\s*).*$ |
no — .*$ eats the line |
move_ticket calls the guarded one (:2731). claim then calls the unguarded
one (:3019) on the next line. So the guard is not missing, not stale, and
not wrong — it runs, it correctly declines, and it is immediately overwritten.
Its own comment states the intended policy exactly:
Only the bare
- **Status:** wordform. A bullet that continues into a sentence ("unfinished -- agent half done, parked awaiting X") is prose carrying a reason, and silently truncating someone's explanation to one word is a worse outcome than a stale word.
That policy is correct and is currently unenforceable, because a second
mechanism serving the same concept does not know about it.
devdocs/dev/normalise-dont-special-case.md calls the shape: two paths for one
concept, and the second is the one that stays broken.
Suggested shape, T's call
set_field is right for Owner — one value, whole-line replacement is what you
want — and wrong for Status, which carries prose. Either give set_field the
same one-word condition when marker == "Status", or drop the three
set_field(..., "Status", ...) calls entirely and let move_ticket's
sync_status_to_folder be the only writer (it already runs on every path that
moves a ticket, which is every path that changes status).
The second is smaller and deletes a case rather than adding one.
Whichever way: the guard needs a positive control — a test asserting a prose
Status line SURVIVES a claim. The current guard has never been able to protect
anything through claim, and nothing said so.
resolve (:3210) and the unfinished path (:3114) call set_field the same
way and have the same exposure — and resolve was then observed doing it, in
the same session, on the same ticket: a restored 6-line Status bullet was
flattened to the bare word done an hour after the claim instance. So this is
not one command with an oversight; it is the shared writer, and both callers
reproduce it on demand. That also makes the positive control easy to specify:
claim a ticket with a prose Status line, resolve it, and assert the prose
survived both.
Related
- [[a-documented-trap-is-not-a-guard]]
devdocs/dev/normalise-dont-special-case.md
Deprioritised 2026-09-02 — the Track T tooling backlog was cut as a pile
This ticket is not being called wrong. It was moved as part of a pile, not judged individually, and nothing here disputes its finding.
Owner decision. 73 of the 74 open track: T tickets were filed between
2026-08-31 and 2026-09-02, 58 on one day. The pile was too large to work through
and returned almost nothing, and a ticket nobody will fix does not sit neutrally
— it stays in the ranker forever at zero value, which is the argument CLAUDE.md
already makes for a terminal folder over a low prio.
Four were kept in the ranker on a purely structural test — an active umbrella or
a hard blocked-by: edge from live work:
umbrella-one-full-tier-run-with-no-red-tier,
feature-t-freebsd-image-and-runner, and the two regression-test-core-* reds
that block the umbrella.
Kept, not deleted, for two reasons: so the finding is not rediscovered and refiled from scratch by the next agent who trips over it, and so it can be pulled back if what it touches becomes load-bearing.
To revive it: move it to the owning lane's backlog, set status: backlog,
and say in the ticket WHAT CHANGED to make it matter now. Restoring it because it
reads well is how the pile comes back.