CB-638: the wiki describes a system that no longer exists — audit index of pages to revise, build and retire #168

Closed
opened 2026-08-24 18:44:37 +02:00 by kevin · 5 comments
Owner

The wiki has drifted behind the code. This ticket is the index of what to fix: which pages to revise, which to build, which to retire.

Found during a full architecture review of fleetd + fleet-manager on 2026-08-24. Every count below was produced by grepping a fresh clone of the wiki against the current main (3f4ac2b), and the "still current" list was checked against the code rather than assumed.

Rule for this work

The code is authoritative. The wiki is not. Where a page and the source disagree, the page is wrong until proven otherwise — and the fix is to read the code, not to reword the page.

Rename map — what actually changed

Stale Current Landed
bridge_* MCP tools (11) fleet_* (11) — fleet_send fleet_reply fleet_ask fleet_ack fleet_status fleet_poll fleet_list fleet_spawn fleet_stop fleet_profiles fleet_whoami CB-632, 2026-08-23
GET/POST/DELETE /workers /members CB-557, 2026-08-14
bridged_spawns / bridged_sends / bridged_push metrics fleet_spawns_total / fleet_sends_total / fleet_push_nudges_total CB-632
herdr protocol 14 (0.7.0) protocol 19 (0.8.0) CB-5xx
ollama.ltms.dev, gx00 llm.ltms.dev —
port 8080 8765 —
Redis Streams / NATS LavinMQ over AMQP, optional CB-307
AgentAPI "swappable fallback injector" never built — discarded option —
SSE / GET /events does not exist — no text/event-stream handler anywhere in bridged/src/main/java —

Do NOT blind find-and-replace bridged

Several bridged* names are still correct and a sweep would break them:

  • BRIDGED_MEMBER, BRIDGED_API, BRIDGED_WORKER_TOKEN — live env var names in the source
  • scripts/redeploy-bridged.sh, scripts/bridged-launchd-wrapper.sh — real filenames
  • deploy/dev.ltms.bridged.plist, dev.ltms.bridged.service — real filenames
  • bridged.jar — the artifact's real finalName
  • bridged.yaml — still accepted as a fallback; Fleetd.java:85-94 notes the operator's live file is still named this

Only the tool names, metric names, and route paths in the table above are renames. Everything else needs a per-hit judgement.

A. Pages to revise

Ranked by how wrong they are. Counts are stale-token hits, verified today.

# Page bridge_* /workers metrics proto14 old host SSE 8080 redis/nats AgentAPI Verdict
1 2-Message-Server 29 0 0 3 5 20 2 7 17 Rewrite. Design-era page describing a system that was not built. Documents GET /events as a real SSE endpoint (line 45) and "REST + SSE (OpenAPI, AgentAPI-shaped)" (line 222). Worst page in the wiki.
2 8-Roadmap 44 3 1 6 8 2 2 1 0 Revise + split. Only page still naming /workers. Historical entries may legitimately keep old names — mark them as history explicitly rather than silently updating.
3 11-Features 66 0 7 2 0 0 0 0 0 Revise. Largest page (2203 lines) and the most bridge_* hits. Also the only page with stale metric names. Note its CLAUDE.md block must stay byte-identical with the repo copy.
4 1-Architecture 11 0 0 0 2 4 0 1 3 Revise. Claims SSE and AgentAPI fallback. Its diagram shows send_text · events.subscribe; the code uses agent.prompt and polls — events.subscribe is deferred (UnixSocketHerdrClient.java:28-30).
5 13-User-Guide 35 0 0 0 1 0 0 0 0 Revise. Accurate as of 2026-08-17 but predates CB-632/633/635. The "eleven tools" section names the deprecated set. Highest-traffic page — fix early.
6 9-Implementation 27 2 0 0 1 0 0 0 0 Revise. Names /workers. Package count/protocol were fixed 2026-08-15 but the tool and route names were not.
7 7-Use-Cases 23 0 0 0 13 0 0 1 0 Revise. Heaviest user of the decommissioned host names. CLAUDE.md block must stay byte-identical with the repo copy.
8 6-Team 15 0 0 0 2 2 0 0 1 Revise. Untouched since 2026-07-14.
9 3-Approaches 3 0 0 0 0 2 0 2 11 Revise lightly. A research matrix — AgentAPI hits are legitimately historical. Add a dated "what was chosen and what was never built" header rather than rewriting.
10 10-Cross-Host-Messaging 8 0 0 0 0 0 0 0 0 Revise. Tool names only.
11 Home 4 0 0 0 0 3 0 0 5 Fix contradiction. Line 73 says AgentAPI "was never built — treat it as a discarded option"; line 103 still says "AgentAPI is retained as a fallback injector." The 2026-08-17 audit fixed one paragraph and left the other. Also still claims SSE.
12 12-Claude-to-OpenCode 0 0 0 0 0 1 0 0 0 Nearly clean. One SSE mention.
13 _Sidebar 0 0 0 0 0 0 0 0 1 Update last — after the new pages in §B exist.

B. Pages to build

Page Why Source material
14-Fleet-Manager fleet-manager has zero coverage in the wiki — grep -ril 'fleet-manager|fleets.json' returns nothing across all 15 pages. It is a separate repo, a separate build, and the operator-facing entry point for multi-fleet work. fleet-manager/README.md, probe.py, issues #160 and #156
15-REST-API-Reference The 14 routes are documented nowhere as a set — only scattered through 7 pages. This matters more than it looks: MCP and REST are sibling adapters over the service layer, not thin wrappers (Fleetd.java:492-506), so REST behaviour cannot be inferred from the MCP contract. fleet_ack and fleet_whoami have no REST route at all. rest/FleetApp.java:115-131, docs/MCP-Contract.md
16-Security-and-Trust-Boundary (optional, recommend yes) The subscription guard, the authz role table, the member credential scrub, and token handling are scattered across pages 1, 11 and 13. Four open issues cluster here — #155, #157, #159, #161 — which is the signal that it deserves one page. guard/SubscriptionGuard.java, auth/, member/MemberEnvAllowList.java

C. Pages to retire — decide, don't drift

4-Setup (25 lines) and 5-Operations (35 lines) are honest redirect stubs pointing at 13-User-Guide. They are not broken and the "what this page predicted vs what shipped" table in 5-Operations has real archival value.

Decision needed: keep them as redirects, or delete and renumber. Either is fine — but leaving it undecided is how they rot again. If kept, fix the two stale technical claims still inside them (protocol 14 in 4-Setup, port 8080 in 4-Setup).

Acceptance criteria

  1. Every page in §A has been read against the current source, not just find-and-replaced.
  2. The "do NOT replace" list above survives intact — the live env vars, script names and plist names are unchanged.
  3. Pages 14 and 15 in §B exist; _Sidebar and Home link to them.
  4. A decision is recorded on §C, in the page itself.
  5. Historical sections (8-Roadmap, 3-Approaches) that keep old names say explicitly that they are historical.
  6. This audit re-run comes back clean for the rename map, allowing for documented historical mentions:
git clone ssh://git@git.ltms.dev:2224/fleet/fleetd.wiki.git /tmp/wiki-audit && cd /tmp/wiki-audit
grep -rInE 'bridge_[a-z]+|/workers|bridged_(spawns|sends|push)|protocol 14|ollama\.ltms\.dev|gx00|8080|GET /events' .
grep -rIniE 'sse\b|event-stream|events\.subscribe' .

Notes

  • 265 bridge_* occurrences across 12 pages is the single largest mechanical sweep, but it is not purely mechanical — the daemon still answers the bridge_* names for one release, so a page describing the deprecation window should keep both, labelled.
  • The wiki is a submodule of the fleetd repo and is not fetched by default — fleetd/wiki/ is empty on a fresh clone while README.md and CLAUDE.md link into it 10 times. Worth fixing alongside this, or the revised pages stay invisible to anyone who clones the repo.

Filed from an architecture review on 2026-08-24 against main @ 3f4ac2b.

The wiki has drifted behind the code. This ticket is the index of what to fix: which pages to revise, which to build, which to retire. Found during a full architecture review of `fleetd` + `fleet-manager` on 2026-08-24. Every count below was produced by grepping a fresh clone of the wiki against the current `main` (`3f4ac2b`), and the "still current" list was checked against the code rather than assumed. ## Rule for this work **The code is authoritative. The wiki is not.** Where a page and the source disagree, the page is wrong until proven otherwise — and the fix is to read the code, not to reword the page. ## Rename map — what actually changed | Stale | Current | Landed | |---|---|---| | `bridge_*` MCP tools (11) | `fleet_*` (11) — `fleet_send` `fleet_reply` `fleet_ask` `fleet_ack` `fleet_status` `fleet_poll` `fleet_list` `fleet_spawn` `fleet_stop` `fleet_profiles` `fleet_whoami` | CB-632, 2026-08-23 | | `GET/POST/DELETE /workers` | `/members` | CB-557, 2026-08-14 | | `bridged_spawns` / `bridged_sends` / `bridged_push` metrics | `fleet_spawns_total` / `fleet_sends_total` / `fleet_push_nudges_total` | CB-632 | | herdr protocol 14 (0.7.0) | protocol 19 (0.8.0) | CB-5xx | | `ollama.ltms.dev`, `gx00` | `llm.ltms.dev` | — | | port 8080 | 8765 | — | | Redis Streams / NATS | LavinMQ over AMQP, **optional** | CB-307 | | AgentAPI "swappable fallback injector" | **never built** — discarded option | — | | SSE / `GET /events` | **does not exist** — no `text/event-stream` handler anywhere in `bridged/src/main/java` | — | ## Do NOT blind find-and-replace `bridged` Several `bridged*` names are **still correct** and a sweep would break them: - `BRIDGED_MEMBER`, `BRIDGED_API`, `BRIDGED_WORKER_TOKEN` — live env var names in the source - `scripts/redeploy-bridged.sh`, `scripts/bridged-launchd-wrapper.sh` — real filenames - `deploy/dev.ltms.bridged.plist`, `dev.ltms.bridged.service` — real filenames - `bridged.jar` — the artifact's real `finalName` - `bridged.yaml` — still accepted as a fallback; `Fleetd.java:85-94` notes the operator's live file is still named this Only the **tool names, metric names, and route paths** in the table above are renames. Everything else needs a per-hit judgement. ## A. Pages to revise Ranked by how wrong they are. Counts are stale-token hits, verified today. | # | Page | `bridge_*` | `/workers` | metrics | proto14 | old host | SSE | 8080 | redis/nats | AgentAPI | Verdict | |---|---|---|---|---|---|---|---|---|---|---|---| | 1 | **2-Message-Server** | 29 | 0 | 0 | 3 | 5 | **20** | 2 | 7 | **17** | **Rewrite.** Design-era page describing a system that was not built. Documents `GET /events` as a real SSE endpoint (line 45) and "REST + SSE (OpenAPI, AgentAPI-shaped)" (line 222). Worst page in the wiki. | | 2 | **8-Roadmap** | 44 | **3** | 1 | 6 | 8 | 2 | 2 | 1 | 0 | **Revise + split.** Only page still naming `/workers`. Historical entries may legitimately keep old names — mark them as history explicitly rather than silently updating. | | 3 | **11-Features** | **66** | 0 | **7** | 2 | 0 | 0 | 0 | 0 | 0 | **Revise.** Largest page (2203 lines) and the most `bridge_*` hits. Also the only page with stale metric names. Note its CLAUDE.md block must stay byte-identical with the repo copy. | | 4 | **1-Architecture** | 11 | 0 | 0 | 0 | 2 | 4 | 0 | 1 | 3 | **Revise.** Claims SSE and AgentAPI fallback. Its diagram shows `send_text · events.subscribe`; the code uses `agent.prompt` and **polls** — `events.subscribe` is deferred (`UnixSocketHerdrClient.java:28-30`). | | 5 | **13-User-Guide** | 35 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | **Revise.** Accurate as of 2026-08-17 but predates CB-632/633/635. The "eleven tools" section names the deprecated set. Highest-traffic page — fix early. | | 6 | **9-Implementation** | 27 | **2** | 0 | 0 | 1 | 0 | 0 | 0 | 0 | **Revise.** Names `/workers`. Package count/protocol were fixed 2026-08-15 but the tool and route names were not. | | 7 | **7-Use-Cases** | 23 | 0 | 0 | 0 | **13** | 0 | 0 | 1 | 0 | **Revise.** Heaviest user of the decommissioned host names. CLAUDE.md block must stay byte-identical with the repo copy. | | 8 | **6-Team** | 15 | 0 | 0 | 0 | 2 | 2 | 0 | 0 | 1 | **Revise.** Untouched since 2026-07-14. | | 9 | **3-Approaches** | 3 | 0 | 0 | 0 | 0 | 2 | 0 | 2 | **11** | **Revise lightly.** A research matrix — AgentAPI hits are legitimately historical. Add a dated "what was chosen and what was never built" header rather than rewriting. | | 10 | **10-Cross-Host-Messaging** | 8 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | **Revise.** Tool names only. | | 11 | **Home** | 4 | 0 | 0 | 0 | 0 | 3 | 0 | 0 | 5 | **Fix contradiction.** Line 73 says AgentAPI "was **never built** — treat it as a discarded option"; line 103 still says "AgentAPI is retained as a fallback injector." The 2026-08-17 audit fixed one paragraph and left the other. Also still claims SSE. | | 12 | **12-Claude-to-OpenCode** | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | **Nearly clean.** One SSE mention. | | 13 | **_Sidebar** | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | **Update last** — after the new pages in §B exist. | ## B. Pages to build | Page | Why | Source material | |---|---|---| | **14-Fleet-Manager** | `fleet-manager` has **zero coverage** in the wiki — `grep -ril 'fleet-manager\|fleets.json'` returns nothing across all 15 pages. It is a separate repo, a separate build, and the operator-facing entry point for multi-fleet work. | `fleet-manager/README.md`, `probe.py`, issues #160 and #156 | | **15-REST-API-Reference** | The 14 routes are documented nowhere as a set — only scattered through 7 pages. This matters more than it looks: MCP and REST are **sibling adapters over the service layer, not thin wrappers** (`Fleetd.java:492-506`), so REST behaviour cannot be inferred from the MCP contract. `fleet_ack` and `fleet_whoami` have **no REST route at all**. | `rest/FleetApp.java:115-131`, `docs/MCP-Contract.md` | | **16-Security-and-Trust-Boundary** *(optional, recommend yes)* | The subscription guard, the authz role table, the member credential scrub, and token handling are scattered across pages 1, 11 and 13. Four open issues cluster here — #155, #157, #159, #161 — which is the signal that it deserves one page. | `guard/SubscriptionGuard.java`, `auth/`, `member/MemberEnvAllowList.java` | ## C. Pages to retire — decide, don't drift **4-Setup** (25 lines) and **5-Operations** (35 lines) are honest redirect stubs pointing at 13-User-Guide. They are not broken and the "what this page predicted vs what shipped" table in 5-Operations has real archival value. Decision needed: keep them as redirects, or delete and renumber. Either is fine — but leaving it undecided is how they rot again. If kept, fix the two stale technical claims still inside them (protocol 14 in 4-Setup, port 8080 in 4-Setup). ## Acceptance criteria 1. Every page in §A has been read against the current source, not just find-and-replaced. 2. The "do NOT replace" list above survives intact — the live env vars, script names and plist names are unchanged. 3. Pages 14 and 15 in §B exist; `_Sidebar` and `Home` link to them. 4. A decision is recorded on §C, in the page itself. 5. Historical sections (8-Roadmap, 3-Approaches) that keep old names say **explicitly** that they are historical. 6. This audit re-run comes back clean for the rename map, allowing for documented historical mentions: ```sh git clone ssh://git@git.ltms.dev:2224/fleet/fleetd.wiki.git /tmp/wiki-audit && cd /tmp/wiki-audit grep -rInE 'bridge_[a-z]+|/workers|bridged_(spawns|sends|push)|protocol 14|ollama\.ltms\.dev|gx00|8080|GET /events' . grep -rIniE 'sse\b|event-stream|events\.subscribe' . ``` ## Notes - 265 `bridge_*` occurrences across 12 pages is the single largest mechanical sweep, but it is **not** purely mechanical — the daemon still answers the `bridge_*` names for one release, so a page describing the deprecation window should keep both, labelled. - The wiki is a submodule of the `fleetd` repo and is **not fetched by default** — `fleetd/wiki/` is empty on a fresh clone while README.md and CLAUDE.md link into it 10 times. Worth fixing alongside this, or the revised pages stay invisible to anyone who clones the repo. --- Filed from an architecture review on 2026-08-24 against `main` @ `3f4ac2b`.
kevin added the ready-to-delegate label 2026-08-24 18:44:37 +02:00
Author
Owner

Proposed structure — research, diagnosis, and a target layout

The page list above says what is wrong. This comment proposes how to organise it so it does not rot again, based on the established frameworks rather than invention.

What the field actually recommends

Diátaxis (Procida; adopted by Canonical, Django, Gatsby) is the dominant structural framework. It says documentation serves four distinct needs, generated by two axes — action vs. cognition, and study vs. work:

Type Serves Question it answers
Tutorial learning, by doing "Take me through my first one."
How-to guide a goal, competently "How do I accomplish X?"
Reference facts, while working "What exactly is the signature/route/key?"
Explanation understanding "Why is it built this way?"

Its central claim is the one that matters here: "crossing or blurring the boundaries described in the map is at the heart of a vast number of problems in documentation." A page that mixes types cannot be maintained, because no single change is ever scoped to it.

arc42 §9 and ADRs (Nygard format: Title / Context / Decision / Status / Consequences) cover the part Diátaxis does not: decisions. The load-bearing rule is that an ADR is immutable — when a decision changes you write a new record with Status: superseded by ADR-000N, you never edit the old one. That preserves the rationale instead of letting it rot in place.

Docs-as-code / generated reference is the consensus anti-rot mechanism: derive reference material from the source, review doc changes with the code change, and run freshness checks in CI. The recurring finding is that the most accurate documentation is generated from code, because then it cannot drift.

Diagnosis — why this wiki rotted

Applying that lens to the audit findings, the 265 stale tokens are symptoms of three specific structural causes:

1. Every page mixes Diátaxis types, so nothing has a maintainable scope.
13-User-Guide is the clearest case — one page covering install (how-to), configure (reference), delegate (tutorial + how-to) and troubleshooting (how-to). It was written accurately on 2026-08-17 and was stale eight days later, because any change to any of those four concerns invalidates "the page" and nobody wants to re-audit 473 lines. 11-Features has the same problem at 2203 lines.

2. The wiki restates facts the code owns — that is the drift engine.
Tool names, route paths, metric names, protocol numbers and ports are all reference facts with an authoritative home in the source. The wiki keeps a hand-copied second copy. 265 bridge_* occurrences exist only because CB-632 renamed a thing in one place and the copy in twelve pages could not follow. This will happen again on the next rename unless the copy stops being hand-maintained.

3. Design decisions live in prose in living pages instead of frozen records.
This directly explains the Home.md contradiction found in the audit. The AgentAPI decision is stated in at least three places (Home, 1-Architecture, 3-Approaches, 2-Message-Server). The 2026-08-17 audit corrected one paragraph and missed the rest, so the same page now says both "never built — a discarded option" (line 73) and "retained as a fallback injector" (line 103). One immutable ADR would have one answer.

Proposed structure

Four sections by Diátaxis type, plus decisions and meta. Prefix by section rather than a flat sequence, so adding a page never renumbers its neighbours:

Home                        — router: "what do you want to do?" → the four sections
_Sidebar

T-1  First fleet             TUTORIAL   ← does not exist today
H-1  Install and bring up    HOW-TO     ← 13 §2  + 4-Setup
H-2  Configure a fleet       HOW-TO     ← 13 §3
H-3  Delegate work           HOW-TO     ← 13 §5
H-4  Run and prove it runs   HOW-TO     ← 13 §4  + 5-Operations
H-5  When it breaks          HOW-TO     ← 13 §6
H-6  Add an OpenCode member  HOW-TO     ← 12
H-7  Operate several fleets  HOW-TO     ← NEW (fleet-manager)
R-1  MCP tool reference      REFERENCE  ← GENERATED
R-2  REST API reference      REFERENCE  ← GENERATED
R-3  Configuration keys      REFERENCE  ← GENERATED
R-4  Metrics                 REFERENCE  ← GENERATED
R-5  Package map             REFERENCE  ← 9
E-1  How the fleet works     EXPLANATION ← 1
E-2  The messaging design    EXPLANATION ← 2 (current parts only)
E-3  Cross-host messaging    EXPLANATION ← 10
E-4  Trust and the subscription boundary  EXPLANATION ← NEW
E-5  Roles and the team model EXPLANATION ← 6
D-*  Decision records        ADR        ← 3, design-era parts of 2 and 8
M-1  Feature log             META       ← 11
M-2  Release history         META       ← 8 (shipped half only)

What changes, concretely:

  • 13-User-Guide splits into H-1…H-5. It is the best page in the wiki and this is not a demotion — splitting it is what lets each half be re-verified independently instead of annually.
  • 3-Approaches becomes D-0001: herdr-centric message server, status accepted, and is then never edited again. The AgentAPI/Redis/NATS content stops being "stale" the moment it is correctly framed as a 2026-07-11 decision record. Same for the design-era half of 2-Message-Server → D-0002, and the bridged→fleetd rename → D-0003.
  • 8-Roadmap splits: shipped history → M-2 (frozen), future plans → Gitea issues and milestones, not the wiki. A roadmap in a wiki is a page that is wrong by default.
  • 11-Features (2203 lines) splits: the capability list is reference, the rationale is explanation. Its CLAUDE.md block must stay byte-identical with the repo copy — that constraint moves with it.
  • The four R-* pages are generated, not written.

The anti-rot mechanism — the part that matters most

Structure alone will not stop this recurring. The concrete proposal:

1. Generate the reference pages from source. This is feasible today with no new dependency. The MCP tools are already declared as McpSchema.Tool values built by sendTool(), replyTool() … whoamiTool() (FleetMcp.java:282-292), so a small emitter can walk them and render name + description + JSON schema. Same shape for routes (FleetApp.java:115-131), metrics (FleetMetrics.java) and config keys (fleetd.example.yaml).

2. Make it a golden-file test, not a build step. Regenerate into a committed file and fail the build when it differs — the idiom this repo already uses heavily, and it inverts the incentive: after this, CB-632 could not have been merged without updating the docs, because the rename would have broken the build. That is the whole fix in one sentence.

3. Run the audit grep from the ticket body in CI, scoped to the non-generated pages, allowing tokens inside D-* records (where old names are correct, because a decision record describes the world at its date).

4. Adopt the "freeze vs. auto-update" distinction explicitly. D-* and M-2 are frozen — old names there are correct and must not be swept. Everything else is live and must match main. Marking this per-page is what stops the next audit from "fixing" history.

Migration order

Diátaxis explicitly recommends against a big-bang restructure — "identify one small improvement, implement it, repeat." Suggested order, each step shippable alone:

  1. R-1…R-4 generated + golden test. Highest leverage: kills the largest category of drift permanently and makes ~200 of the 265 stale tokens unreachable.
  2. D-0001–D-0003. Cheap — mostly relabelling existing pages — and immediately resolves the Home.md contradiction plus most of the AgentAPI/Redis/NATS noise, without rewriting the prose.
  3. Split 13-User-Guide into H-1…H-5, re-verifying each against main as it moves.
  4. H-7 (fleet-manager) and E-4 (trust boundary) — the two genuine coverage gaps.
  5. E-* prose sweep, last, because by then only genuine explanation text remains.
  6. Home + _Sidebar rewritten as routers, once the destinations exist.

One cost to accept deliberately

Renaming pages breaks every inbound link — from README.md, CLAUDE.md, prior issues and commit messages. Two options: keep the old page as a one-line redirect stub (the pattern 4-Setup already uses, which works), or accept the breakage and fix the repo's own links in the same PR. Recommend redirect stubs for Home, 13-User-Guide and 11-Features (the three with real external inbound traffic) and clean renames for the rest.

Sources

