Skip to content

docs(config): reconcile CONFIGURATION.md with the schema, and test that it stays reconciled - #73

Merged
mizu-jun merged 1 commit into
masterfrom
docs/configuration-inventory
Aug 21, 2026
Merged

docs(config): reconcile CONFIGURATION.md with the schema, and test that it stays reconciled#73
mizu-jun merged 1 commit into
masterfrom
docs/configuration-inventory

Conversation

@mizu-jun

Copy link
Copy Markdown
Owner

What

Config has 36 fields. docs/CONFIGURATION.md covered 13, mentioned one in passing, and documented ten keys that have never existed in the code. Since the TOML parser does not reject unknown keys, all ten parsed silently and did nothing — the document read as though they worked.

This closes the "CONFIGURATION.md inventory PR" item in docs/plans/ui-ux-modernization-v3.md.

Documented but fictional

Doc said Reality
[terminal] table: alt_screen_buffer, dec_mode_47_1047_1049, osc_window_title, osc_notifications, cjk_width, ime_support No such table. Replaced with a list of these behaviours stated as unconditional, which is what they are
log_template, placeholders {session}/{date}/{time} file_name_template, placeholders {session}/{pane}/{datetime}
binary binary_log
local_forwards (table array with local_port/remote_host/remote_port) forward_local — an array of "<local>:<host>:<remote>" strings. Same shape for forward_remote
socks5_proxy No such key
[[serial]] [[serial_ports]] — and its keys were never documented at all; the section described the command-palette action instead

Also newly documented on [[hosts]]: group and tags, which existed but were missing.

max_log_size — the key was fiction, but so was the behaviour

The document promised automatic rotation at 100 MB. The rotation machinery does exist in pane.rs, but the config-driven path (start_recording_with_configstart_recording_with_options) passes a limit of 0, which disables it.

A log started from nexterm.toml grows without bound. That is now stated plainly, along with the fact that wiring a size limit through to the config is outstanding work. Worth its own issue — this PR only stops the document from promising something that does not happen.

Newly documented (21 sections/keys)

Top-level scalars (api_version, language, leader_key, cursor_style, auto_check_update, colors_follow_system, colors_light, colors_dark, active_profile, plugin_dir, plugins_disabled), plus [cursor], [ui], [animations], [scrolling], [gpu], [quake_mode], [security], [hooks], [[profiles]], [inactive_pane_hsb], [[serial_ports]].

Details worth calling out, because each is a trap for anyone writing a config:

  • [gpu] custom shaders — the vertex layouts, and the fact that the fragment output must be premultiplied alpha. A shader written for straight alpha looks wrong wherever it is not fully opaque.
  • [quake_mode] — the global hotkey cannot work on Wayland by spec; use nexterm-ctl quake toggle from the compositor instead.
  • [security]plugin_read defaults to deny, not prompt, and prompt is treated as deny because there is no synchronous prompt path for a server-side plugin call.
  • [inactive_pane_hsb]hue is accepted and ignored (a real hue shift needs a shader pass).

Why it drifted, and what now prevents it

Nothing compared the document to the schema. Three tests in the new nexterm-config/tests/doc_matches_schema.rs do:

  1. The complete example must parse as Config, with spot-checks on the renamed keys.
  2. Every top-level key in that example must be a real Config field — the known-key set comes from serializing Config::default(), not a hard-coded list, so a field added to Config needs no test change. This is the check that catches a [terminal].
  3. The ten phantom keys are named explicitly, so copying an old revision back in fails with a file and line number. Prose inside block quotes may still mention them (the document explains why they were removed).

Test plan

  • cargo fmt --check
  • cargo clippy --all-targets -- -D warnings — clean through every crate
  • cargo test --workspace — all pass, 0 failures
  • Both regression tests verified by reintroducing the defect they target: injecting [terminal] into the example fails test 3 with docs/CONFIGURATION.md:221 documents \alt_screen_buffer``; injecting an unknown table fails test 2. Neither passes vacuously
  • Bidirectional coverage checked mechanically: every Config field now appears in the doc, and every key documented in a table exists in the code

🤖 Generated with Claude Code

…at it stays reconciled

`Config` has 36 fields. The document covered 13 of them, mentioned one in
passing, and described ten keys that **have never existed in the code**.
Because the TOML parser does not reject unknown keys, every one of those
ten parsed without complaint and did nothing, so the document read as
though they worked.

Documented but fictional, now removed or corrected:

- The whole `[terminal]` table — `alt_screen_buffer`,
  `dec_mode_47_1047_1049`, `osc_window_title`, `osc_notifications`,
  `cjk_width`, `ime_support`. Replaced with a list of the behaviours,
  stated as unconditional, since that is what they are.
- `log_template` → the field is `file_name_template`, and its
  placeholders are `{session}` / `{pane}` / `{datetime}`, not
  `{session}` / `{date}` / `{time}`.
- `binary` → `binary_log`.
- `local_forwards` as a table array with `local_port` / `remote_host` /
  `remote_port` → `forward_local`, an array of `"<local>:<host>:<remote>"`
  strings. Same for `forward_remote`.
- `socks5_proxy` → no such key.
- `[[serial]]` → the table is `[[serial_ports]]`, and its keys (`name`,
  `port`, `baud_rate`, `data_bits`, `stop_bits`, `parity`) were never
  documented at all; that section described the command-palette action
  instead.

