[v0.1/CLI Review] Point/Stream 例外と ErrorKind 二重定義を 1.0 で整理 #145
Labels
No labels
priority/P0
priority/P1
priority/P2
release/v0.1.0
status/blocked
status/planned
type/bug
type/design
type/test-gap
type/tracker
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
natsukium/felis#145
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
背景
docs/reference/cli.mdの Machine output 節とcrates/felis-cli/src/cli_output.rsのErrorKind::exit_code/from_stream_reasonは 1.0 で frozen するが、現行の CLI に「Point/Stream 例外」と「ErrorKind 二重定義」が残っている。1. Point/Stream 例外の散在
reference/cli.mdは全 verb を Point / Stream / Exempt に三分するが、例外が 3 箇所ある:felis config check/show-effective: Point だが exit1が「document errors」を意味し、他 Point の1(no_match/ambiguous/refused) と意味が違う。cli.mdExit codes 表に「Diagnostic exceptions」として脚注があるのみ。felis doctor: Point だが daemon unreachable を exit2ではなくwarn+ exit1/0にする例外(cli.mdDoctor 節)。felis daemon status: Point だがResourceReportのworker_threadsがresources[]外の単独フィールドで、他 Point の{"v":1, ...}と shape が異なる。いずれも
reference/cli.md分類表では同じ Point に置かれ、例外が表から読めない。2. ErrorKind の二重定義と
exit_codeの重複crates/felis-cli/src/cli_output.rs: ErrorKind(20 variants) とcrates/felis-protocol/src/messages.rs: StreamErrorReason(4 variants) /AttachFailure/RefusalReasonが別オントロジーで、map がErrorKind::from_stream_reasonと各 verb のmatchに散在する:StreamErrorReason::TooManyStreams → AtCapacityはcli_output.rsで一箇所だけ map。AttachFailure::SessionLimitReached → SpawnFaileddowngrade はconvert/session.rsで ledger 行5として処理。RefusalReason::AtCapacity → daemon unreachableの preface レベルの map はconnector.rs。docs/reference/cli.mdExit codes 表はこれらを「Kinds mapping to exit 1/2」として一覧するが、ErrorKind::exit_codeのmatchと手で同期する必要があり、ずれると exit 契約が破れる。skills/felisの scripting 例もこの表を参照する。3.
--formatの verb クラスごとの拒否が clap value_parser に依存PointFormat::parse_point_formatはjsonlを拒否し、StreamFormat::parse_stream_formatはjsonを拒否する。拒否は clap のvalue_parser = fnで行われ、exit2+ human message になるが、reference/cli.mdMachine output 節の「Selecting an incompatible format exits 2」と同じ文言がcli_output.rsの Err 文字列にも重複する。二箇所を同期しないと help と docs がずれる。問い
1.0 で以下を決める:
config check/show-effective/doctorの exit 例外を Point のサブクラス (Point-diagnostic) として分類表に明示するか、現行の脚注のまま frozen にするか。ErrorKindを CLI surface の single source にし、StreamErrorReason/AttachFailure/RefusalReasonとの map をcli_output.rsの一箇所 (from_wire_reason/from_attach_failure) に集約するか。daemon statusのworker_threadsをresources[]に含めるか、単独フィールドのまま docs に「resource row ではない」理由を frozen として残すか。提案
reference/cli.md「Machine output」分類表に「Point-diagnostic」行を追加し、config check/show-effective/doctorをそこに移動。Exit codes 表の「Diagnostic exceptions」脚注を削除し、表本体にconfig check: 1 = document errorsを行として追加。cli_output.rsのPointFormat/StreamFormatは現行の value_parser のまま frozen と明記。ErrorKind::from_wireを新設し、StreamErrorReason/AttachFailure/RefusalReasonからの map を一箇所に集約。reference/cli.mdExit codes 表はこの関数のmatchから生成される golden test (tests/cli_output.rs) で同期を担保。daemon statusのworker_threadsは単独フィールドのまま残すが、reference/cli.mdDaemon status 節に「worker_threadsは resource row ではなく runtime identity」と frozen コメントを追加し、OpsStatusReplyの proto コメントと一致させる。判定基準
reference/cli.md「Classification by verb」表を読んだだけでconfig checkが exit1で document error を意味することが分かり、sessions listの1(no_match) と混同しないこと。ErrorKindから exit1/2への map がcli_output.rsの一箇所で定義され、reference/cli.mdExit codes 表とcargo test -p felis-cli --test cli_outputの golden が同期していること。felis daemon status --format jsonのworker_threadsがresources[]外にあることが docs と proto コメントの両方で同じ理由で説明されていること。対象ファイル
docs/reference/cli.md「Machine output」「Exit codes」「Daemon status」「Doctor」crates/felis-cli/src/cli_output.rs(ErrorKind,from_stream_reason,exit_code)crates/felis-cli/src/cli_sessions.rs/cli_config.rs/cli_daemon.rs(各 verb の ErrorKind 選択)crates/felis-protocol/proto/felis.proto(OpsStatusReply.worker_threadsコメント)tests/(cli_outputgolden,skills/felisの scripting 例)Parent: #12 および #23 / #29 / #55
Triage (2026-09-05)
Verdict: accept with narrowing, P1. The exit-code and classification tables freeze at v0.1.0, so the doc half must land before #29 records the goldens; the code half is a refactor that only matters because it feeds the golden.
Point-diagnosticrow to the classification table forconfig check/show-effective/doctor, and move the "Diagnostic exceptions" footnote into the exit-code table body. No exit code changes.ErrorKind::from_wire(stream reason / attach failure / refusal) incli_output.rs, with a golden test that #29 freezes; the reference table is then derived, not hand-synced.worker_threadsoutsideresources[]and state the reason (runtime identity, not a resource row) in both the reference and the proto comment.Order: before #29. Parent: #55.
Triage plan (2026-09-05)
Source-grounded triage against
mainat07a77ae4, reviewed through six rounds of an independent reviewer (piluna then sol); every finding was verified against the source and folded in, and the design decisions below were settled with the maintainer on 2026-09-05. The order that supersedes the tracker's is posted on #12: this issue lands before #29 (schemas, goldens, and reference tables freeze there).Point-diagnostic class, one wire →
ErrorKindmap,worker_threadsClaim check
docs/reference/cli.md:41-51lists the diagnostic exceptions as proseafter the exit-code table;
:66-73putsconfig check,show-effective,doctorin the plain Point row.cli_output.rs:150-254:ErrorKind(21 variants),exit_code, andfrom_stream_reasonare already the single stream map; the attach mapis
cli_sessions.rs:2322-2333create_refusal, and the prefacerefusal map is
conn.rs:90-104(AtCapacityvsDaemonUnreachable).Three sites, as the issue says.
worker_threads:felis.proto:1607-1611already states "identity, not aresource row";
cli.md:183-204does not.Verdict
accept with narrowing, as triaged. No exit-code change.
Approach
cli.md: add aPoint-diagnosticrow to "Classification by verb"(
config check,config show-effective,doctor) with the meaning of1in the row; move the "Diagnostic exceptions" prose into the tablebody. Bridge's own-pipe exit
1stays a sentence underfelis bridge.cli_output.rs:ErrorKind::from_attach_failureandErrorKind::from_refusalnext tofrom_stream_reason, withcreate_refusal(cli_sessions.rs:2322-2333), the bridge's owninline arm (
cli_bridge.rs:1648-1658, the same two-way splitduplicated), the
conn.rsarm, and the bridge's dial path(
cli_bridge.rs:2877-2895,at_capacity_detail) all calling them. One golden test(
crates/felis-cli/tests/or the existingcli_outputtests) thatrenders the full kind → exit table and the three wire maps as a fixture
#29 will freeze; the reference table is then checked against the
fixture, not hand-synced.
cli.md"Daemon status": one sentence forworker_threadsmirroringthe proto comment.
Dependencies / risk / labels
Before #29. S. Keep labels. Parent #55.