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

@ -1,6 +1,6 @@
{
"name": "repo-mailbox",
"version": "0.27.0",
"version": "0.28.0",
"description": "Local mailbox for coordination between Claude Code sessions in different repositories. Directed messages and broadcasts as plain Markdown files on your own disk, injected as context at session start. Local, private, no network.",
"author": {
"name": "Kjell Tore Guttormsen"

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

View file

@ -10,7 +10,7 @@ Session A in repo X leaves a message for repo Y; the next session in repo Y gets
*AI-generated: all code produced by Claude Code through dialog-driven development.*
![Version](https://img.shields.io/badge/version-0.27.0-blue)
![Version](https://img.shields.io/badge/version-0.28.0-blue)
![Hooks](https://img.shields.io/badge/hooks-1-green)
![Skills](https://img.shields.io/badge/skills-4-orange)
![CLI scripts](https://img.shields.io/badge/CLI_scripts-8-blue)

View file

@ -1,6 +1,6 @@
{
"name": "repo-mailbox",
"version": "0.27.0",
"version": "0.28.0",
"private": true,
"type": "module",
"engines": {

View file

@ -20,7 +20,7 @@ description: >-
user names no repo and no tool — choosing *between* repos is this skill. Not for
"where were we" inside the current repo: that is this repo's own STATE.md,
already injected at session start.
version: "0.27.0"
version: "0.28.0"
---
# board — which repo deserves the next session

View file

@ -15,7 +15,7 @@ description: >-
covers retiring a broadcast that has become wrong or obsolete: "retract that
broadcast", "that announcement is outdated, pull it", "trekk tilbake kringkastingen",
"den broadcasten er utdatert".
version: "0.27.0"
version: "0.28.0"
---
# coord-send — natural-language front door for inter-repo messages

View file

@ -17,7 +17,7 @@ description: >-
skill. Not for choosing WHICH repo deserves the next session (that is `board`),
not for scoring model and effort alone (that is `route`), and not for sending a
message to another repo (that is `coord-send`).
version: "0.27.0"
version: "0.28.0"
---
# dispatch — hand a session a task it can actually start on

View file

@ -14,7 +14,7 @@ description: >-
the operator names no model and no tool — choosing the model for the next
session IS this skill. Not for choosing which REPO gets the next session:
that is the `board` skill.
version: "0.27.0"
version: "0.28.0"
---
# route — what the next session should run with