docs: name the Point-diagnostic verb class #163

Merged
natsukium merged 2 commits from docs/point-diagnostic-145 into main 2026-09-06 14:27:23 +09:00
Owner

Fixes #145.

Two changes, one contract: the exit code a caller sees is a function of error.kind, and every wire refusal reaches that kind through one table.

  • cli: map every wire refusal through one ErrorKind tablefrom_attach_failure and from_refusal join from_stream_reason as the whole wire-to-kind surface, replacing the split decisions in cli_sessions, the bridge, conn.rs and cli_bridge. The kinds are declared through a macro that emits the enum, the roster, the tokens and the exit map together, and a golden fixture (crates/felis-cli/tests/golden/error_kinds.txt) is rendered from those maps plus exit_code. at_capacity_detail widens to refusal_detail so the dial sites can reach the reason, not just the capacity detail.
  • docs: name the Point-diagnostic verb classconfig check, config show-effective and doctor read exit 1 as "here are the diagnostics you asked for", which is a different answer from sessions list's 1. They get their own row in the classification and exit-code tables instead of a paragraph after the fact. daemon status gains the sentence saying worker_threads is runtime identity, not a resource row.

Doc cascade

  • docs/reference/cli.md: Point-diagnostic row in the verb-classification and exit-code tables; the bridge's pipe-failure exception stated where the rule is; the daemon status shape note.
  • docs/explanation/architecture/control-surfaces.md: the argument for the new class.
  • skills/felis/SKILL.md: the scripting example follows the reference's exit table.
  • tests/cli_exit_table.rs: a workspace guard checks the reference's two kind lists against the golden the CLI renders, so the frozen table is derived rather than hand-synced.

Verified: just check green (fmt, clippy, nextest, deny, proto-compat); reviewed by pi luna + pi sol; docs proofread by Gemini gemini-3.8-flash-high

Deferred

  • No CHANGELOG.md entry — no user-visible contract change: same kinds, same exit codes, same JSON.
  • ErrorKind::ALL is #[cfg(test)] and hand-listed — a kind missing from it is caught by the count assertion in every_kind_is_listed_once.
Fixes #145. Two changes, one contract: the exit code a caller sees is a function of `error.kind`, and every wire refusal reaches that kind through one table. - **`cli: map every wire refusal through one ErrorKind table`** — `from_attach_failure` and `from_refusal` join `from_stream_reason` as the whole wire-to-kind surface, replacing the split decisions in `cli_sessions`, the bridge, `conn.rs` and `cli_bridge`. The kinds are declared through a macro that emits the enum, the roster, the tokens and the exit map together, and a golden fixture (`crates/felis-cli/tests/golden/error_kinds.txt`) is rendered from those maps plus `exit_code`. `at_capacity_detail` widens to `refusal_detail` so the dial sites can reach the reason, not just the capacity detail. - **`docs: name the Point-diagnostic verb class`** — `config check`, `config show-effective` and `doctor` read exit `1` as "here are the diagnostics you asked for", which is a different answer from `sessions list`'s `1`. They get their own row in the classification and exit-code tables instead of a paragraph after the fact. `daemon status` gains the sentence saying `worker_threads` is runtime identity, not a resource row. ## Doc cascade - `docs/reference/cli.md`: Point-diagnostic row in the verb-classification and exit-code tables; the bridge's pipe-failure exception stated where the rule is; the `daemon status` shape note. - `docs/explanation/architecture/control-surfaces.md`: the argument for the new class. - `skills/felis/SKILL.md`: the scripting example follows the reference's exit table. - `tests/cli_exit_table.rs`: a workspace guard checks the reference's two kind lists against the golden the CLI renders, so the frozen table is derived rather than hand-synced. Verified: just check green (fmt, clippy, nextest, deny, proto-compat); reviewed by pi luna + pi sol; docs proofread by Gemini gemini-3.8-flash-high ## Deferred - No `CHANGELOG.md` entry — no user-visible contract change: same kinds, same exit codes, same JSON. - `ErrorKind::ALL` is `#[cfg(test)]` and hand-listed — a kind missing from it is caught by the count assertion in `every_kind_is_listed_once`.
The kind a caller branches on was decided at three sites: the spawn
refusal in cli_sessions, the same two-way split duplicated inline in the
bridge, and the dial paths in conn.rs and cli_bridge. Three sites means
the same wire reason could exit 1 on one verb and 2 on another, which is
exactly what the exit contract promises cannot happen.

