[Post-v0.1/P2] Choose the scrollback capacity control surface #36
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#36
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-grid::DEFAULT_SCROLLBACK_ROWS = 10_000が全セッションの上限として compiled-in で固定されている(crates/felis-grid/src/lib.rs:241,docs/explanation/data-model/scrollback.md「Capacity and eviction」,docs/reference/config.md「Not configurable today」)。Grid自体はwith_scrollback(rows, cols, cap)で per-session 可変であり、cap=0(alternate / mirror)の経路も既存。問題は設定の置き場が決まっていないこと。関連:
docs/explanation/architecture/control-surfaces.md「Diagnostic verbs」: daemon は config file を読まず caps は compiled-in、報告のみ(daemon statusで観測)。1つ目の tunable は正当だが 2つ目で config 導入を再検討するという Revisit trigger が明記。config.tomlは client-only(felis-client-coreが読む)、daemon は読まないという control surface 分離。docs/reference/config.md「Not configurable today」行: scrollback depth は意図的に未公開。要望
daemon のスクロールバック上限をユーザが変更できること。少なくともグローバルデフォルト、できれば per-session override。
論点 — 設定をどこに持つか
control-surfaces.mdの5面(Daemon CLI / Client CLI / config file / keybind / env / wire)のどこに置くかが本 issue の主論点。候補とトレードオフ:A. クライアント
config.toml(例:[scrollback] rows = 20000)config check/ JSON Schema の恩恵をそのまま受けられる。--host越しで client と daemon host が異なる場合、どちらの値が正か曖昧。daemon statusのlimit報告との整合も必要。control-surfaces.mdの「daemon は TOML を読まない」原則と衝突はしないが、値を daemon へ伝える経路(SpawnArgs/ 新 IPC)が別途必要。B. daemon 起動時 env var(例:
FELIS_SCROLLBACK_ROWS=20000 felis-daemon serve)FELIS_TERM/FELIS_TERM_PROGRAMと同型で daemon が TOML を読まずに済む。#10 で代替案として挙がったFELIS_DAEMON_*系と整合。C. daemon 専用 config file(例:
daemon.toml)MAX_SESSIONS等)をまとめて tunable にできる。--configとの関係を新規に設計する必要。D.
sessions spawnの per-session 引数(例:felis sessions spawn --scrollback-rows 50000/SpawnArgs.scrollback_rows)daemon statusへの反映が必要。いずれにせよ
Gridのcapを可変にする配管は既にあるため、実装自体は小さい。決定すべきは control surface の選択と、既存セッションへの適用可否(再起動後のみ / 新規セッションのみ / 既存の ring 縮小・拡大を許すか)。提案する進め方
--host越しの曖昧さを理由に一旦見送りも選択肢)。docs/explanation/architecture/control-surfaces.md/docs/reference/config.md/docs/explanation/data-model/scrollback.md/docs/reference/spec.md(REQ 追加があれば)/CHANGELOG.mdを更新。felis daemon statusにscrollback_rowsの limit/used 相当を載せるか(#10/#26 の status 報告の流儀に合わせる)も同時に決める。受け入れ条件(案)
control-surfaces.mdに記録され、採用しなかった代替と Revisit 条件が明記されているFELIS_SCROLLBACK_ROWS=1 felis-daemon serve→ 新規セッションが1行で eviction する、またはspawn --scrollback-rowsが反映される)daemon status(または同等の観測面)で有効な上限が確認できるdocs/reference/config.md「Not configurable today」の記述が更新されているcapacity変更が既存セッションに与える影響(新規のみ / 縮小時は即時切り捨て / 拡大時は次回 push から)が仕様化されている備考
DEFAULT_SCROLLBACK_ROWSの変更はcargo testのscrollback_tests/table_gc/refsnapshot を更新するだけで済む程度に局所的。cc @natsukium
daemonのスクロールバック上限を可変にする / 設定の置き場を決めるto [Post-v0.1/P2] Choose the scrollback capacity control surfaceTriage plan (2026-09-03)
Source-grounded triage against
mainat69076d42, reviewed through seven rounds of an independent reviewer (pisol/luna) until it passed with no findings. The dependency order that supersedes the tracker's is posted on #12.Claim check
Accurate, with one line-number slip and one gap in the option analysis.
pub const DEFAULT_SCROLLBACK_ROWS: usize = 10_000;is atcrates/felis-grid/src/lib.rs:242(issue says 241).Grid::new→with_scrollback(rows, cols, DEFAULT_SCROLLBACK_ROWS)at:834-851;scrollback_capacity()at:2861. The daemon's only production construction site iscrates/felis-daemon/src/pool.rs:86(Grid::new(rows, cols)), so the plumbing really is one call, as the issue says. Capacity 0 for mirrors/alternate screen is documented atdocs/explanation/data-model/scrollback.md:715-723.docs/reference/config.md:673-678"Not configurable today" — confirmed.docs/reference/spec.md:156REQ-605 fixes the default at 10 000 (a user-set capacity does not contradict it).scrollback.md:750-756records why a larger default is rejected (per-session residency × session count), andscrollback.md:987-990"Future revisits" already lists "per-session caps with a global memory ceiling across sessions".docs/explanation/architecture/control-surfaces.md:180-190— confirmed: limits are compiled in, "the daemon reads no configuration file at all", and the Revisit trigger is "if a second knob wants the same treatment: one compiled constant with a report is honest, three would be a config file denied". The first knob isMAX_SESSIONS = 256(crates/felis-daemon/src/pool.rs:46, reported viaDaemonCaps.max_sessionsatserve.rs:147,163,971).FELIS_TERM/FELIS_TERM_PROGRAMfrom its env (crates/felis-daemon/src/lib.rs:246-247;config.md:680-686).SpawnArgs(crates/felis-protocol/proto/felis.proto:500-515) already carries client-decided, spawn-time, daemon-owned parameters —cwd,env,dims, tags — and the CLI already exposes them (felis sessions spawn --cwd/--env/--rows/--cols/--tag,crates/felis-cli/src/cli_sessions.rs:282-307), including the local-vs-remote resolution the issue worries about for--host(resolve_spawn_cwd :2167). Scrollback rows is the same kind of value asdims.daemon statusalready has a per-session limit scope:LimitScope::LIMIT_SCOPE_SESSION(felis.proto~:1435) and a closedResourceKindenum with reserved slots 6–7 — a scrollback row fits the existing shape without a new taxonomy.Verdict
defer (keep post-v0.1.0, P2), accept-with-changes on the proposed surface: recommend D + A (wire field + CLI flag, with
config.tomlsupplying the client's default), not the issue's minimal "B + D", and no daemon config file (C).Reasoning against B/C and for A+D, in the docs' own terms:
dimsnever does. Option B (daemon env) makes depth a daemon-restart-paced setting, which is exactly the boundary crossing principle 3's test names ("If changing a client config requires a daemon restart, the boundary has been crossed"). Option C fires the control-surfaces Revisit trigger for one number.--hostambiguity the issue raises against A resolves the way--cwd/--envalready resolve: the spawner's request wins, and the remote daemon clamps it to its compiled ceiling. Nothing is ambiguous once the value travels inSpawnArgs.MAX_SCROLLBACK_ROWS, e.g. 1_000_000 per thescrollback.md:987on-disk-overflow revisit) and reports it as aLIMIT_SCOPE_SESSIONrow, so the "second knob" stays a report, not a config file — consistent with control-surfaces.md's argument.Does deferral get more expensive because of the freeze? Slightly, in two known places, both cheap if the v0.1.0 work leaves the door open:
SpawnArgs.scrollback_rowsis an additive minor after the 2.0 baseline (docs/reference/ipc.md:202-205). No cost as long as #20's move of spawn to correlatedOpskeepsSpawnArgsa message that can grow.usedis a daemon-wide sum or max —LIMIT_SCOPE_SESSIONalready says exactly that, so #26 should not remove it.CHANGELOGitem, not a contract break. A config key added later is an unknown key to v0.1.0 builds (theadd-config-keyskill's "older builds reject unknown keys" gotcha) — the normal forward-incompatibility of any new key, and the reason to keep it out of v0.1.0 rather than rush it in.So: settle the decision (A+D) in the docs whenever convenient (it is a paragraph in
control-surfaces.md), implement after the tag.Approach
with_scrollbackexists. Daemon:pool.rs:86takes the requested capacity, clamped toMAX_SCROLLBACK_ROWS(new const besideMAX_SESSIONS,pool.rs:46) — clamp, not refuse, and report the clamp in the create reply or log (decide at implementation; refuse-with-GeometryOutOfRange-style failure is the other option, matching howdimsout of REQ-605a range refuses atfelis.proto:511-512; refusing is more explicit and matches thedimsprecedent, so prefer refuse).extend-ipcskill):SpawnArgs.scrollback_rows: optional uint32(0/absent → daemon default), aResourceKind::SCROLLBACK_ROWSstatus row (used= max over sessions or sum,limit= ceiling,scope= SESSION), minor bump, seeds forfuzz/seeds/ipc_body/.spawn.rs/connector.rsSpawnArgsgains the field;config.rsgains[scrollback] rows(add-config-keyskill: struct,just schema, home-manager module, live-reload table noting it applies to new sessions only).felis sessions spawn --scrollback-rows N(cli_sessions.rs beside--rows/--cols),sessions info --format jsonreports the session's capacity,daemon statusshows the new row. Bridgesessions.spawnparams mirror the flag. Completions/man regenerate.scrollback.md"Capacity and eviction".control-surfaces.md(decision + rejected B/C + Revisit: "if a second daemon-side tunable that is not per-session appears, reconsider a daemon config"),config.md(new key; delete "Not configurable today"),scrollback.md,spec.md(REQ-605 gains "default; per-session override via SpawnArgs, ceiling reported by status"),cli.md,ipc.mdreference,CHANGELOG.md,skills/felis(the flag and the status row).scrollback_rows = 1and asserting eviction after one row (pattern atcrates/felis-daemon/src/serve/tests.rs:1086); a refuse/clamp test above the ceiling; CLI parse tests; config schema snapshot; status golden fixture (per #26's fixture set).Dependencies
--config) settles the config surface the key joins. All are v0.1.0, so this lands after the tag as planned.Risk/effort
M. Grid plumbing S; wire + CLI + config + status row + docs M. Main risk: memory — a user-set 1M rows at 96 cols is ≈1.5 GiB per session (
scrollback.md:726-729gives 15 MiB per 10k), so the compiled ceiling and the status row are not optional, and the value belongs beside the admission limits #14/#15 introduce.Labels
Keep
priority/P2, post-v0.1.0. Recommend recording the A+D decision in the issue now so #20/#26/#30 implementers know what to leave room for.