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
|
|
@ -325,7 +325,14 @@ printf '%s\n' "$REPOS" | while IFS= read -r d; do
|
|||
line="$(grep -m1 '^<!-- board:' "$state" 2>/dev/null)"
|
||||
status=""; blockedon=""; cost=""
|
||||
if [ -n "$line" ]; then
|
||||
status="$(printf '%s' "$line" | sed -n 's/.*status=\([a-z-]*\).*/\1/p')"
|
||||
# Captures to the next ';' or the closing '-->', NOT to the first
|
||||
# non-[a-z-] byte: a prefix class stops early on a value that is one byte
|
||||
# past a valid token ("done2" -> "done") and silently accepts it as that
|
||||
# token, or on a case variant ("Planned") and captures empty - the exact
|
||||
# bugs F3 closes. The case statement below still does an EXACT match, so
|
||||
# anything out of vocabulary lands in MALFORMED with its real value intact.
|
||||
status="$(printf '%s' "$line" | sed -n 's/.*status=\([^;>]*\).*/\1/p' \
|
||||
| sed -e 's/--$//' -e 's/[[:space:]]*$//' -e 's/^[[:space:]]*//')"
|
||||
blockedon="$(printf '%s' "$line" | sed -n 's/.*blocked-on=\([A-Za-z0-9._-]*\).*/\1/p')"
|
||||
# Value runs to the next ';' or the closing '-->', NOT to the first
|
||||
# non-lowercase byte: the rubric names models "Sonnet 5 / xhigh", so a
|
||||
|
|
@ -529,10 +536,20 @@ rows() {
|
|||
route_cmd_for() {
|
||||
rc_line="$(grep -m1 '^<!-- route:' "$1/STATE.md" 2>/dev/null)"
|
||||
[ -n "$rc_line" ] || return 1
|
||||
rc_p="$(printf '%s' "$rc_line" | sed -n 's/.*path=\([a-z-]*\).*/\1/p')"
|
||||
rc_v="$(printf '%s' "$rc_line" | sed -n 's/.*verification=\([a-z-]*\).*/\1/p')"
|
||||
rc_r="$(printf '%s' "$rc_line" | sed -n 's/.*reversibility=\([a-z-]*\).*/\1/p')"
|
||||
rc_s="$(printf '%s' "$rc_line" | sed -n 's/.*scope=\([a-z-]*\).*/\1/p')"
|
||||
# Captures to the next ';' or '-->', NOT to the first non-[a-z-] byte: a
|
||||
# prefix class silently truncates "known2" to "known", which route.sh's own
|
||||
# exact-match validation then ACCEPTS - a safely-worded but WRONG command
|
||||
# instead of the refusal this defect (F4) exists to force. route.sh still
|
||||
# does the real rejection; this only stops the value from being mangled
|
||||
# into something valid before it gets there.
|
||||
rc_p="$(printf '%s' "$rc_line" | sed -n 's/.*path=\([^;>]*\).*/\1/p' \
|
||||
| sed -e 's/--$//' -e 's/[[:space:]]*$//' -e 's/^[[:space:]]*//')"
|
||||
rc_v="$(printf '%s' "$rc_line" | sed -n 's/.*verification=\([^;>]*\).*/\1/p' \
|
||||
| sed -e 's/--$//' -e 's/[[:space:]]*$//' -e 's/^[[:space:]]*//')"
|
||||
rc_r="$(printf '%s' "$rc_line" | sed -n 's/.*reversibility=\([^;>]*\).*/\1/p' \
|
||||
| sed -e 's/--$//' -e 's/[[:space:]]*$//' -e 's/^[[:space:]]*//')"
|
||||
rc_s="$(printf '%s' "$rc_line" | sed -n 's/.*scope=\([^;>]*\).*/\1/p' \
|
||||
| sed -e 's/--$//' -e 's/[[:space:]]*$//' -e 's/^[[:space:]]*//')"
|
||||
bash "$ROUTE" --path "$rc_p" --verification "$rc_v" \
|
||||
--reversibility "$rc_r" --scope "$rc_s" --rationale brief 2>/dev/null \
|
||||
| sed -n 's/^command=//p'
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue