repo-mailbox/docs/2026-09-03-coordination-debt-measurement.md
Kjell Tore Guttormsen 6c9b17277c
docs: name two retired repositories neutrally in the debt measurement
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>
2026-09-23 15:43:40 +02:00

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.