chore(release): bump to 0.28.0

Five fixes were committed and pushed after v0.27.0 and none is reachable:
every entry point on this machine runs the version-pinned plugin cache, not
this tree. This bump is step one of making them reachable - the tag and the
catalog ref follow together via release-plugin.mjs, never one without the
other.

Carries: dot-prefixed repo discovery (3e5add0), the bare-name defect in the
three order-verb emitters (393499c), --to refused on a control character in
both write sides (29a94dd), the FILENAME== focus-filter join (2928c28), and
route_cmd_for reading the rationale instead of the field (b70786d).

Version bumped in all seven places CLAUDE.md's Release section names:
plugin.json, package.json, the README badge, and the frontmatter of
skills/coord-send, skills/board, skills/route, skills/dispatch. CHANGELOG
entry added alongside.

Pre-release gate, all five suites plus npm: coord 230, board 259 (was 252 -
section 23 added 7 checks), route 69, orders 110, guard 40, node 11/11.
Catalog pre-flight run by hand first per the order: 12 plugins, 0 ERROR.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AZa4oEsa93ac6pZQFEXqBF
This commit is contained in:
Kjell Tore Guttormsen 2026-08-20 23:07:45 +02:00
commit 2377735554
8 changed files with 71 additions and 7 deletions

View file

@ -5,6 +5,70 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.28.0] - 2026-08-20
Five fixes were committed and pushed after `v0.27.0` and none of them was
reachable: every entry point on this machine runs the version-pinned plugin
cache, not the tree. This release is what makes them reachable.
### Fixed
- **`board.sh` repo discovery skipped dot-prefixed repos.** A repo named
`.profile` (the Forgejo/GitHub org-profile convention) was invisible to the
board entirely - not listed, and `--dispatch --repo .profile` refused with
"no repo named '.profile' in the scanned roots". The fix is a dedicated
`add_dot_repos()` rather than `shopt -s dotglob`: with dotglob on, the same
`[ -e "$entry/.git" ]` test would route a dot-directory that is NOT a repo
(e.g. `.claude`) into the polyrepo-container branch, silently widening what
counts as a container. Bounded gap left open deliberately: a dot-directory
that is not itself a repo is still never treated as a container.
- **The three order-verb emitters told a session to run the verbs by a BARE
name, and neither verb is on PATH** - command-not-found on step one,
misreadable as "the order does not exist". `board.sh`'s dispatch starter,
`coord-order-inbox.sh`'s SessionStart injection and `coord-order-claim.sh`'s
own `WHEN DONE` lines now call the verb by the absolute path sibling to the
printing script itself, correct for whichever install location is live.
- **`--to` is now REFUSED on a control character rather than sanitized, on
both write sides.** A target name is also the destination DIRECTORY name, so
collapsing a newline to a space the way `sanitize_field` does everywhere else
delivers to a mailbox the sender never named. Both corruptions were measured
on the live engine before the guard existed, each with exit 0 and a
"delivered" line: a newline lands its payload inside the frontmatter block
and silences the debt the engine itself declared; a tab makes `coord-count`
print five tab-separated fields where its contract is four, which `board.sh`
consumes. `coord-order-send.sh` had the identical defect, where it costs
more - an order filed under a name no session can hold is the silent
evaporation the ownership chain exists to prevent.
- **A third `NR==FNR` join survived in `plan()`'s focus filter**, next to two
comments stating the file's own rule against it. Measured before touching it:
unlike the two prior instances, this one has no reachable defect - it is
fixed as a live counter-example to a rule the file states about itself, and
pinned structurally rather than behaviourally, because there is no behaviour
to pin.
- **`route_cmd_for()` read the RATIONALE instead of the field.** Its four trait
extractions searched the whole route line with a greedy `.*trait=`, and
`route.sh --help` asks for a rationale per score - so a rationale that names
a trait won the match over the field itself. `route.sh` correctly refused the
prose, `--plan` printed `command_missing=`, and the operator read a broken
PARSER as "that repo has no route line". A/B-ing the pre-fix script against
the fixed one over the real tree at the same moment: 25 tabs,
`command_missing` 7 -> 2. The cut is at the first `rationale=`; F4's
`[^;>]*` class is untouched, since the two answer different questions.
### Changed
- Two claims about the catalog's `release-plugin.mjs` were corrected in
`CLAUDE.md` after being read off the script rather than assumed: it no longer
pushes a tag without `--write`, and its pre-flight gate now runs BEFORE the
catalog write, so the half-applied-catalog recovery the old text prescribed
has nothing left to recover.
### Testing
`board-selftest.sh` 252 -> 259 checks (section 23, both failure directions plus
two known-positive controls). All five suites green: coord 230, board 259,
route 69, orders 110, guard 40; `npm test` 11/11.
## [0.27.0] - 2026-08-17
`v0.26.0` was bumped and pushed but **never tagged**, and two changes landed