CB-595: the Features catalogue is ~14 entries behind, so shipped capabilities are invisible to an operator #81

Closed
opened 2026-08-16 16:51:04 +02:00 by ltms · 2 comments
Owner

Found while checking release-1 close-out state on 2026-08-16.

CLAUDE.md has a mandatory rule: anything an operator can use, configure, or observe gets one entry in wiki/11-Features.md — what it does · the knob that turns it on · why it exists · the gotcha. The rule exists because this already happened once:

for twenty tickets a shipped capability landed nowhere and the Roadmap went on claiming the stage was finished

It has happened again.

The measurement

Ticket ids named in wiki/11-Features.md, against ticket ids in git log v1.0.0..HEAD:

in Features:  CB-113 115 301 302 303 305 307 401 501 502 504 505 508 511 517 518 521 522
              524 525 527 529 530 531 532 534 535 539 542 543 544 547 548 557 558 559 560
              561 562 563 566 568 571 572 573 574 576 578 580 581

shipped, no entry:  CB-523 538 551 552 553 554 564 565 567 569 570 575 577 579 583 584
                    585 587 588 591 592 593

Not all of those earn an entry — internal contract changes belong in wiki/9-Implementation.md, and test/coverage work is a Roadmap line. My first pass at classifying them:

Needs a Features entry (operator-facing).

Ticket Why it is operator-facing
CB-551 idle-lead heartbeat — a timer that nudges an idle lead back to work; has knobs
CB-553 + CB-554 + CB-585 three changes to what weight: and maxLoad: mean. weight <= 0 now really excludes; maxLoad: 0 really caps at zero; a negative value is refused at load
CB-579 a lead is resolved by tab name; the terminal: pin is gone and a config still carrying it is now rejected at load
CB-588 an async wait:false ticket now nudges the lead's pane by itself when it goes terminal
CB-592 the admin GITEA_ACCESS_TOKEN is shadowed in every member's environment
CB-567 + CB-569 + CB-570 + CB-575 per-role charters composed per spawn, delivered to both adapters, and receipted in the roster and the logs
CB-564 previously silent member-failure paths now report
CB-565 unsafe session recycle removed
CB-583 bridge_list's capacity view is quarantine-aware
CB-584 agentSessionId is persisted and exposed on bridge_spawn / bridge_list
CB-523 + CB-538 opencode members launch with --auto and a pinned compaction.auto
CB-591 the fleet runs through the LLM gateway; both of its ceilings were raised

Belongs elsewhere, not here. CB-552 (a superseded design → Roadmap) · CB-577 and CB-587 (internal contract → 9-Implementation.md) · CB-571 (a retag) · CB-593 (it is a documentation correction).

Why this blocks the release rather than trailing it

The three config ones are the sharp end. weight: and maxLoad: and the lead pin all changed meaning, not just behaviour, and bridged.yaml is gitignored — so a worker never sees it, CI never checks it, and the only place an operator could learn the new meaning is this page. A release whose knobs mean something different from the last release, with nothing written down, is how the fleet gets misconfigured silently.

Acceptance criteria

  1. Every ticket in the first table has an entry: what it does · the knob (exact config key or tool name) · why it exists · the gotcha.
  2. The why line is present and specific in every entry. It is the one that stops a decision being re-litigated from scratch a month later, and it is the one that gets skipped.
  3. The three config-meaning changes (CB-553/554/585, CB-579) each name the old meaning as well as the new one. An operator upgrading needs to know what changed under them.
  4. Tickets in the second list are placed where they belong, or deliberately left out with a one-line reason.
  5. No entry claims a capability that is not actually on main. Check the code, not the commit message.

Note on who can do this

wiki/ is a git submodule with its own remote. A worker's worktree does not contain it, and project rules forbid committing it. So the research can be delegated, but the wiki edit and push are the lead's.