`max_log_size` deserves its own note, because removing the key is not the
whole story. The document promised automatic rotation at 100 MB. The
rotation machinery does exist in `pane.rs`, but
`start_recording_with_config` reaches it through
`start_recording_with_options`, which passes a limit of `0` —
rotation off. **A log started from `nexterm.toml` grows without bound**,
which is now stated plainly, together with the fact that wiring a limit
through is outstanding work.

Newly documented (21 sections/keys): the top-level scalars
(`api_version`, `language`, `leader_key`, `cursor_style`,
`auto_check_update`, `colors_follow_system`, `colors_light`,
`colors_dark`, `active_profile`, `plugin_dir`, `plugins_disabled`),
`[cursor]`, `[ui]`, `[animations]`, `[scrolling]`, `[gpu]` (including the
custom-shader vertex layouts and the premultiplied-alpha requirement),
`[quake_mode]` (including the Wayland limitation), `[security]` (noting
that `plugin_read` defaults to `deny` and that `prompt` is treated as
`deny`), `[hooks]`, `[[profiles]]`, `[inactive_pane_hsb]` (noting that
`hue` is accepted and ignored), and `[[serial_ports]]`.

The reason this drifted so far is that nothing compared the two. Three
tests in `nexterm-config/tests/doc_matches_schema.rs` now do:

- the complete example must parse as `Config`, with spot-checks on keys
  that were renamed;
- every top-level key in that example must be a real `Config` field,
  derived from serializing `Config::default()` rather than a hard-coded
  list — this is the check that catches a `[terminal]`;
- the ten phantom keys are named, so copying an old revision back in
  fails with a file and line number.

Both regression tests were verified by reintroducing the defect they
target and confirming they fail.

A note at the top of the reference now warns that unknown keys are
ignored silently, so a reader who finds a setting doing nothing knows to
suspect the spelling first.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>
@github-actions

Copy link
Copy Markdown

Coverage report


Generated by cargo llvm-cov (workspace minus nexterm-client-gpu and nexterm-i18n).

@mizu-jun
mizu-jun merged commit dbf6a30 into master Aug 21, 2026
12 checks passed
@mizu-jun
mizu-jun deleted the docs/configuration-inventory branch August 21, 2026 14:11
mizu-jun added a commit that referenced this pull request Aug 28, 2026
Three accuracy fixes to the phase-tracking steering document:

- Add the missing P3b1 entry (shipped via #79, squash 5d6e167,
  merged to master): the shared SurfaceMotion timer pair and
  open/close motion for eleven overlay surfaces, including the
  redacted password-modal ghost.
- Fix P3b2, which claimed "shipped via #80" while #80 is still
  open. A checklist that overstates what is on master is worse
  than one that lags behind -- it's exactly the failure mode the
  CONFIGURATION.md reconciliation (#73) exists to prevent. P3b2a
  is pending review in #80, P3b2b in #81; the item is unchecked
  since neither half has merged.
- Replace the dangling "this branch" reference with #81, matching
  every other entry's PR-number provenance convention.

No code changes.
mizu-jun added a commit that referenced this pull request Aug 29, 2026
…/UX v3 P3b2b) (#82)

* docs(plan): P3b2b implementation plan for the tab bar and window buttons

Records two traps found by measuring, neither of which is in the design:
the tab bar's is_hovered also gates whether the tear-out and close buttons
are drawn (a behavioural use that must keep the boolean, since a button
drawn at weight 0.05 is still clickable), and hovered_window_button has a
second write site in the Windows snap-layout event handler.

Generated with [Claude Code](https://claude.ai/code)
via [Happy](https://happy.engineering)

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Happy <yesreply@happy.engineering>

* feat(client): cross-fade the tab bar's hover tint

* test(client): remove decorative tab-hover gate test

a_tab_transition_that_is_never_retargeted_stays_quiet could not fail:
it only exercised HoverTransition::default(), already covered by
a_fully_idle_state_wants_no_animation_frames, and never called
retarget, so it did not exercise the config gate in mouse.rs even by
proxy. A test that cannot fail but carries the name of a requirement
is worse than no test - it creates the appearance of coverage.

The tab_bar.hover_highlight gate is verified by code inspection only.
Covering it properly needs an EventHandler test harness this crate
does not have, which is out of scope for P3b2b.

* feat(client): cross-fade the window buttons' hover fill and glyph

* docs(client): record the hover-model rule, and resolve HoverTransition::target

target() has no production caller across all four hover models, so gate it
behind #[cfg(test)] instead of #[allow(dead_code)] -- following
AnimationManager::tick_by_dt's precedent -- rather than deleting it and
losing the retarget-moved-the-target assertion the weight checks alone
cannot express. Also closes out P3b2 in the plan doc and adds the
hover-model rule to nexterm-client-gpu/CLAUDE.md.

* docs(plan): correct P3b provenance in ui-ux-modernization-v3

Three accuracy fixes to the phase-tracking steering document:

- Add the missing P3b1 entry (shipped via #79, squash 5d6e167,
  merged to master): the shared SurfaceMotion timer pair and
  open/close motion for eleven overlay surfaces, including the
  redacted password-modal ghost.
- Fix P3b2, which claimed "shipped via #80" while #80 is still
  open. A checklist that overstates what is on master is worse
  than one that lags behind -- it's exactly the failure mode the
  CONFIGURATION.md reconciliation (#73) exists to prevent. P3b2a
  is pending review in #80, P3b2b in #81; the item is unchecked
  since neither half has merged.
- Replace the dangling "this branch" reference with #81, matching
  every other entry's PR-number provenance convention.

No code changes.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Happy <yesreply@happy.engineering>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant