[v0.1/CLI Review] frontend への --config 転送 / 拒否の欠落は 1.0 で凍結すべき #136
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#136
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?
背景
felis --config <PATH> frontend <name> ...が黙って無視される。crates/felis-cli/src/main.rsのCmd::Frontend腕はglobal_passthroughを呼ばず、global_carrierのみ拒否する。結果:felis --config /tmp/work.toml frontend tui→felis-tuiはデフォルトパスを読む。ユーザは「work 用 config で tui を開いた」と信じるが実際は反映されない。felis --host devbox frontend ...は「拒否」されるが、--configは拒否も転送もされない中途半端。attach/ barefelisはglobal_passthroughで--config/--host/--socket/--ssh-argを正規に転送する。frontendだけが例外で、しかもcli_sessions::reject_global_carrierの拒否対象外になっている。これは
reference/cli.md「Global options」「Alternate frontends」で「--configは window launch /config/doctorのみが読む」「frontend は自前の flag を自分で dial する」とある記述とも不整合:felis frontendは window launch ではないが、ユーザ視点ではfelis -- --cmdと同じ「window を開く」操作として--configを期待する。問い
1.0 で凍結する前にどちらで統一するか:
frontendでも--configを転送する —attach/ bare と同様にglobal_passthroughに含め、frontend側で再パースさせる。--host/--socket/--ssh-argは「frontend が自前で持つならそちら、なければ拒否」の現行を維持するが、--configだけは felis 側で解決してから渡す(既にresolve_config_sourceで絶対パス化している)。frontendで--configを拒否する —attachと同じく window launch として扱わず、frontend <name>は完全に外部プログラムとして「felisは何も転送しない」と明記し、--configはfelis-<name> --configの形で書かせる。案Aがユーザの期待に近い(
felis --config X -- htopと同じ書き方でfelis --config X frontend tuiも動く)。案Bは「felisは薄いラッパ」という原則に忠実だが、既存の bare/attachが転送する以上、非対称が残る。いずれにせよ 1.0 で「どの global flag がどの Cmd で転送/拒否/無視か」を表で凍結する必要がある。
提案
crates/felis-cli/src/main.rsのCmd::Frontend腕でglobal_passthroughと同様に--configを受け取り、exec_frontendに--config <abs>として渡す。--host/--socket/--ssh-argは現行どおり拒否のまま。Cmd::Frontendの入口でconfig.is_some()をreject_global_carrierと同等の framing で拒否し、reference/cli.md「Alternate frontends」に「--configはfelis frontend <name> --configで指定」と追記。reference/cli.md「Global options」表とreference/control-surfaces.md「Placement」に「転送/拒否/無視マトリクス」として固定し、cli_sessions::reject_global_carrierとverb_reading_no_configの分岐テストに golden 化。判定基準
felis --config <PATH> --help/felis --config <PATH> frontend --help/felis attach --helpの help が、どの位置で--configが効くかを推測可能にすること。felis --config /nonexistent frontend tuiが 1.0 の契約どおり exit 2 で失敗するか、または明示的に拒否されるか、どちらかに一意に決まること(黙ってデフォルトを読むのは不可)。just testの CLI パーステストがfrontendの global flag 組み合わせを網羅していること。対象ファイル
crates/felis-cli/src/main.rs(global_passthrough,verb_reading_no_config,Cmd::Frontend腕)crates/felis-client/src/main.rs/crates/felis-client-core/src/config.rs(ConfigSource解決)docs/reference/cli.md「Global options」「Alternate frontends」docs/reference/control-surfaces.mdParent: #12 および #11 / #3
Triage (2026-09-05)
Verdict: accept, P1. Recommend option B (reject). Verified in
crates/felis-cli/src/main.rsCmd::Frontend:--configis neither forwarded nor refused. The carrier refusal already records the reason forwarding is wrong (felisdoes not knowfelis-<name>'s flags, so it would guess a spelling), and--confighas the same problem: a third-party frontend need not accept that flag. Option A would trade a silent ignore for a possible exec failure with a foreign usage error. Reject with the same framing as the carrier refusal, then freeze the forward/refuse/ignore matrix for every global flag ×Cmdinreference/cli.mdandreference/control-surfaces.md, with a parser test per cell. 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).felis --config … frontend <name>: refuse (already true), freeze the matrixClaim check
The premise is stale. Since
f2083767(2026-09-04, the--configlaunchoption from #27),
verb_reading_no_configincrates/felis-cli/src/main.rs:661-697lists
Cmd::Frontend, andmain.rs:412-423exits2(usage) with"--config selects the config.toml a window launch,
felis config, orfelis doctorreads; this verb reads none" before any resolution. Sofelis --config /tmp/work.toml frontend tuiis refused, not ignored:option B is already in effect, with the same reasoning as the carrier
refusal (
main.rs:535-537: felis does not knowfelis-<name>'s flagspelling). The verdict comment ("neither forwarded nor refused") was
verified against a tree before
f2083767.What is still missing:
docs/reference/cli.md:292-298"Alternate frontends" names only thecarrier flags as refused;
--configis covered only by the genericsentence at
:16-20. No table states, per verb, which global flag isforwarded, refused, or read in-process.
crates/felis-cli/src/tests.rs:620-640pins the refusal per verb namebut not the whole matrix (the forwarded set for bare/
attachlives inglobal_passthrough,main.rs:702-720, tested separately).Verdict
accept, narrowed to docs + one matrix test, plus three small refusals.
The frontend case itself needs no code; the matrix sweep turns up three
forms that still drop a global silently (
--version,completions,__mangen), and those become refusals in the same PR.Approach
docs/reference/cli.md"Global options": add a matrix, rows = the fourglobals (
--config,--host,--socket,--ssh-arg), columns = verbgroups: window launch (bare,
attach) → forwarded;frontend→ refused(both
--configand carrier);config→--configread in-process,carrier refused;
doctorits own column →--configread in-process,carrier used (
main.rs:453-461:--hostmakes the daemon rowreport the remote daemon);
window retarget→ all four refused(
main.rs:412-423,581-590); headless verbs →--configrefused, carrier used;__complete-sessionsgets its owncells:
--configrefused,--socketused,--host/--ssh-arg→no candidates, exit 0 (
cli_completions.rs:10-24, the recordedno-SSH-on-TAB decision). Three rows are behavior changes, all of the
same kind (a flag silently dropped):
felis --version(
main.rs:371-387) runs before any validation and ignores all fourglobals;
completionsand__mangenignore the carrier flags. Maintainerdecision (2026-09-05): all three refuse —
--versionwith theArgumentConflictmessage italready uses for a trailing verb, the two verbs through
reject_global_carrier."Alternate frontends": add the
--configsentence ("write it after thename in the frontend's own spelling").
docs/reference/control-surfaces.md"Placement": one line pointing atthe matrix (no duplicate table).
crates/felis-cli/src/tests.rsthatwalks every
Cmdvariant plus the two non-Cmdforms (bare launch,cmd = None; top-level--version) × global flag and assertsforwarded / refused / used / in-process, so a new verb without a row
fails to compile or fails the test.
Dependencies / risk / labels
None. S. Keep
priority/P1,release/v0.1.0(the reference tablefreezes).
CHANGELOG.mdfor the three new refusals. Parent #55.