Found while checking release-1 close-out state on 2026-08-16. `CLAUDE.md` has a mandatory rule: anything an operator can **use, configure, or observe** gets one entry in `wiki/11-Features.md` — what it does · the knob that turns it on · **why it exists** · the gotcha. The rule exists because this already happened once: > for twenty tickets a shipped capability landed nowhere and the Roadmap went on claiming the stage was finished It has happened again. ## The measurement Ticket ids named in `wiki/11-Features.md`, against ticket ids in `git log v1.0.0..HEAD`: ``` in Features: CB-113 115 301 302 303 305 307 401 501 502 504 505 508 511 517 518 521 522 524 525 527 529 530 531 532 534 535 539 542 543 544 547 548 557 558 559 560 561 562 563 566 568 571 572 573 574 576 578 580 581 shipped, no entry: CB-523 538 551 552 553 554 564 565 567 569 570 575 577 579 583 584 585 587 588 591 592 593 ``` Not all of those earn an entry — internal contract changes belong in `wiki/9-Implementation.md`, and test/coverage work is a Roadmap line. My first pass at classifying them: **Needs a Features entry (operator-facing).** | Ticket | Why it is operator-facing | |---|---| | CB-551 | idle-lead heartbeat — a timer that nudges an idle lead back to work; has knobs | | CB-553 + CB-554 + CB-585 | three changes to what `weight:` and `maxLoad:` **mean**. `weight <= 0` now really excludes; `maxLoad: 0` really caps at zero; a negative value is refused at load | | CB-579 | a lead is resolved by **tab name**; the `terminal:` pin is gone and a config still carrying it is now rejected at load | | CB-588 | an async `wait:false` ticket now nudges the lead's pane by itself when it goes terminal | | CB-592 | the admin `GITEA_ACCESS_TOKEN` is shadowed in every member's environment | | CB-567 + CB-569 + CB-570 + CB-575 | per-role charters composed per spawn, delivered to both adapters, and receipted in the roster and the logs | | CB-564 | previously silent member-failure paths now report | | CB-565 | unsafe session recycle removed | | CB-583 | `bridge_list`'s capacity view is quarantine-aware | | CB-584 | `agentSessionId` is persisted and exposed on `bridge_spawn` / `bridge_list` | | CB-523 + CB-538 | opencode members launch with `--auto` and a pinned `compaction.auto` | | CB-591 | the fleet runs through the LLM gateway; both of its ceilings were raised | **Belongs elsewhere, not here.** CB-552 (a superseded design → Roadmap) · CB-577 and CB-587 (internal contract → `9-Implementation.md`) · CB-571 (a retag) · CB-593 (it *is* a documentation correction). ## Why this blocks the release rather than trailing it The three config ones are the sharp end. `weight:` and `maxLoad:` and the lead pin all changed **meaning**, not just behaviour, and `bridged.yaml` is gitignored — so a worker never sees it, CI never checks it, and the only place an operator could learn the new meaning is this page. A release whose knobs mean something different from the last release, with nothing written down, is how the fleet gets misconfigured silently. ## Acceptance criteria 1. Every ticket in the first table has an entry: **what it does · the knob (exact config key or tool name) · why it exists · the gotcha.** 2. The **why** line is present and specific in every entry. It is the one that stops a decision being re-litigated from scratch a month later, and it is the one that gets skipped. 3. The three config-meaning changes (CB-553/554/585, CB-579) each name the **old** meaning as well as the new one. An operator upgrading needs to know what changed under them. 4. Tickets in the second list are placed where they belong, or deliberately left out with a one-line reason. 5. No entry claims a capability that is not actually on `main`. Check the code, not the commit message. ## Note on who can do this `wiki/` is a git submodule with its own remote. A worker's worktree does not contain it, and project rules forbid committing it. So the research can be delegated, but the wiki edit and push are the lead's.
ltms added this to the 1.1 — single-host close-out milestone 2026-08-16 16:51:04 +02:00
Author
Owner

Done. Wiki commits f7dd817 and bec9fdf — twelve new entries in total, closing the gap this ticket named.

A worker did the research (reading the code on main, not commit messages) and I wrote the entries. The split mattered: the research turned up things the commit messages did not say.

The three keys that changed meaning lead the batch, in one table, because that is what an upgrading operator meets first and none of it shows up in a diff of their own config:

Key Used to mean Now means
weight: 0 coerced to 1.0 — "pick me normally" excluded from automatic selection
maxLoad: 0 coerced to unlimited capped at zero
fleet.leaders.*.terminal a terminal-id pin refused at startup

The first two did the exact opposite of what they read like. maxLoad: 0 is the sharper one: it was the only throttle a subscription: true profile had against the operator's own paid plan, and it meant "unlimited".

