The 2026-09-03 coordination-debt measurement named two repositories that no longer exist, in its table and in the cutoff reconstruction. They now read "retired repository A" and "retired repository B"; every count, timestamp and the 7 + 4 = 11 reconstruction are unchanged. CHANGELOG 0.36.1 widened to match, so its text stays true. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
152 lines
7.3 KiB
Markdown
152 lines
7.3 KiB
Markdown
# Coordination debt: what does not converge, and why building a second
|
|
# mechanism would have been wrong
|
|
|
|
Measured 2026-09-03 against the live mailbox, for order
|
|
`20260902T113745Z-1254925290-from-.claude` (WP5). Every number below was
|
|
produced by a command, and every negative result carries the control that
|
|
proves the query could have found something.
|
|
|
|
The order offered two candidate mechanisms and said to choose by measurement,
|
|
not taste: a broadcast TTL, or a bulk-ack for pure notices. The measurement
|
|
chose neither. One of them is already built and has never been run; the other
|
|
addresses the class that converges on its own.
|
|
|
|
## Denominators
|
|
|
|
| population | count |
|
|
|---|---|
|
|
| mailbox directories under the coord root | 55 |
|
|
| of those, holding an `inbox/` | 52 |
|
|
| pending directed messages across all inboxes | 27 |
|
|
| broadcasts in `_broadcast/inbox/` | 17 |
|
|
| (mailbox x broadcast) delivery pairs | 884 |
|
|
|
|
The three directories with no `inbox/` are named rather than silently dropped:
|
|
`jobbsok`, `mediemon`, `medieovervaaking`. 55 - 3 = 52 is the reconciliation,
|
|
stated because an unreconciled pair of denominators in one report is the same
|
|
positive-looking null this engine refuses everywhere else.
|
|
|
|
## The two classes behave in opposite directions
|
|
|
|
**Directed messages do not converge.** They are re-injected at every session
|
|
start until a session closes them by hand. Of the 27 pending, 4 owe a reply and
|
|
23 are pure notices (`reply-expected: no`). By age:
|
|
|
|
| class | <7d | 7-13d | 14-29d | >=30d |
|
|
|---|---|---|---|---|
|
|
| owes a reply | 0 | 3 | 1 | 0 |
|
|
| pure notice | 10 | 6 | 7 | 0 |
|
|
|
|
**Broadcasts converge on their own.** Reading one records it as seen, so a
|
|
mailbox clears its whole backlog on its next session. 263 of the 884 pairs are
|
|
unread (29.8%), and the distribution shows the self-clearing: 10 mailboxes are
|
|
fully current, 26 sit at exactly 6 unread (the newest announcements), and the
|
|
tail is short.
|
|
|
|
## The floor under the broadcast number, which strengthens the case
|
|
|
|
Two mailboxes hold all 17 broadcasts unread, and neither can ever read them:
|
|
|
|
- `ktg-plugin-marketplace` is a **retired `--to` address**. It is a polyrepo
|
|
directory, not a git repo, so `basename(git toplevel)` can never resolve to
|
|
it and no session can hold that identity. This is already documented as
|
|
engine behaviour; the 17 unread are its permanent consequence.
|
|
- `llm-ingestion-guard` has no checkout anywhere under `/Users/ktg`
|
|
(`find -maxdepth 4`, with `llm-ingestion-okf` as the known-positive control
|
|
proving the query finds a real one) and no `.origin`. It also holds the
|
|
single oldest pending notice, 24 days.
|
|
|
|
So **34 of 263 unread pairs (12.9%) are a permanent floor no TTL would reduce
|
|
to zero** - it would close them, but it would be closing announcements for
|
|
mailboxes that were never going to read anything. `.origin` absence alone is
|
|
NOT a proxy for unholdable: `repos` also lacks one, yet sits at 2 unread of 17,
|
|
which is only possible if something reads it.
|
|
|
|
## Why no second mechanism was built
|
|
|
|
`coord-sweep.sh` already **is** the bulk-ack for pure notices: machine-wide,
|
|
one mechanically decidable class (`reply-expected: no`, older than a grace
|
|
window), dry-run by default, closing through `coord-done.sh`, logging sender
|
|
and subject for every closure. Building the order's second candidate would have
|
|
been a second copy of a shipped policy - the defect class this repo names
|
|
repeatedly.
|
|
|
|
Its own dry-run reports what it would close today, and the figures agree
|
|
exactly with the independent classification above:
|
|
|
|
--days 30 -> 0 messages
|
|
--days 14 -> 7 messages
|
|
--days 7 -> 13 messages
|
|
|
|
**The gap is invocation, not mechanism.** No `_sweep.log` exists at the default
|
|
path, and no sweep log exists anywhere under `~/.claude` (the one `*sweep*` hit
|
|
is an unrelated plugin file) - stated that way because `--log` can override the
|
|
default, so an absent default-path log alone would not prove it never ran.
|
|
|
|
## What remains, and why it is not this repo's call
|
|
|
|
Making the notice class converge without opening each repo means running
|
|
`coord-sweep.sh --write` unattended. That closes mail in 51 other repos'
|
|
inboxes, unread, and the script's own design says so in as many words: a notice
|
|
to a repo left unopened for the whole window is closed unread, and the log is
|
|
the only thing standing between that and a silent disappearance.
|
|
|
|
Deciding that on another repo's behalf is the one anti-pattern with no
|
|
exception clause, and the grace window is a policy constant of the same class
|
|
as the STATE.md line limit, which was an operator decision both times it moved.
|
|
Dry-run is the default precisely because this is the script that destroys
|
|
pending state; flipping that to a schedule is the operator's act, not a
|
|
plugin's.
|
|
|
|
The messages that owe a reply are untouched by any of this, at any age, with
|
|
any flag. That is not a gap to close later - it is the rule that keeps a
|
|
procedural duty from becoming a substantive one.
|
|
|
|
---
|
|
|
|
## Appendix: the before-state, captured 2026-09-04 08:0x UTC
|
|
|
|
The operator authorized the sweep on 2026-09-03 (14-day window, scheduled via
|
|
launchd). This is `coord-count.sh` immediately before the authorized
|
|
`--write --days 14` run, recorded here because a before-state stops existing
|
|
the moment the write happens, and the order asks for debt before/after with a
|
|
denominator.
|
|
|
|
mailbox pending owed origin-age
|
|
app-creator 1 1 -
|
|
claude-playlist-corpus 1 0 -
|
|
graceful-handoff 3 0 -
|
|
human-friendly-style 1 0 -
|
|
(retired repository A) 1 0 -
|
|
llm-ingestion-guard 1 0 25
|
|
llm-security 2 0 -
|
|
(retired repository B) 2 0 -
|
|
okr 1 0 -
|
|
org-ops 5 2 -
|
|
portfolio-optimiser-commons 3 0 -
|
|
repo-standard 1 1 -
|
|
wiki-advise 2 0 -
|
|
.claude 1 0 -
|
|
.profile 1 0 -
|
|
------------------------------------------------------
|
|
15 mailboxes with pending mail 26 4
|
|
|
|
`$CLAUDE_COORD_DIR/_sweep.log` did not exist: the sweep had still never run.
|
|
|
|
**The control this file exists to make runnable:** after the write, the `owed`
|
|
column must be BYTE-IDENTICAL (total 4), because the sweep spares every message
|
|
that owes a reply at any age. A changed `owed` figure means the sweep closed
|
|
something it must never touch, and is a defect, not a result.
|
|
|
|
**The dry-run said 11, not the 7 this document measured a day earlier, and the
|
|
gap is entirely the moving cutoff.** Verified two ways rather than assumed.
|
|
Yesterday's 14-day cutoff was ~20260820T184902; today's is 20260821T055442.
|
|
Four notices timestamped 2026-08-20 between those two instants
|
|
(`human-friendly-style` T210113Z, retired repository A T205611Z, `org-ops`
|
|
T210955Z and T211358Z) crossed the boundary in one calendar day: 7 + 4 = 11.
|
|
Independently, `--days 15` today yields 6, and those 6 plus
|
|
retired repository B's `20260820T104644Z` - which sits between the 15-day cutoff and
|
|
yesterday's 14-day one - reconstruct yesterday's 7 exactly. The engine is
|
|
consistent; the 7 was a measurement of a moment, never a constant, and reading
|
|
it as one would have been face 3 of the verification law pointed at our own
|
|
report.
|