## Proposed structure — research, diagnosis, and a target layout The page list above says *what* is wrong. This comment proposes *how to organise it* so it does not rot again, based on the established frameworks rather than invention. ### What the field actually recommends **[Diátaxis](https://diataxis.fr/)** (Procida; adopted by Canonical, Django, Gatsby) is the dominant structural framework. It says documentation serves four distinct needs, generated by two axes — *action vs. cognition*, and *study vs. work*: | Type | Serves | Question it answers | |---|---|---| | **Tutorial** | learning, by doing | "Take me through my first one." | | **How-to guide** | a goal, competently | "How do I accomplish X?" | | **Reference** | facts, while working | "What exactly is the signature/route/key?" | | **Explanation** | understanding | "Why is it built this way?" | Its central claim is the one that matters here: *"crossing or blurring the boundaries described in the map is at the heart of a vast number of problems in documentation."* A page that mixes types cannot be maintained, because no single change is ever scoped to it. **[arc42 §9](https://docs.arc42.org/section-9/)** and **[ADRs](https://github.com/architecture-decision-record/architecture-decision-record)** (Nygard format: Title / Context / Decision / Status / Consequences) cover the part Diátaxis does not: *decisions*. The load-bearing rule is that an ADR is **immutable** — when a decision changes you write a new record with `Status: superseded by ADR-000N`, you never edit the old one. That preserves the rationale instead of letting it rot in place. **Docs-as-code / generated reference** is the consensus anti-rot mechanism: derive reference material from the source, review doc changes with the code change, and run freshness checks in CI. The recurring finding is that *the most accurate documentation is generated from code, because then it cannot drift*. ### Diagnosis — why *this* wiki rotted Applying that lens to the audit findings, the 265 stale tokens are symptoms of three specific structural causes: **1. Every page mixes Diátaxis types, so nothing has a maintainable scope.** `13-User-Guide` is the clearest case — one page covering install (how-to), configure (reference), delegate (tutorial + how-to) and troubleshooting (how-to). It was written accurately on 2026-08-17 and was stale eight days later, because *any* change to *any* of those four concerns invalidates "the page" and nobody wants to re-audit 473 lines. `11-Features` has the same problem at 2203 lines. **2. The wiki restates facts the code owns — that is the drift engine.** Tool names, route paths, metric names, protocol numbers and ports are all *reference* facts with an authoritative home in the source. The wiki keeps a hand-copied second copy. 265 `bridge_*` occurrences exist only because CB-632 renamed a thing in one place and the copy in twelve pages could not follow. This will happen again on the next rename unless the copy stops being hand-maintained. **3. Design decisions live in prose in living pages instead of frozen records.** This directly explains the `Home.md` contradiction found in the audit. The AgentAPI decision is stated in at least three places (`Home`, `1-Architecture`, `3-Approaches`, `2-Message-Server`). The 2026-08-17 audit corrected one paragraph and missed the rest, so the same page now says both "never built — a discarded option" (line 73) and "retained as a fallback injector" (line 103). One immutable ADR would have one answer. ### Proposed structure Four sections by Diátaxis type, plus decisions and meta. Prefix by section rather than a flat sequence, so adding a page never renumbers its neighbours: ``` Home — router: "what do you want to do?" → the four sections _Sidebar T-1 First fleet TUTORIAL ← does not exist today H-1 Install and bring up HOW-TO ← 13 §2 + 4-Setup H-2 Configure a fleet HOW-TO ← 13 §3 H-3 Delegate work HOW-TO ← 13 §5 H-4 Run and prove it runs HOW-TO ← 13 §4 + 5-Operations H-5 When it breaks HOW-TO ← 13 §6 H-6 Add an OpenCode member HOW-TO ← 12 H-7 Operate several fleets HOW-TO ← NEW (fleet-manager) R-1 MCP tool reference REFERENCE ← GENERATED R-2 REST API reference REFERENCE ← GENERATED R-3 Configuration keys REFERENCE ← GENERATED R-4 Metrics REFERENCE ← GENERATED R-5 Package map REFERENCE ← 9 E-1 How the fleet works EXPLANATION ← 1 E-2 The messaging design EXPLANATION ← 2 (current parts only) E-3 Cross-host messaging EXPLANATION ← 10 E-4 Trust and the subscription boundary EXPLANATION ← NEW E-5 Roles and the team model EXPLANATION ← 6 D-* Decision records ADR ← 3, design-era parts of 2 and 8 M-1 Feature log META ← 11 M-2 Release history META ← 8 (shipped half only) ``` **What changes, concretely:** - **`13-User-Guide` splits into H-1…H-5.** It is the best page in the wiki and this is not a demotion — splitting it is what lets each half be re-verified independently instead of annually. - **`3-Approaches` becomes `D-0001: herdr-centric message server`,** status `accepted`, and is then **never edited again**. The AgentAPI/Redis/NATS content stops being "stale" the moment it is correctly framed as a 2026-07-11 decision record. Same for the design-era half of `2-Message-Server` → `D-0002`, and the `bridged`→`fleetd` rename → `D-0003`. - **`8-Roadmap` splits**: shipped history → `M-2` (frozen), future plans → **Gitea issues and milestones, not the wiki.** A roadmap in a wiki is a page that is wrong by default. - **`11-Features` (2203 lines) splits**: the capability list is reference, the rationale is explanation. Its CLAUDE.md block must stay byte-identical with the repo copy — that constraint moves with it. - **The four `R-*` pages are generated, not written.** ### The anti-rot mechanism — the part that matters most Structure alone will not stop this recurring. The concrete proposal: **1. Generate the reference pages from source.** This is feasible today with no new dependency. The MCP tools are already declared as `McpSchema.Tool` values built by `sendTool()`, `replyTool()` … `whoamiTool()` (`FleetMcp.java:282-292`), so a small emitter can walk them and render name + description + JSON schema. Same shape for routes (`FleetApp.java:115-131`), metrics (`FleetMetrics.java`) and config keys (`fleetd.example.yaml`). **2. Make it a golden-file test, not a build step.** Regenerate into a committed file and fail the build when it differs — the idiom this repo already uses heavily, and it inverts the incentive: after this, **CB-632 could not have been merged without updating the docs**, because the rename would have broken the build. That is the whole fix in one sentence. **3. Run the audit grep from the ticket body in CI**, scoped to the non-generated pages, allowing tokens inside `D-*` records (where old names are *correct*, because a decision record describes the world at its date). **4. Adopt the "freeze vs. auto-update" distinction explicitly.** `D-*` and `M-2` are frozen — old names there are correct and must not be swept. Everything else is live and must match `main`. Marking this per-page is what stops the next audit from "fixing" history. ### Migration order Diátaxis explicitly recommends against a big-bang restructure — *"identify one small improvement, implement it, repeat."* Suggested order, each step shippable alone: 1. **`R-1`…`R-4` generated + golden test.** Highest leverage: kills the largest category of drift permanently and makes ~200 of the 265 stale tokens unreachable. 2. **`D-0001`–`D-0003`.** Cheap — mostly relabelling existing pages — and immediately resolves the `Home.md` contradiction plus most of the AgentAPI/Redis/NATS noise, without rewriting the prose. 3. **Split `13-User-Guide` into `H-1`…`H-5`**, re-verifying each against `main` as it moves. 4. **`H-7` (fleet-manager) and `E-4` (trust boundary)** — the two genuine coverage gaps. 5. **`E-*` prose sweep**, last, because by then only genuine explanation text remains. 6. **`Home` + `_Sidebar` rewritten as routers**, once the destinations exist. ### One cost to accept deliberately Renaming pages breaks every inbound link — from `README.md`, `CLAUDE.md`, prior issues and commit messages. Two options: keep the old page as a one-line redirect stub (the pattern `4-Setup` already uses, which works), or accept the breakage and fix the repo's own links in the same PR. **Recommend redirect stubs for `Home`, `13-User-Guide` and `11-Features`** (the three with real external inbound traffic) and clean renames for the rest. ### Sources - [Diátaxis](https://diataxis.fr/) · [Start here](https://diataxis.fr/start-here/) - [arc42 §9 — Architecture Decisions](https://docs.arc42.org/section-9/) · [Tip 9-5: document decisions as ADRs](https://docs.arc42.org/tips/9-5/) - [ADR examples and templates (Nygard format)](https://github.com/architecture-decision-record/architecture-decision-record) - [Canonical on adopting Diátaxis](https://ubuntu.com/blog/diataxis-a-new-foundation-for-canonical-documentation) - [Sequin — fixing docs with Diátaxis](https://blog.sequinstream.com/we-fixed-our-documentation-with-the-diataxis-framework/) - [Fern — generated vs. manual documentation](https://buildwithfern.com/post/generated-vs-manual-documentation-which-approach)
Owner