The rest: the unconditional maxLoad cap on explicit spawns (with its documented TOCTOU race), the opt-in idle-lead heartbeat and why it must stay opt-in, charter receipts, the quarantine-aware capacity view, session resume and why it demands an explicit profile, opencode's --auto and forced auto-compaction with the trade stated plainly, the silent member-failure logging, and the removal of recycle().

Two claims in the research I checked before publishing, because both would have put an error on the page.

The researcher reported that CB-592's BRIDGED_MEMBER marker is "a no-op until the operator guards the export in secrets.sh". That describes the mechanism correctly but not the current state — the guard was applied on 2026-08-15 and verified on a live pane, which measured the sentinel in place and the admin token returning 401. The existing entry stands unchanged.

It also flagged that the tracked opencode.json reads {}. On main it has the full WORKER_GITEA_TOKEN mapping. The {} is what a member's worktree sees: the parity overlay writes an empty file and flags it skip-worktree, so a member can neither inherit nor commit the primary's config. Working as designed — but it fooled a careful reader, which is worth knowing.

Not closing this ticket yet. The backfill list still names five uncatalogued areas: /metrics and /healthz, bearer-token auth, the authz table and audit log, systemd supervision, and multi-profile routing. Those were out of this batch's scope and each needs its own verification pass. This ticket was about the post-v1.0.0 gap, and that part is done — say the word if you would rather track the remainder separately and close this one.

Done. Wiki commits `f7dd817` and `bec9fdf` — twelve new entries in total, closing the gap this ticket named. A worker did the research (reading the code on `main`, not commit messages) and I wrote the entries. The split mattered: the research turned up things the commit messages did not say. **The three keys that changed meaning lead the batch**, in one table, because that is what an upgrading operator meets first and none of it shows up in a diff of their own config: | Key | Used to mean | Now means | |---|---|---| | `weight: 0` | coerced to 1.0 — "pick me normally" | excluded from automatic selection | | `maxLoad: 0` | coerced to unlimited | capped at zero | | `fleet.leaders.*.terminal` | a terminal-id pin | **refused at startup** | The first two did the exact opposite of what they read like. `maxLoad: 0` is the sharper one: it was the only throttle a `subscription: true` profile had against the operator's own paid plan, and it meant "unlimited". The rest: the unconditional `maxLoad` cap on explicit spawns (with its documented TOCTOU race), the opt-in idle-lead heartbeat and why it must stay opt-in, charter receipts, the quarantine-aware capacity view, session resume and why it demands an explicit profile, opencode's `--auto` and forced auto-compaction with the trade stated plainly, the silent member-failure logging, and the removal of `recycle()`. **Two claims in the research I checked before publishing, because both would have put an error on the page.** The researcher reported that CB-592's `BRIDGED_MEMBER` marker is "a no-op until the operator guards the export in `secrets.sh`". That describes the mechanism correctly but not the current state — the guard was applied on 2026-08-15 and verified on a live pane, which measured the sentinel in place and the admin token returning 401. The existing entry stands unchanged. It also flagged that the tracked `opencode.json` reads `{}`. On `main` it has the full `WORKER_GITEA_TOKEN` mapping. The `{}` is what a **member's worktree** sees: the parity overlay writes an empty file and flags it `skip-worktree`, so a member can neither inherit nor commit the primary's config. Working as designed — but it fooled a careful reader, which is worth knowing. **Not closing this ticket yet.** The backfill list still names five uncatalogued areas: `/metrics` and `/healthz`, bearer-token auth, the authz table and audit log, systemd supervision, and multi-profile routing. Those were out of this batch's scope and each needs its own verification pass. This ticket was about the post-`v1.0.0` gap, and that part is done — say the word if you would rather track the remainder separately and close this one.
Author
Owner

Closed. The catalogue is current.

Two passes got here. The first cleared the ~14 operator-facing tickets this issue measured. The second (wiki 073f010) wrote the five areas that pass had explicitly left open: /metrics and /healthz, bearer auth and the bind fail-fast, the authz table and audit log, systemd supervision, and multi-profile kind: routing. Every claim in those five is traced to a file:line on main.

One item is deliberately still listed as outstanding: the reply push loop's nudge budget. CB-590 and CB-598 both changed it today, and the interesting part — that the cap now bounds nudges per pending item, so a lead with a steady arrival of new work keeps being nudged — deserves a settled description rather than one written the same afternoon the code changed.

