feat(board): rank --plan on one score, with transitive chain-root credit
blocked-on was scanned and then used for a single display string; it never
reached the ordering. A blocked chain's root could therefore rank below the
repos waiting on it - measured on the real tree, the root opened at tab 14
while the two repos it held up opened at tabs 5 and 8.
--plan now ranks on one score instead of four hard buckets, because four
groups cannot express "this repo owes one message and releases two others":
40 x repos released transitively + 15 x inbox
+10 in-progress / +5 planned / +2 undeclared, +3 for a Sonnet row
Chain-root credit follows blocked-on transitively to the first repo that is
not itself blocked and credits only that root. Opening a blocked repo
releases nobody - its own next step is by definition waiting. A cycle, a
blocked-on naming an unscanned repo, and a blocked repo with no target all
credit NOBODY: inventing a root there yields a plan that looks correct and
sends the operator to the wrong repo.
Debt is deliberately uncapped. A cap was proposed alongside the credit and
declined: owing a reply is the other axis from a repo's own next step, and
answering is often what unblocks a chain. The weight carries that decision -
15 per message exceeds the sum of every other bonus (13), so one message
more still outranks any combination of status and cost. At the originally
proposed 12 a tiebreak could flip the debt order, which is the cap arriving
through the back door.
blocked-on becomes a record field, inserted BEFORE neste so no existing field
index moves: neste is free prose lifted from a STATE.md and may carry a
literal '|' from a markdown table, so it stays last.
why= now names the dominant term rather than the first rule that matched, so
a block says what opening it would release instead of repeating inbox:N.
Format is otherwise unchanged for both declared consumers: tab=, repo=, dir=,
why=, status=, neste=, command=/command_missing=, paste= and the fokus_*
header all keep their names and positions.
board-selftest 118 -> 134 (chain, cycle, dangling-edge and format fixtures
written first, all failing before the change).
This commit is contained in:
parent
917a902172
commit
e5e9cbe847
10 changed files with 404 additions and 51 deletions
43
CLAUDE.md
43
CLAUDE.md
|
|
@ -54,7 +54,7 @@ marketplace plugin. Three components, one boundary:
|
|||
- **Board (`scripts/board.sh`):** cross-repo attention board. Reads STATE.md
|
||||
next-step blocks + board lines, `git status`, and mailbox pending counts, and
|
||||
prints one line per repo. Read-only by construction: it writes to no repo, no
|
||||
STATE.md and no mailbox. Pinned by `board-selftest.sh` (89 checks).
|
||||
STATE.md and no mailbox. Pinned by `board-selftest.sh` (134 checks).
|
||||
|
||||
**It lives here because the mailbox is one of its three inputs, and it carries
|
||||
the same axis distinction the mailbox does.** A pending count means *others
|
||||
|
|
@ -85,15 +85,36 @@ marketplace plugin. Three components, one boundary:
|
|||
**`board.sh --plan` is the THIRD rendering, and the only one that takes a
|
||||
position.** It answers which repos to open a tab for today, in what order,
|
||||
with which command. The position it takes is the ORDER and nothing else -
|
||||
there is no cutoff, so the plan hides nothing, and every rule is a lookup over
|
||||
fields the scan already read. Debt ranks first regardless of status, and that
|
||||
is the rule most likely to be "fixed" into a defect: excluding `blocked` or
|
||||
`done` is a claim about a repo's OWN next step, which by definition cannot be
|
||||
moved, while owing a reply is the other axis entirely - answering is often
|
||||
what unblocks it. Measured on the real tree at 0.16.0, two of 26 planned repos
|
||||
were `done` with an unhandled inbox. Repos with no board line rank last and
|
||||
are LABELLED rather than dropped, because the table already prints a MERK line
|
||||
about them and a plan that omitted them silently would repeat that defect.
|
||||
there is no cutoff, so the plan hides nothing, and every term is a lookup over
|
||||
fields the scan already read. Since 0.19.0 it is ONE score rather than four
|
||||
buckets, because four groups cannot express "this repo owes one message and
|
||||
releases two others" - which is how a chain's root ended up ranked below the
|
||||
repos waiting on it.
|
||||
|
||||
**Debt is never excluded and never capped, and that is the rule most likely to
|
||||
be "fixed" into a defect.** Excluding `blocked` or `done` is a claim about a
|
||||
repo's OWN next step, which by definition cannot be moved, while owing a reply
|
||||
is the other axis entirely - answering is often what unblocks it. Measured on
|
||||
the real tree at 0.16.0, two of 26 planned repos were `done` with an unhandled
|
||||
inbox. A cap on debt was proposed with the chain credit at 0.19.0 and DECLINED
|
||||
by the operator for the same reason. The weight carries that decision: 15 per
|
||||
message is above the sum of every other bonus (13), so one message more still
|
||||
outranks any combination of status and cost. Lowering it to 12 - the value
|
||||
originally proposed - lets a tiebreak flip the debt order, which is the cap
|
||||
arriving through the back door.
|
||||
|
||||
**Chain-root credit lands on the ROOT and nowhere else.** For every `blocked`
|
||||
repo the `blocked-on` edge is followed transitively to the first repo that is
|
||||
not itself blocked. Crediting a blocked repo would open a tab that cannot move;
|
||||
crediting only the direct blocker leaves a two-hop chain's root uncredited,
|
||||
which is the shape the real tree actually had. A cycle, a `blocked-on` naming
|
||||
an unscanned repo, and a blocked repo with no target must all credit NOBODY:
|
||||
inventing a root there produces a plan that looks correct and sends the
|
||||
operator to the wrong repo.
|
||||
|
||||
Repos with no board line rank last and are LABELLED rather than dropped,
|
||||
because the table already prints a MERK line about them and a plan that
|
||||
omitted them silently would repeat that defect.
|
||||
|
||||
It renders `key=value` blocks, not prose, because it has two consumers: the
|
||||
operator, and a driver repo consuming the plan. Prose would make the rendered
|
||||
|
|
@ -251,7 +272,7 @@ obligations in another repo.
|
|||
builtins only in hook and tests.
|
||||
- TDD: no behavior change without a failing selftest check first.
|
||||
`bash scripts/coord-selftest.sh` must exit 0 (183/183),
|
||||
`bash scripts/board-selftest.sh` must exit 0 (89/89) and
|
||||
`bash scripts/board-selftest.sh` must exit 0 (134/134) and
|
||||
`bash scripts/route-selftest.sh` must exit 0 (73/73).
|
||||
- English for all code, docs, and commit messages (public repo). Norwegian
|
||||
trigger aliases in the skill description are deliberate.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue