fix(board): exact-match status and route-trait tokens, not a prefix
board.sh's status classifier and route_cmd_for()'s four-trait extraction both used a [a-z-]* sed capture that stops at the first byte outside that class instead of running to the field's real boundary. status=done2 silently classified as done (excluded from --plan like a real done repo, shown green); status=Planned captured as empty and read as "?" (no board line at all), feeding the MERK footer a false count. route_cmd_for() had the same defect on all four traits: path=known2 truncated to known, which route.sh's own exact-match validation then accepted, producing a safely-worded but WRONG startup command instead of a refusal. Fixed by capturing to the next ';' or the closing '-->' (the same [^;>]* + trim shape next-cost already used), so the exact-match case statements downstream see the real, un-truncated value. Selftest: repo-status-prefix, repo-status-case, repo-trait-prefix and repo-revers-prefix pin all four cases, with known-positive controls that a genuinely absent board line still reads ? and a genuinely valid route line still derives a real command. All four suites green: coord 220, board 229, route 69, guard 40. Verified no MALFORMED regression against the real ~/repos tree (empty set before and after). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DxLmbNN6qswBuu6XkSYVrt
This commit is contained in:
parent
165385be5f
commit
dde392d79d
3 changed files with 161 additions and 6 deletions
33
CLAUDE.md
33
CLAUDE.md
|
|
@ -217,7 +217,10 @@ marketplace plugin. Three components, one boundary:
|
|||
selected with `board.sh`'s own anchor (`^<!-- board:`) and the status token
|
||||
compared exactly, so prose saying `status=done` never triggers it (a STATE.md
|
||||
documenting this guard writes that string routinely) and `done2` is not `done`
|
||||
here even though board.sh's F3+F4 prefix defect still reads it as one.
|
||||
here - and, since F3 (see `board.sh` below), not on `board.sh` either
|
||||
anymore: both now do the same exact match on the same extracted value, so
|
||||
`done2` reads as MALFORMED in both places, never as `done` in one and
|
||||
something else in the other.
|
||||
Selftest section 10, 17 checks, including the mandatory known-positive: a
|
||||
`status=done` with everything pushed must still go through, or the guard is a
|
||||
gate that denies everything and proves nothing.
|
||||
|
|
@ -471,6 +474,34 @@ marketplace plugin. Three components, one boundary:
|
|||
environment. A tree where nobody owes anything is a different case — that is a
|
||||
valid, non-empty briefing saying so, and is written normally.
|
||||
|
||||
**F3+F4 (2026-08-16): the status classifier and `route_cmd_for()`'s four-trait
|
||||
extraction both matched a PREFIX of the closed vocabulary, not the exact
|
||||
token.** Both used a `[a-z-]*` sed capture, which stops at the first byte
|
||||
outside that class instead of running to the field's real boundary. Two
|
||||
distinct failure shapes came out of the same defect: `status=done2` (a valid
|
||||
token plus one byte) captured as `done` and was silently classified as a real
|
||||
`done` - excluded from `--plan` the same way a genuine done repo is, and shown
|
||||
green in the table, never flagged; `status=Planned` (a case variant) captured
|
||||
as empty and was silently classified as `?` - "no board line at all" - which
|
||||
fed the MERK footer a false count for a repo that has one. `route_cmd_for()`
|
||||
carried the identical class on all four route traits, and there the failure is
|
||||
worse: `path=known2` truncated to `known`, which `route.sh`'s own exact-match
|
||||
validation then ACCEPTS, producing a safely-worded but WRONG startup command
|
||||
(row 1) instead of the refusal a typo like `knwon` (a whole different word,
|
||||
already handled correctly) already got. Fixed by capturing to the next `;` or
|
||||
the closing `-->` instead - the same `[^;>]*` + trim shape `next-cost` already
|
||||
used for its own reason (spec-conformant values contain spaces and capitals) -
|
||||
so the classifier and `route.sh`'s case statement see the value un-truncated
|
||||
and the exact-match either accepts it or correctly calls it MALFORMED /
|
||||
`command_missing=`. `blocked-on`'s `[A-Za-z0-9._-]*` capture is a different,
|
||||
wider class feeding a different mechanism (matched against scanned repo
|
||||
names for chain-root credit, not a closed vocabulary) and was checked, not
|
||||
touched - grepping `scripts/board.sh` for `[a-z-]*` after the fix returns
|
||||
nothing. Selftest fixtures `repo-status-prefix`, `repo-status-case`,
|
||||
`repo-trait-prefix` and `repo-revers-prefix` pin all four cases, plus the
|
||||
known-positive controls that a genuinely absent board line still reads `?`
|
||||
and a genuinely valid route line still derives a real command.
|
||||
|
||||
- **Route (`scripts/route.sh`):** pure calculator for the next session's model
|
||||
and effort. Takes four scored traits of the next task plus a required
|
||||
rationale, and prints one block of `key=value` lines: the rubric row, the rule
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue