Skip to content

Settings: Context pane splits Claude/SSH context out of Text Processing - #223

Open
T0mSIlver wants to merge 9 commits into
settings-row-idiomfrom
settings-context-pane
Open

Settings: Context pane splits Claude/SSH context out of Text Processing#223
T0mSIlver wants to merge 9 commits into
settings-row-idiomfrom
settings-context-pane

Conversation

@T0mSIlver

@T0mSIlver T0mSIlver commented Aug 4, 2026

Copy link
Copy Markdown
Owner

Stacked on #201 (settings-row-idiom) — base is that branch, not main. Merge #201 first.

What

Text Processing's "Polishing" group had grown into three unrelated things: the transcript-formatting toggles it is named for, seven consent-grade context toggles whose help text is the consent, and the whole Claude Code plugin + remote-SSH enrollment UI. This splits the last two out into a Context pane of its own.

New SettingsTab case, raw value context (existing raw values untouched — the scripts key off them). Sidebar tile terminal.fill on systemIndigo; subtitle "What the polisher and Claude Code integration may see."

Moved from Text Processing → Context, with identical bindings, help text and behavior:

Context group Rows
Polish context Repo vocabulary from terminal · Use Claude Code terminal screen as polish context · Use Claude Code project files as polish context · Use clipboard as polish context · Send polish context to non-local endpoints
Claude Code Local Claude title fallback · Claude Code plugin (this Mac)
Remote hosts Remote Claude Code over SSH (sheet + alert wiring + onAppear refresh intact)

The three groups are static — a toggle switches a group's content, never the number or identity of the groups (owner rule, 2026-07-04).

Gating moves with the rows it gated: the Polish context group carries the same SettingsAvailabilityCard ("No Overlay Buffer shortcut") and the same .disabled(!isLLMPolishingReachable).opacity(...) treatment. The plugin and remote-host rows stay always enabled, with the existing comment explaining why — revoking a host is the security off switch for an already-bound listener and cannot depend on the current hotkey configuration.

Text Processing keeps: Replacements; Polishing reduced to Enable / Agent prompt profile in terminals / Spoken clipboard paste (still carded and gated as before); Configuration unchanged.

Nothing about what the app collects or sends changes — this is presentation and consent legibility only.

Contracts updated in the same PR

The raw value is a literal in two scripts, so all three move together:

  • Tests/localvoxtralTests/SettingsTabTests.swiftcontext added to the frozen raw-value set (existing pins untouched), plus a new test spelling out settings.tab.context / settings.pane.context.
  • scripts/ui-smoke.sh — drills the pane by AX id and asserts, scoped to settings.pane.context, both the group heading ("Polish context") and "Remote Claude Code over SSH", which exists on no other pane.
  • scripts/capture-readme-assets.shTAB_NAMES/TAB_IDS/TAB_FILES gain "Context" / context / settings-context.png.
  • README.md — settings screenshot table gains the Context row.

Proof

  • Unit suite green — ./scripts/remote-build.sh (build + full suite)
Test Suite 'localvoxtralPackageTests.xctest' passed at 2026-08-04 20:43:09.475.
	 Executed 2022 tests, with 2 tests skipped and 0 failures (0 unexpected) in 114.306 (114.450) seconds
Test Suite 'Selected tests' passed at 2026-08-04 20:43:09.475.
	 Executed 2022 tests, with 2 tests skipped and 0 failures (0 unexpected) in 114.306 (114.452) seconds
  • The contract test that demonstrates the new pane — ./scripts/remote-build.sh test --filter SettingsTabTests
Test Case '-[localvoxtralTests.SettingsTabTests testAccessibilityIdentifiersUseTheDrillScheme]' passed (0.001 seconds).
Test Case '-[localvoxtralTests.SettingsTabTests testContextTabUsesTheDrillIdentifiersTheScriptsHardcode]' passed (0.000 seconds).
Test Case '-[localvoxtralTests.SettingsTabTests testEveryTabHasCompleteChrome]' passed (0.000 seconds).
Test Case '-[localvoxtralTests.SettingsTabTests testRawValuesAreStable]' passed (0.000 seconds).
Test Case '-[localvoxtralTests.SettingsTabTests testSidebarArraysCoverEveryTabExactlyOnce]' passed (0.000 seconds).
Test Case '-[localvoxtralTests.SettingsTabTests testSidebarArraysDoNotOverlap]' passed (0.000 seconds).
Test Case '-[localvoxtralTests.SettingsTabTests testSubtitlesAreOneLineSentences]' passed (0.000 seconds).
Test Suite 'SettingsTabTests' passed at 2026-08-04 20:43:30.817.
	 Executed 7 tests, with 0 failures (0 unexpected) in 0.002 (0.003) seconds

testRawValuesAreStable (existing, unweakened) is what fails on any raw-value drift; testSidebarArraysCoverEveryTabExactlyOnce is what fails if the new tab were declared but never reachable in the sidebar; the new testContextTabUsesTheDrillIdentifiersTheScriptsHardcode pins the two literals the drills press and scope by. No test was weakened, no assertion removed, no skip added; the only warnings in the build are the pre-existing ones in ClaudePluginInstallService.swift and ClaudeHookPublisherTests.swift.

  • UI change — hand verification on the Mac is PENDING. Verified so far only by build + unit suite + the AX contract tests; the tier-2 ui-smoke.sh drill and eyes-on-pane checks (sidebar tile/order, the availability card gating the Polish context group, the enrollment sheet still opening from its new group) have not been run against a packaged build in this PR. Pane screenshots come from the capture-assets workflow (capture-assets.yml / scripts/capture-readme-assets.sh), not from this branch — assets/settings-context.png is referenced by the README but not yet generated. The orchestrator will attach screenshots and the hand-test result.

LLM lanes: not run and not required — no prompt, model pin, sampling, request-shape, or context-attachment path is touched. This is Settings presentation plus two AX drill scripts; the bindings the toggles write are byte-identical.


Update — review round 1 (codex, 2026-08-04)

An independent codex review of the diff found no behavior drift in the move (bindings, consent copy, gating, sheet/alert/onAppear wiring all verified) and two minors, both fixed in 7eac743:

  1. README referenced assets/settings-context.png before it existed → the capture-assets workflow was dispatched on this branch (run 30941718903) and the generated screenshot is now committed. Preview: Context pane
  2. The script-contract test never inspected the scriptstestContextTabUsesTheDrillIdentifiersTheScriptsHardcode only repeated the Swift-side identifier scheme, so a divergent literal in ui-smoke.sh/capture-readme-assets.sh kept tests green while the AX drills broke at runtime. Replaced by testAutomationScriptsDrillExactlyTheTabsTheEnumDefines, which reads both scripts and compares their drilled tab ids against the enum. Red/green proof:

Red (with assert_tab "context" seeded to assert_tab "kontext" in ui-smoke.sh):

error: -[localvoxtralTests.SettingsTabTests testAutomationScriptsDrillExactlyTheTabsTheEnumDefines] : XCTAssertEqual failed: ("["kontext", "endpoints", "context", "general", "about", "textProcessing", "dictation"]") is not equal to ("["about", "context", "endpoints", "dictation", "textProcessing", "general"]") - ui-smoke.sh must drill exactly the tabs the enum defines

Green (real scripts): Executed 7 tests, with 0 failures (SettingsTabTests, 2026-08-04 21:07).

Update — review round 2 (opencode final review, 2026-08-04)

The pane split itself was verified clean (bindings, gating, consent copy byte-identical, AX derivation, Swift 6 isolation). Findings, all addressed in a2bcba4:

  • Major — stale navigation copy: five user-facing paths still said Settings → Text Processing … for rows that now live on Context (README install one-liner + pane list, and three paths in integrations/claude-code/README.md, a file the PR had not touched). All now point at Settings → Context → …, and the README pane list gains a Context bullet.
  • Minor — parallel-array coverage: the script-contract test now also pins TAB_NAMES/TAB_IDS/TAB_FILES lockstep (previously a missing sibling entry only failed at README-regen time under set -u).
  • Minor — parser fragility: the one-line-array parser keeps failing loud on a reformat, now with an actionable message.
  • Two nits (duplicated availability card by design; if let around the Remote hosts group) judged intentional and left, with rationale in code comments.

SettingsTabTests after both rounds: Executed 7 tests, with 0 failures.

Text Processing's Polishing group had grown to seven consent-grade context
toggles plus the Claude Code plugin row plus the whole remote-SSH enrollment
UI, under a heading that promised transcript formatting. The toggles whose
help text IS the consent — what may be read from your terminal, your repo,
your clipboard, and where it may be sent — were being scrolled past as if
they were siblings of "Exact match".

They move to a Context pane of their own (raw value `context`, sidebar tile
terminal.fill on systemIndigo), in three static groups: Polish context (the
four sources plus the non-local-endpoint relaxation), Claude Code (title
fallback + plugin install), Remote hosts (SSH enrollment). Same bindings,
same help text, same behavior — nothing here changes what the app sends.

The availability gating moves with the rows it gated: the Polish context
group carries the same "No Overlay Buffer shortcut" card and the same
disabled/opacity treatment, because context is only ever harvested for an
Overlay Buffer dictation. The plugin and remote-host rows stay ALWAYS
enabled, for the reason they always were — revoking a host is the security
off switch for an already-bound listener, and it must work whatever the
hotkey configuration is.

Text Processing keeps Replacements, a Polishing group reduced to the three
rows that really are about the transcript (Enable, agent prompt profile,
spoken clipboard paste), and Configuration.

Contracts updated in step, since the raw value is a literal in two scripts:
SettingsTabTests pins `context` and its settings.tab/settings.pane ids,
ui-smoke.sh drills the pane and asserts content unique to it, and
capture-readme-assets.sh captures assets/settings-context.png for the README
table.
…ontract test read the scripts

The README referenced assets/settings-context.png before it existed; the
capture-assets run on this branch generated it, so it ships with the PR.

The script-contract test asserted only the Swift-side identifier scheme, so
a divergent literal in ui-smoke.sh or capture-readme-assets.sh kept every
test green while the AX drills broke at runtime. It now reads both scripts
from the repo and compares their drilled tab ids against the enum.
… new pane

The opencode pass found the real gap was documentation, not code: five
user-facing paths still sent people to Settings -> Text Processing for rows
that now live on Context — the README install one-liner, the pane feature
list (which also gains a Context bullet), and three paths in the
integration README that nothing in the move had touched.

Also pins the capture script's TAB_NAMES/TAB_IDS/TAB_FILES lockstep (the
loop indexes them under set -u, so a missing sibling entry previously only
failed at README-regen time on the Mac) and gives the one-line-array parser
an actionable failure message.
# Conflicts:
#	Sources/localvoxtral/SettingsView.swift
#	scripts/capture-readme-assets.sh
@T0mSIlver

Copy link
Copy Markdown
Owner Author

Merged the updated #201 (settings-row-idiom, which now carries #199 and main's 21 commits — the remote-context campaign #216#221).

Conflicts (2 files)

  • SettingsView.swift: both hunks were the parent still holding the rows this PR moved out of Text Processing. Took this branch's side (rows stay on the Context pane), then re-placed the parent's new content by hand — see below.
  • scripts/capture-readme-assets.sh: this branch added the fifth (context) entry to the three tab arrays; Settings: hand-rolled sidebar chrome in place of the TabView #199's later commit added the arity check that they stay index-aligned. Kept both — 5 entries and the check.

Where main's new Claude/remote UI landed — Context pane, three groups unchanged:

  • Claude Code: the cmuxSurfaceJoinEnabled toggle ("Join Claude Code sessions in cmux") next to "Local Claude title fallback" — it is a join arm, not a polish-context source, and like the title fallback it is deliberately outside the Overlay-Buffer availability gate. ClaudeCmuxPasswordSettingsRow directly under it, since its help text says to enter the password "below", and above ClaudePluginSettingsRow.
  • Remote hosts: everything the persistent-forward and plugin-update work added rides inside ClaudeRemoteHostsSettingsRow and therefore lands here with no edit — per-host "Keep the tunnel open" toggle + status + Retry, "Update Plugin…" + its confirmation panel, the rejection hint, the model-rendered relative statusText, and the enrollment sheet's "Update later" section / no-alias copy-only path.
  • Polish context: main's rewritten help sentence on "Use Claude Code project files as polish context" ("…a supported terminal, or a Remote Control session in the focused browser tab…").
  • Nothing new went back into Text Processing; About's new dogfood "Build" row stays on About.

Proof: ./scripts/remote-build.sh — build clean, Executed 2594 tests, with 2 tests skipped and 0 failures. SettingsTabTests all 7 pass, including testAutomationScriptsDrillExactlyTheTabsTheEnumDefines, which parses both scripts/ui-smoke.sh (8 assert_tab calls covering all five raw values) and scripts/capture-readme-assets.sh (TAB_IDS/TAB_NAMES/TAB_FILES all 5, index-aligned). Pushed as 59e32cc.

…e main merge surfaced

Main's cmux additions were written against the old Text Processing layout,
so the merge brought two more Settings paths pointing at rows that now live
on Context. And the terminal-screen row's help still claimed Ghostty only —
stale on main itself since the allowlist grew to iTerm2, Terminal.app, and
cmux; the row lives here now, so the copy gets corrected here.
The coverage tests compare Sets, so an accidental reorder passed every
test while moving rows users have muscle memory for. Pinned here at the
stack top, where the final five-pane order lives.
… and the row-idiom polish since the first capture
@T0mSIlver

Copy link
Copy Markdown
Owner Author

Final scoped review (opencode/GLM-5.2) of everything since the first full review (merge from main, copy fixes, row-idiom merge-up, order pin): clean — no resolution damage. Verified: all 13 of main's Polishing-group rows accounted for exactly once across the three Context groups; exactly the five consent toggles inside the availability gate, both join arms and the remote plumbing outside it; no stale navigation path remains anywhere; footer-slot usage consistent; order-pin test byte-identical to the sidebar arrays. One low-severity copy nuance adopted in the follow-up commit: the terminal-screen row now cross-references the cmux join it depends on.

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