The backfill found two defects it was not looking for

Both are the same shape, and it is the shape this repo keeps hitting: a configuration that is accepted, does nothing useful, and reports no error.

  • #102 (CB-604) — kind: is never validated. kind: opencod is accepted, routed to the claude-code adapter, and with argv: unset the launch command becomes the misspelled string itself. Filed on 1.1.
  • #103 (CB-605) — the systemd unit has the login-shell secret gap that scripts/bridged-launchd-wrapper.sh already fixes for launchd, and names only BRIDGED_API_TOKEN. An operator following its own guidance gets a daemon that boots fine and members that cannot open a PR. Filed on 2.0, since it bites only when the first Linux gateway is stood up.

Also recorded on the page: AgentControl's class doc says herdr protocol 19, HerdrClient's still says 14, and nothing compares the number herdr reports against what bridged needs — which is how /healthz once went green while every spawn failed.

One correction to the delivery

The worker reported that the entry Supervise the daemon without breaking the fleet "does not exist anywhere in the repo". It does — it has been on the page for hours. The worker was not careless: it ran git submodule update --init, which checks out the pointer recorded in the parent repo, and that pointer is deliberately never updated because committing wiki/ is on the never-commit list. Its checkout was months old.

That is worth more than the correction. A worker cannot read the current wiki. Any brief that says "read wiki/11-Features.md" is asking for a stale answer, and the worker has no way to know. I have written this into the page's backfill section, and briefs should paste the relevant text instead of pointing at the file.

The worker also flagged that the reviewer skill I named in line 1 did not fit a research-and-write task and that it followed the brief's own format instead. That was the right call and my brief was wrong to name that skill.

Closed. The catalogue is current. Two passes got here. The first cleared the ~14 operator-facing tickets this issue measured. The second (wiki `073f010`) wrote the five areas that pass had explicitly left open: `/metrics` and `/healthz`, bearer auth and the bind fail-fast, the authz table and audit log, systemd supervision, and multi-profile `kind:` routing. Every claim in those five is traced to a `file:line` on `main`. One item is deliberately still listed as outstanding: the reply push loop's nudge budget. CB-590 and CB-598 both changed it **today**, and the interesting part — that the cap now bounds nudges *per pending item*, so a lead with a steady arrival of new work keeps being nudged — deserves a settled description rather than one written the same afternoon the code changed. ## The backfill found two defects it was not looking for Both are the same shape, and it is the shape this repo keeps hitting: **a configuration that is accepted, does nothing useful, and reports no error.** - **#102 (CB-604)** — `kind:` is never validated. `kind: opencod` is accepted, routed to the *claude-code* adapter, and with `argv:` unset the launch command becomes the misspelled string itself. Filed on 1.1. - **#103 (CB-605)** — the systemd unit has the login-shell secret gap that `scripts/bridged-launchd-wrapper.sh` already fixes for launchd, and names only `BRIDGED_API_TOKEN`. An operator following its own guidance gets a daemon that boots fine and members that cannot open a PR. Filed on 2.0, since it bites only when the first Linux gateway is stood up. Also recorded on the page: `AgentControl`'s class doc says herdr protocol 19, `HerdrClient`'s still says 14, and nothing compares the number herdr reports against what bridged needs — which is how `/healthz` once went green while every spawn failed. ## One correction to the delivery The worker reported that the entry *Supervise the daemon without breaking the fleet* "does not exist anywhere in the repo". It does — it has been on the page for hours. The worker was not careless: it ran `git submodule update --init`, which checks out the pointer **recorded in the parent repo**, and that pointer is deliberately never updated because committing `wiki/` is on the never-commit list. Its checkout was months old. That is worth more than the correction. **A worker cannot read the current wiki.** Any brief that says "read `wiki/11-Features.md`" is asking for a stale answer, and the worker has no way to know. I have written this into the page's backfill section, and briefs should paste the relevant text instead of pointing at the file. The worker also flagged that the `reviewer` skill I named in line 1 did not fit a research-and-write task and that it followed the brief's own format instead. That was the right call and my brief was wrong to name that skill.
ltms closed this issue 2026-08-16 18:33:15 +02:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: fleet/fleetd#81