Audit done and merged — docs/wiki-audit.md (PR #193)

All 15 pages have a verdict with quoted lines and file:line evidence for every claim.

Verdict Pages
REBUILD 1 Architecture · 2 Message Server · 6 Team · 7 Use Cases · 8 Roadmap · 9 Implementation
REVISE Home · _Sidebar · 3 Approaches · 10 Cross-Host · 11 Features · 12 Claude-to-OpenCode · 13 User Guide
RETIRE 4 Setup · 5 Operations — both are redirect-only stubs that say their own procedure was never written
KEEP none

I spot-checked the evidence rather than taking it on trust

Everything I sampled held up:

  • fleet_read is not a registered tool. The full set is fleet_ack, ask, list, poll,
    profiles, reply, send, spawn, status, stop, whoami. Chapters 1 and 2 both document it.
  • There is no GET /events route. FleetApp.build() registers 15 routes and none is /events.
    Chapters 1 and 2 both document an SSE stream that does not exist.
  • fleet_send's real parameters are sessionId, content, timeoutMs, wait, turnId,
    coordId. Chapter 6 teaches {role, prompt} and chapter 7 teaches {to, kind, body, block}.
    Neither would work.
  • fleet_whoami also returns architect, which chapter 11 omits.
  • Chapter 11's own index cites mcp/BridgeMcp and config/FleetdConfig. Neither resolves.

The one wrong finding turned out to be my bug, not the auditor's

The audit reported memberHerdrSocket as entirely undocumented. That is wrong — the section is at
11-Features.md:2174. But checking it showed the real gap: it has no row in chapter 11's index
table
, and that table is how the page is meant to be read. I added that section on 2026-08-31 and
forgot the row.

Fixed in the wiki (b24965c), and the audit file corrected on merge (2d55b0b) to state the
distinction rather than quietly deleting the finding. "Undocumented" and "documented but unindexed"
are different jobs and should not be collapsed.

Honest coverage

The auditor reported checking 11 pages claim-by-claim (Home, Sidebar, 1, 2, 4, 5, 6, 7, 9, 11, 13)
and skimming the four long historical pages (3, 8, 10, 12) before checking the specific claims that
set their verdicts. Worth weighing when acting on those four.

What I would do next, and why not now

The obvious follow-up is to rebuild chapters 1, 2 and 9 first — they are the ones an agent reads to
learn the system, so their errors propagate into work. But 6 REBUILDs is more rewriting than is
worth committing to before the current code settles
: #185, #189 and #192 are all in flight and two
of them change what chapters 11 and 13 must say. Rewriting now means rewriting twice.

Leaving this issue open with the audit merged as its work list.

## Audit done and merged — `docs/wiki-audit.md` (PR #193) All 15 pages have a verdict with quoted lines and `file:line` evidence for every claim. | Verdict | Pages | |---|---| | **REBUILD** | 1 Architecture · 2 Message Server · 6 Team · 7 Use Cases · 8 Roadmap · 9 Implementation | | **REVISE** | Home · _Sidebar · 3 Approaches · 10 Cross-Host · 11 Features · 12 Claude-to-OpenCode · 13 User Guide | | **RETIRE** | 4 Setup · 5 Operations — both are redirect-only stubs that say their own procedure was never written | | **KEEP** | none | ### I spot-checked the evidence rather than taking it on trust Everything I sampled held up: - **`fleet_read` is not a registered tool.** The full set is `fleet_ack`, `ask`, `list`, `poll`, `profiles`, `reply`, `send`, `spawn`, `status`, `stop`, `whoami`. Chapters 1 and 2 both document it. - **There is no `GET /events` route.** `FleetApp.build()` registers 15 routes and none is `/events`. Chapters 1 and 2 both document an SSE stream that does not exist. - **`fleet_send`'s real parameters** are `sessionId`, `content`, `timeoutMs`, `wait`, `turnId`, `coordId`. Chapter 6 teaches `{role, prompt}` and chapter 7 teaches `{to, kind, body, block}`. Neither would work. - **`fleet_whoami` also returns `architect`**, which chapter 11 omits. - **Chapter 11's own index** cites `mcp/BridgeMcp` and `config/FleetdConfig`. Neither resolves. ### The one wrong finding turned out to be my bug, not the auditor's The audit reported `memberHerdrSocket` as entirely undocumented. That is wrong — the section is at `11-Features.md:2174`. But checking it showed the real gap: **it has no row in chapter 11's index table**, and that table is how the page is meant to be read. I added that section on 2026-08-31 and forgot the row. Fixed in the wiki (`b24965c`), and the audit file corrected on merge (`2d55b0b`) to state the distinction rather than quietly deleting the finding. "Undocumented" and "documented but unindexed" are different jobs and should not be collapsed. ### Honest coverage The auditor reported checking 11 pages claim-by-claim (Home, Sidebar, 1, 2, 4, 5, 6, 7, 9, 11, 13) and skimming the four long historical pages (3, 8, 10, 12) before checking the specific claims that set their verdicts. Worth weighing when acting on those four. ### What I would do next, and why not now The obvious follow-up is to rebuild chapters 1, 2 and 9 first — they are the ones an agent reads to learn the system, so their errors propagate into work. **But 6 REBUILDs is more rewriting than is worth committing to before the current code settles**: #185, #189 and #192 are all in flight and two of them change what chapters 11 and 13 must say. Rewriting now means rewriting twice. Leaving this issue open with the audit merged as its work list.
Owner

Pages 4 and 5: keeping them, not retiring them — the audit was wrong here

The audit marked 4-Setup.md and 5-Operations.md RETIRE, describing them as redirect-only stubs. I checked both before acting, and that is not what they are.

5-Operations.md carries real content that exists nowhere else:

  • a "what actually shipped, against what this page predicted" table — five predictions against what is true now, including that recycle() never existed, that per-session authorization did ship, and that the broker is optional rather than required;
  • a guardrails section: never busy-poll a member's pane, keep the port off public interfaces, and give members a minimal write:repository forge token rather than the admin one.

Deleting the page would throw that away. A correction record is worth keeping precisely because someone will otherwise re-derive the wrong version.

4-Setup.md is shorter, but it still carries the subscription-boundary rule and an explicit list of what had gone wrong on it — a decommissioned model host, port 8080, herdr protocol 14, a systemd unit that does not exist here, and Redis Streams / NATS that were never built. That list is useful: it tells a reader which specific wrong facts used to be published.

Also, four pages link to them. Retiring them would break those links or force edits across the wiki for no gain.

Decision: both stay as superseded pages that point at 13 User Guide. They already carry a ⚫ status banner naming the section that replaced them. _Sidebar.md marks both as superseded, and 1-Architecture.md's related-pages section now sends a reader to chapter 13 for the procedure instead of to these two.

This is recorded rather than quietly done, because "retire" and "keep as a redirect with its corrections intact" are different outcomes and the difference matters to anyone reading the audit later.

## Pages 4 and 5: keeping them, not retiring them — the audit was wrong here The audit marked `4-Setup.md` and `5-Operations.md` **RETIRE**, describing them as redirect-only stubs. I checked both before acting, and that is not what they are. **`5-Operations.md`** carries real content that exists nowhere else: - a "what actually shipped, against what this page predicted" table — five predictions against what is true now, including that `recycle()` never existed, that per-session authorization did ship, and that the broker is optional rather than required; - a guardrails section: never busy-poll a member's pane, keep the port off public interfaces, and give members a minimal `write:repository` forge token rather than the admin one. Deleting the page would throw that away. A correction record is worth keeping precisely because someone will otherwise re-derive the wrong version. **`4-Setup.md`** is shorter, but it still carries the subscription-boundary rule and an explicit list of what had gone wrong on it — a decommissioned model host, port 8080, herdr protocol 14, a systemd unit that does not exist here, and Redis Streams / NATS that were never built. That list is useful: it tells a reader which specific wrong facts used to be published. **Also, four pages link to them.** Retiring them would break those links or force edits across the wiki for no gain. **Decision: both stay as superseded pages that point at [13 User Guide](https://git.ltms.dev/fleet/fleetd/wiki/13-User-Guide).** They already carry a ⚫ status banner naming the section that replaced them. `_Sidebar.md` marks both as superseded, and `1-Architecture.md`'s related-pages section now sends a reader to chapter 13 for the procedure instead of to these two. This is recorded rather than quietly done, because "retire" and "keep as a redirect with its corrections intact" are different outcomes and the difference matters to anyone reading the audit later.
Owner

Done — all 15 pages handled

Every page the audit listed has been rewritten, revised, or explicitly kept, and all of it is pushed to the wiki.

Wiki commit Pages
798d3a8 11 Features
48c8a1e 10 Cross-Host Messaging
06cceee 1 Architecture · 2 Message Server · 7 Use Cases · 8 Roadmap · 9 Implementation
e9c4f96 Home · _Sidebar · 3 Approaches · 12 Claude→OpenCode
426f5a2 6 Team
7962e69 13 User Guide

Pages 4 and 5 are kept as superseded pages — reasoning in the comment above.

The claims that were removed, and are now gone from every page

Three false claims were spread across several pages, which is why fixing one page at a time would not have worked:

  • A fleet_read tool. It has never existed. The registered set is 11 tools (FleetMcp.java:301-327).
  • An SSE GET /events route. No such route is registered. FleetApp.build() (FleetApp.java:143-158) is the complete list, and the pages now say so explicitly so the claim cannot come back.
  • AgentAPI as a "swappable fallback injector". It was never built. A case-insensitive search for agentapi under fleetd/src/main/java returns nothing, and both Profile.kind values run through HerdrPeerLauncher. It is kept on 3-Approaches as discarded research, never in the present tense.

Also removed: ccs profiles and commands, fleet_send parameters that were never shipped (role, prompt, to, kind, body, block), Redis Streams and NATS JetStream as the queue, and every hardcoded backend hostname — the guard's allowlist is a config value that defaults to empty, so no page names one.

Two things worth recording for the next audit

1. Reviewer voice leaked onto the pages. My shared brief asked each writer to say what it had verified, and three pages came back saying "I checked this in the code" and "I did not verify X in this pass" on the page itself. A reference page states the fact and cites the line; who read what belongs in the report. I stripped about 25 of these by hand and added a rule to the shared brief. Worth writing into the brief from the start next time.

2. Home.md carried a release number, a ticket count and a test total. Those were accurate when written and stale within two weeks, and by then they read as current facts. The page no longer carries any of them; 8-Roadmap holds the delivery record instead, and it deliberately drops exact test counts for the same reason.

One correction to the audit itself

The audit's own coverage note says it checked 11 pages claim-by-claim and skimmed four. The skim is where the pages-4-and-5 error came from — both were called redirect-only stubs, and neither is. Every verdict on a skimmed page is worth re-reading before acting on it.

Closing this. mmdc rendered every diagram on every page before each push.

## Done — all 15 pages handled Every page the audit listed has been rewritten, revised, or explicitly kept, and all of it is pushed to the wiki. | Wiki commit | Pages | |---|---| | `798d3a8` | 11 Features | | `48c8a1e` | 10 Cross-Host Messaging | | `06cceee` | 1 Architecture · 2 Message Server · 7 Use Cases · 8 Roadmap · 9 Implementation | | `e9c4f96` | Home · _Sidebar · 3 Approaches · 12 Claude→OpenCode | | `426f5a2` | 6 Team | | `7962e69` | 13 User Guide | Pages 4 and 5 are kept as superseded pages — reasoning in the comment above. ### The claims that were removed, and are now gone from every page Three false claims were spread across several pages, which is why fixing one page at a time would not have worked: - **A `fleet_read` tool.** It has never existed. The registered set is 11 tools (`FleetMcp.java:301-327`). - **An SSE `GET /events` route.** No such route is registered. `FleetApp.build()` (`FleetApp.java:143-158`) is the complete list, and the pages now say so explicitly so the claim cannot come back. - **AgentAPI as a "swappable fallback injector".** It was never built. A case-insensitive search for `agentapi` under `fleetd/src/main/java` returns nothing, and both `Profile.kind` values run through `HerdrPeerLauncher`. It is kept on 3-Approaches as discarded research, never in the present tense. Also removed: `ccs` profiles and commands, `fleet_send` parameters that were never shipped (`role`, `prompt`, `to`, `kind`, `body`, `block`), Redis Streams and NATS JetStream as the queue, and every hardcoded backend hostname — the guard's allowlist is a config value that defaults to empty, so no page names one. ### Two things worth recording for the next audit **1. Reviewer voice leaked onto the pages.** My shared brief asked each writer to say what it had verified, and three pages came back saying *"I checked this in the code"* and *"I did not verify X in this pass"* on the page itself. A reference page states the fact and cites the line; who read what belongs in the report. I stripped about 25 of these by hand and added a rule to the shared brief. Worth writing into the brief from the start next time. **2. `Home.md` carried a release number, a ticket count and a test total.** Those were accurate when written and stale within two weeks, and by then they read as current facts. The page no longer carries any of them; 8-Roadmap holds the delivery record instead, and it deliberately drops exact test counts for the same reason. ### One correction to the audit itself The audit's own coverage note says it checked 11 pages claim-by-claim and skimmed four. The skim is where the pages-4-and-5 error came from — both were called redirect-only stubs, and neither is. Every verdict on a skimmed page is worth re-reading before acting on it. Closing this. `mmdc` rendered every diagram on every page before each push.
ltms closed this issue 2026-08-31 05:41:03 +02:00
ltms reopened this issue 2026-08-31 05:41:13 +02:00
Owner

§B is done too — correcting my earlier close

I closed this an hour ago against §A and §C only, and reopened it straight away: §B asks for three pages that did not exist, and acceptance criterion 3 names two of them explicitly. That was my error, not a scope decision. All three now exist.

Wiki commit What
4912b7a 14 Fleet Manager · 15 REST API Reference · 16 Security & Trust Boundary — new, linked from Home and _Sidebar
cd3a12f Home diagram: events.subscribe was never built

The three new pages

14 Fleet Manager. fleet-manager had zero coverage, so an operator had no way to learn it exists. Written from its own source — the fleets.json shape taken from the parser rather than the example file, and the probe's real progress test, which compares worktree modification times twice four seconds apart and reports stalled when nothing changed. It also carries the two limits that come from fleetd rather than from the tool: two daemons sharing one herdr session tear down each other's members, and a session inside a pane is resolved as a worker, which is why the manager sits outside a pane and speaks REST.

15 REST API Reference. All 14 routes in one table with the Authz.Action each handler checks, plus per-route bodies taken from the handlers. It leads with the fact that makes the page necessary: MCP and REST are siblings over one shared MessageService, so REST behaviour cannot be inferred from the MCP contract. fleet_ack and fleet_whoami have no route at all.

16 Security & Trust Boundary. The guard, the role table, the member credential scrub and token scope, collected. The limits are stated rather than glossed — see below.

Two things found while writing these

1. A live inconsistency: GET /members returns its rows under a workers key (FleetApp.java:322). The route was renamed /workers → /members in CB-557 and the body key was left behind. A caller that reads body["members"] gets an empty list and sees an idle fleet — not an error. fleet-manager reads body["workers"] and is correct (fleet_manager/probe.py:134). Documented on page 15; not changed, because changing it would break fleet-manager. Worth its own ticket if anyone wants the names to agree.

2. The security page had to state four limits, not three. A page that overstates protection is worse than no page, so it records: the effective allow-list is a union and therefore a strict superset of what an operator writes under allow:; the ZDOTDIR scrub is zsh-only; blocking SSH_AUTH_SOCK does not stop a member reaching a passphrase-free key file on disk; and argv is world-readable, which bypasses every environment control on the page. fleetd itself is clean there — it hands a member's environment to herdr as its own field — but nothing stops another program on the host leaking through its own argv.

Acceptance criteria

  1. ✅ Every §A page read against the source.
  2. ✅ Protected names intact — BRIDGED_MEMBER and bridged.yaml still present. bridged.jar is legitimately gone: the artifact really was renamed to fleetd.jar in CB-634, so that entry on the protect-list is itself out of date.
  3. ✅ Pages 14 and 15 exist and are linked from Home and _Sidebar — 16 as well.
  4. ✅ §C decision recorded, both on this issue and in the two pages' own status banners.
  5. ✅ Historical sections say so: 8-Roadmap separates "tried and dropped" from what is live, and 3-Approaches labels AgentAPI research-only.
  6. ✅ The sweep in criterion 6 returns one hit — the deliberate note about the workers key above.

Closing.

## §B is done too — correcting my earlier close I closed this an hour ago against §A and §C only, and reopened it straight away: **§B asks for three pages that did not exist, and acceptance criterion 3 names two of them explicitly.** That was my error, not a scope decision. All three now exist. | Wiki commit | What | |---|---| | `4912b7a` | **14 Fleet Manager · 15 REST API Reference · 16 Security & Trust Boundary** — new, linked from `Home` and `_Sidebar` | | `cd3a12f` | Home diagram: `events.subscribe` was never built | ### The three new pages **14 Fleet Manager.** `fleet-manager` had zero coverage, so an operator had no way to learn it exists. Written from its own source — the `fleets.json` shape taken from the parser rather than the example file, and the probe's real progress test, which compares worktree modification times twice four seconds apart and reports `stalled` when nothing changed. It also carries the two limits that come from `fleetd` rather than from the tool: two daemons sharing one herdr session tear down each other's members, and a session inside a pane is resolved as a **worker**, which is why the manager sits outside a pane and speaks REST. **15 REST API Reference.** All 14 routes in one table with the `Authz.Action` each handler checks, plus per-route bodies taken from the handlers. It leads with the fact that makes the page necessary: MCP and REST are **siblings over one shared `MessageService`**, so REST behaviour cannot be inferred from the MCP contract. `fleet_ack` and `fleet_whoami` have no route at all. **16 Security & Trust Boundary.** The guard, the role table, the member credential scrub and token scope, collected. The limits are stated rather than glossed — see below. ### Two things found while writing these **1. A live inconsistency: `GET /members` returns its rows under a `workers` key** (`FleetApp.java:322`). The route was renamed `/workers` → `/members` in CB-557 and the body key was left behind. A caller that reads `body["members"]` gets an empty list and sees an idle fleet — not an error. `fleet-manager` reads `body["workers"]` and is correct (`fleet_manager/probe.py:134`). Documented on page 15; **not** changed, because changing it would break `fleet-manager`. Worth its own ticket if anyone wants the names to agree. **2. The security page had to state four limits, not three.** A page that overstates protection is worse than no page, so it records: the effective allow-list is a **union** and therefore a strict superset of what an operator writes under `allow:`; the `ZDOTDIR` scrub is **zsh-only**; blocking `SSH_AUTH_SOCK` does not stop a member reaching a passphrase-free key **file** on disk; and **`argv` is world-readable**, which bypasses every environment control on the page. `fleetd` itself is clean there — it hands a member's environment to herdr as its own field — but nothing stops another program on the host leaking through its own argv. ### Acceptance criteria 1. ✅ Every §A page read against the source. 2. ✅ Protected names intact — `BRIDGED_MEMBER` and `bridged.yaml` still present. `bridged.jar` is legitimately gone: the artifact really was renamed to `fleetd.jar` in CB-634, so that entry on the protect-list is itself out of date. 3. ✅ Pages 14 and 15 exist and are linked from `Home` and `_Sidebar` — 16 as well. 4. ✅ §C decision recorded, both on this issue and in the two pages' own status banners. 5. ✅ Historical sections say so: 8-Roadmap separates "tried and dropped" from what is live, and 3-Approaches labels AgentAPI research-only. 6. ✅ The sweep in criterion 6 returns one hit — the deliberate note about the `workers` key above. Closing.
ltms closed this issue 2026-08-31 05:50:02 +02:00
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: fleet/fleetd#168