feat(engine): retire a broadcast with coord-send --retract

Nothing could remove a message from _broadcast/inbox/. coord-done is
directed-only and never touches the broadcast queue, so the backlog could
only grow: every new repo received the entire standing history at its first
session, including announcements that had since become false.

--retract <filename> archives the message into _broadcast/archive/, so no
future repo is served it. Three deliberate limits, all pinned by tests:

- Un-send, not recall. Repos that already received it keep it;
  _broadcast/seen/ is delivery history and is left untouched.
- Only the sender may retract (from: must match the repo identity). --from
  overrides it, as everywhere else in the engine, which makes the check an
  accident guard rather than a security boundary.
- Nothing is deleted, mirroring coord-done. Retracting twice is a no-op.

The branch runs before every send-side validation and before the stdin body
read, since a retract carries no subject and no body.

Selftest 70 -> 82 (new section 19). Also fixes two README defects the
feature exposed: the install command still named coord@ after the v0.3.0
rename, and the docs advised pruning _broadcast/inbox/ by hand, which
contradicted the rule that the script owns mailbox files.
This commit is contained in:
Kjell Tore Guttormsen 2026-07-25 15:11:47 +02:00
commit 316b8acdd2
8 changed files with 184 additions and 15 deletions

View file

@ -11,8 +11,11 @@ description: >-
triggers on Norwegian phrasings: "send info til alle repo", "varsle repo X", "gi
beskjed til Y og Z", "kringkast at …", "svar på coord-meldingen", "når Z er ferdig,
varsle X". Trigger even when the user names a repo plus something to convey without
saying "coord" explicitly — routing a message to another repo IS this skill.
version: "0.3.0"
saying "coord" explicitly — routing a message to another repo IS this skill. Also
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.4.0"
---
# coord-send — natural-language front door for inter-repo messages
@ -58,6 +61,9 @@ Interface (body comes from a quoted heredoc so nothing in it is shell-expanded):
<message body>
BODY
# retire one of THIS repo's own broadcasts (no subject, no body)
"$CSEND" --retract <broadcast-filename>
Sender identity (`--from`) defaults to the basename of the current git toplevel, so
you almost never set it. Exit 0 = delivered; exit 2 = usage/IO error (read stderr and
fix the arguments rather than retrying blindly).
@ -80,11 +86,34 @@ fix the arguments rather than retrying blindly).
- **All repos**`--broadcast`. Prefer this only when the notice genuinely concerns
everyone, because broadcasts accumulate and every future first-time repo sees the
standing backlog. For a bounded, known set, loop `--to` instead so unrelated future
repos don't inherit it.
repos don't inherit it. A broadcast that later turns out wrong can be retired with
`--retract` (see below), but only for repos that have not received it yet.
- **A reply to something received**`--reply-to <filename>`. Use the filename from
the injected inbox/archive; it resolves the sender and closes the original in one
step.
## Retracting a broadcast
When a broadcast has become wrong or obsolete, retire it — don't send a correction
and leave the original standing, because every future first-time repo would receive
both. `--retract <broadcast-filename>` archives it out of the delivery queue.
Three things to be honest about when you report it:
- **It is un-send, not recall.** Repos that already received the broadcast keep it.
Retraction only stops delivery to repos that haven't seen it yet. If the old news
actively misleads someone who already got it, a correcting broadcast is still
needed — retraction alone does not reach them.
- **Only the sender may retract.** The `from:` field must match this repo's identity.
If the announcing repo has since been renamed, its old identity no longer resolves,
so pass `--from <old-sender>` explicitly (read the sender off the file). Say that
you did.
- **Nothing is deleted.** The message moves to `_broadcast/archive/`. Never remove a
mailbox file by hand — the script owns the filename grammar and delivery guarantees.
Find the filename in `~/.claude/coord/_broadcast/inbox/` (or from the injected
`--- broadcast: <filename> ---` line) rather than guessing it.
## Composing the message
Derive a short, specific `--subject` from the intent if the user didn't give one
@ -138,3 +167,9 @@ pending notice to the user.
**Example 5 — reply**
Input: "svar på coord-meldingen fra repo-x at vi tar det"
Action: `--reply-to <that-message-filename>`, body acknowledging and stating the plan.
**Example 6 — retract**
Input: "den gamle kringkastingen om plugin-navnet er utdatert, trekk den"
Action: locate the file in `_broadcast/inbox/`, then `--retract <that-filename>`
(adding `--from <old-sender>` if this repo has been renamed since). Report that
repos which already received it are unaffected.