from_attach_failure and from_refusal join from_stream_reason as the
whole wire-to-kind surface, and a golden fixture rendered from those
maps plus exit_code pins the table the reference documents.

The kinds are declared through a macro that emits the enum, the roster
the fixture renders, the tokens, and the exit map together: a
hand-written roster beside the enum would let a new kind compile with an
exit code and still be missing from the frozen table. The wire rosters
the fixture walks are linked through exhaustive successor matches for
the same reason — those enums live in felis-protocol and have no
derived iteration.

Reaching a RefusalReason at the dial sites needs the reason, not just
the capacity detail, so at_capacity_detail widens to refusal_detail;
ConnectError::at_capacity stays for the callers that only ask whether
the daemon is full.

Refs #145
docs: name the Point-diagnostic verb class
Some checks failed
darwin / build felis (aarch64-darwin) (pull_request) Successful in 2m3s
fuzz / cargo fuzz smoke (per target) (pull_request) Successful in 1m22s
pr / cargo build / clippy / test / deny (pull_request) Successful in 2m18s
pr / wire schema is compatible with the base (pull_request) Successful in 8s
windows / frontend smoke (Windows) (pull_request) Successful in 2m52s
windows / package felis (x86_64-pc-windows-msvc) (pull_request) Has been skipped
pr / frontend smoke (x86_64-linux) (pull_request) Successful in 3m49s
pr / publish felis (x86_64-linux) (pull_request) Has been skipped
bench / Criterion full-suite snapshot (pull_request) Has been skipped
fuzz / cargo fuzz nightly long-run (pull_request) Has been skipped
bench / Criterion regression gate (pull_request) Failing after 2m7s
pr / nix flake check (pull_request) Successful in 1m21s
windows / cargo nextest (Windows) (pull_request) Successful in 6m35s
windows / cargo clippy (Windows cross) (pull_request) Successful in 14s
darwin / build felis (aarch64-darwin) (push) Successful in 13s
fuzz / cargo fuzz smoke (per target) (push) Successful in 1m57s
fuzz / cargo fuzz nightly long-run (push) Has been skipped
pr / nix flake check (push) Successful in 10s
pr / cargo build / clippy / test / deny (push) Failing after 1m36s
pr / wire schema is compatible with the base (push) Successful in 11s
pr / frontend smoke (x86_64-linux) (push) Successful in 7s
windows / cargo clippy (Windows cross) (push) Successful in 25s
pr / publish felis (x86_64-linux) (push) Has been skipped
windows / cargo nextest (Windows) (push) Successful in 8m21s
windows / frontend smoke (Windows) (push) Successful in 1m39s
windows / package felis (x86_64-pc-windows-msvc) (push) Successful in 2m15s
46bb9d8ef2
config check, config show-effective and doctor read exit 1 as "here are
the diagnostics you asked for": the document has errors, or a check
reported fail. The classification table put them in the plain Point row
and left the difference to a paragraph after the exit-code table, so a
reader who matched sessions list's 1 (no_match) against config check's
read the same code as the same answer.

They get their own row in both tables, and the exit-code table carries
the meaning in its body. Only config check and doctor are exceptions to
the code being a function of error.kind: show-effective still refuses
with invalid_request, because the defaults it would otherwise print are
not the effective config. The bridge's override of its own pipe-failure
code stays an exception too, now stated where the rule is rather than
only under felis bridge. A workspace guard checks the reference's two
kind lists against the golden the CLI renders from ErrorKind::exit_code,
so the frozen table is derived rather than hand-synced.

daemon status gains the sentence the proto comment already carried:
worker_threads is runtime identity, not a resource row.

Refs #145
natsukium deleted branch docs/point-diagnostic-145 2026-09-06 14:27:24 +09:00
Sign in to join this conversation.
No description provided.