repo-mailbox/docs/2026-08-23-free-capacity-investigation.md
Kjell Tore Guttormsen 3beef2a603 feat(board): FLY column and free-capacity lines, no process inspection
ORDRE counted pending orders only, so a repo with one order in flight and a
repo with no orders at all both printed 0 - the same digit for two opposite
facts. Measured 2026-08-23: two panes stood open and idle for 45 hours holding
finished orders, with full quota authorised, and no column on the board
reported it.

FLY counts orders/claimed/ - the same queue in its other state, never summed
with ORDRE and never a fourth axis. It does NOT mean a session is alive:
nothing un-claims an order when the claiming session dies, and one order on
the live mailbox had been claimed for 117 hours. The legend denies the
liveness reading in those words, pinned as a check on the legend text.

--plan now names free capacity as ledig_antall=N plus one ledig=<repo>
(<status>) line per repo with nothing owed, no pending order, nothing in
flight, a clean tree, at done or deferred. All four conditions are required:
measured on the real tree, 4 of 17 done/deferred repos were not free. Lines,
never blocks - the plan's second consumer discards a block with no tab=, so a
block would be visible to the operator and invisible to the driver.

Process inspection was considered and refused; the selftest asserts the
absence of pgrep/pkill/lsof structurally with a known-positive control. The
full argument, and the gap left open, are in
docs/2026-08-23-free-capacity-investigation.md.

board-selftest: 259 -> 281 checks, all green. npm test 11/11.

Order 20260823T162951Z-941745020-from-.claude

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Hfbfr8ERC63kuAfWeHYHQb
2026-08-23 19:07:00 +02:00

7.2 KiB

Which repos are free? The investigation, and where it stopped

Ordered 2026-08-23. The operator's words, translated: "we need more precision about you knowing which repos are finished and can take more work." What was ordered was an investigation and a design, not a named column — the sending repo supplied the problem and the measurements and left the shape of the answer here.

Repos are unnamed throughout. This is a public mirror, and which repo was idle for how long is not a fact this file needs to carry to make its argument.

The incident

A session read the board's ORDRE column, ran pgrep -fl claude, and told the operator that four sessions were working. The operator looked at their screen: one was. Measured afterwards, two of the four processes had accumulated ~38 minutes of CPU across 45 hours of wall clock. They were open panes sitting at a prompt, holding finished orders, during a window in which full quota had been authorised against a deadline four days out.

Nothing on the board reported it, and that is the part this file is about.

Three blind spots, one of which was ours

  1. ORDRE counted pending orders only. So a repo with one order in flight and a repo with no orders at all both printed 0. The same digit for two opposite facts — "work is happening here" and "nothing is waiting here" — with no way to tell them apart. This one is a defect in this repo's own rendering, and it is fixed.
  2. STATUS describes the plan, not the capacity. done does mean "no open step", which is close to what the operator wanted; planned and in-progress say nothing about whether anyone is actually sitting there. One of the idle repos was planned for the full 45 hours, entirely correctly.
  3. A process proves existence, not activity. pgrep finds a session that finished everything and went quiet. This one is not ours to fix — see below.

What was changed

FLY: the order queue's other state

A second count over orders/claimed/, printed in its own column beside ORDRE and never summed with it. Same queue, other state — not a fourth axis, which is why it is a second reading of a source the board already had rather than a new source.

Verified live on the day it shipped: one repo went from ORDRE 0 (reading as "nothing here") to ORDRE 0 / FLY 1, next to another repo still reading ORDRE 0 / FLY 0 and genuinely holding nothing. Those two rows had been byte-identical the day before.

What FLY does not mean, and must never be reworded into: that a session is alive. A claim is a mv a session performed once. Nothing un-claims it when that session dies — which is exactly why the order queue's read path already shows claimed orders with their in-flight age. Measured on the live mailbox the same day: one order had been sitting claimed for 117 hours. FLY is evidence that someone took the order. It is not evidence that anyone is still working it, and the on-screen legend says so in those words, because a column that read as "a session is running here" would be the process axis smuggled in as a file count.

--plan names free capacity

ledig_antall=N, then one ledig=<repo> (<status>) line per free repo. Free means all four at once: nothing owed (not merely nothing pending — a notice is not an obligation), no pending order, nothing in flight, clean tree, at done or deferred.

All four conditions are load-bearing. Measured on the real tree the same day: of 17 done/deferred repos, 13 were free and 4 were not — two held a pending order, one owed a reply, one had an uncommitted tree. status=done alone would have named the wrong set roughly a quarter of the time.

It is emitted as lines, never as blocks, and that is the whole design rather than a formatting preference. The plan's second consumer opens one pane per block and discards any block without a tab= key; a free repo written as a block would therefore be visible to the operator and invisible to the driver. A line is visible to both and can never be opened as a tab by accident. The count prints even when it is zero, so "none found" and "not computed" cannot render as the same output.

A tab block whose repo already holds a claimed order additionally carries fly=N. The driver types into live panes; it should be able to see that first.

What was NOT changed, and the argument for it

The board still inspects no processes. No pgrep, no ps, no lsof, and a structural check in the selftest now says so with a known-positive control proving the grep can find a planted call. This was the order's open design question, and the answer is no, for four reasons that compound:

  1. Every other column is a durable filesystem fact. They survive a reboot and they are reproducible in a throwaway fixture tree under CLAUDE_COORD_DIR. A process column measures the operator's machine at one instant. There is no fixture for it, so it would ship as an unmeasured assumption wearing a passing test — this repo's own named defect class.
  2. Mapping a process to a repo needs its working directory, which on macOS means lsof. That is a new external dependency against a stated zero- dependency convention, for a number that would still not mean what a reader would take it to mean.
  3. The discriminator is a threshold, and a threshold is a verdict. "38 minutes of CPU across 45 hours is idle" is a judgement about a session's liveness. Encoding it makes the board decide that a session is dead. The order queue is already forbidden from doing exactly this: nothing there expires anything, because building expiry would require the engine to know something it cannot. A process column is that same rule broken on a different surface.
  4. The file-based signal is not a substitute either, and pretending otherwise would just move the error. The 117-hour claim is the proof. So the board reports the claim and refuses the inference, which is what "prints evidence and takes no position" has always meant here.

The gap this leaves is real and is stated rather than closed: a pane that is open and idle with no claimed order and no queued work is still invisible to the board. Such a repo now shows up in ledig= if it is done/deferred and clean, which covers the common case; a planned repo with an idle pane does not, and cannot, because nothing in the filesystem distinguishes it from a planned repo nobody has opened. Closing that needs a terminal-side measurement, and that belongs to whatever drives the terminal, not to the mailbox.

What this does not answer

The order asked whether the board should say anything about open tabs at all. It now says nothing about them, deliberately. If the operator later wants pane occupancy on the board, the honest construction is for the terminal driver — which already probes panes and already consumes --plan — to supply that fact inward, the same way --dispatch requires --target-pane to be measured by the caller and passed in rather than looked up here. That direction keeps the dependency running one way and keeps this repo unable to break on a terminal API. It was not built, because it was not ordered and the operator has not asked for it.