Skip to content

fix(settings): link Settings mentions in prose and correct wrong destinations - #8261

Merged
iamwhatever merged 1 commit into
mainfrom
feat/settings-link-migrations
Sep 5, 2026
Merged

fix(settings): link Settings mentions in prose and correct wrong destinations#8261
iamwhatever merged 1 commit into
mainfrom
feat/settings-link-migrations

Conversation

@CrysisDeu

@CrysisDeu CrysisDeu commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

Summary

The settings-redirect audit found 96 places where the product tells the user to go to Settings; only 21 were clickable and 7 frontend strings named a destination that does not exist. This PR lands the frontend half that needs no new infrastructure: (a) prose naming a real tab becomes a <SettingsLink>, (b) hand-written /settings/... literals go through the shared builder, (c) the 5 wrong-destination strings still on main are corrected in all 13 locale catalogs (the other 2, AWS Control's, were fixed upstream by #8471).

(a) Prose → <SettingsLink> (Trans idiom, <0>…</0> in catalogs)

InstancesViewport error footer → instances: SettingsLink fires onPlainClick and the viewport returns to its Local tab first, the same overlay rule the panel's hand-off button already follows (the link soft-navigates the local SPA underneath the opaque remote overlay). SettingsLink itself is now a guard-aware navigation surface: an unmodified primary click goes through useGuardedLeave (skipped when the target is the current address) and stays put when the page on screen vetoes, so a hand-authored Settings link can no longer unmount a dirty editor without the confirm the sidebar and palette already give; modified clicks are left to the browser. This makes SettingsLink a fourth wired exit on the leave-guard channel, on purpose: it is the one declarative Settings link, so asking there covers every prose link at once instead of per call site (NavigationLeaveGuard.tsx's inventory is updated to say so). The imperative navigate(settingsPath(...)) callers this PR only re-pointed at the builder (update modal and pill, mobile connect, approval-mode picker, chat voice branch) still do not ask — they are modal or menu actions the user just chose, and wiring them one by one is the per-caller model #8010 exists to retire, so they stay with #8010. SttSettings drops the "(Settings → About → Restart gateway)" parenthetical — the restart button is inline beside it.

Five audit sites are deliberately not migrated: OpsMissionControl/SettingsPanel's notifications note sits on a panel that holds unsaved provider secrets and registers no leave guard, so any new exit there discards a half-typed token — the sentence stays plain text (its de/es/fr/it/pt values still carry the English source, as on main — an audit leftover for a follow-up, not this fix); SessionColorPicker is mounted by no production component (dead code — a follow-up should delete it, not decorate it); UpdateFoundModal's update-failed sentence is unreachable (apiFailure guarantees a non-empty ApiError.message), so the pre-PR e.message || i18nT(...) shape stays; OnboardingFlow's "change anytime in Settings → Chat" sits inside a fixed inset-0 overlay whose open state is internal, so a link there would navigate underneath the overlay — and the copy says later, so it stays plain text; VoiceDisabledModal's "Settings → Voice" sentence sits two lines above a primary Open settings button that already makes the same call, so an inline link would duplicate it (the modal is unchanged).

(b) Hand-written literals → settingsPath() / <SettingsLink>

UpdateFoundModal, UpdatePill, MobileConnectModal, ChatPage voice branch (embedded branch untouched), TipCard (TIPS_SETTINGS_PATH deleted; no highlight yet — the Feature Tips toggle has no anchor). The two legacy <Navigate to="/settings/…"> redirects in App.tsx are left as literals on purpose: the feature-map gate reads any rewritten <Route> line as a route swap, and a builder call is not worth a feature-map edit for two redirects that never change.

(c) Copy fixes (en + 12 locales, en-XA regenerated via i18n:pseudo)

  • Mochi mcp_empty / mcp_error_disabled / mcp_error_probe_failed: "Settings → MCP" → Agent Capabilities → Connections — the rail entry is labeled Agent Capabilities (nav.agent_capabilities) and the tab that hosts MCP servers is labeled Connections (CapabilitiesPage.tsx uses connections_label). The catalogs do not re-spell those words: every locale carries {{capabilities}} → {{tab}} and the call sites pass capabilitiesVars('connections') (destinationVars.ts), which reads the same label keys the Capabilities page renders — so a relabel cannot re-create the wrong-destination drift this PR fixes.
  • AWS Control's two "Settings → Deploy" strings were superseded on main by aws-control: empty state points at "Settings -> Deploy", which does not exist #8471 (the empty state now registers profiles in place), so they are out of this PR.
  • md-notebook connectHelp: "in Settings" → Agent Capabilities → Knowledge (capabilitiesVars('knowledge')).
  • projectSkillsTrust.withdraw_hint: "the Skills settings page" → Agent Capabilities → Skills (capabilitiesVars('skills'); the withdraw list renders there, not in Settings).

SettingsLink.children becomes optional: react-i18next's <Trans components={[<SettingsLink … />]}> passes the element self-closing and injects the translated fragment at render time.

No linked issue: follow-up to the settings-redirect audit run in a dashboard session (parent: #8098).

Before / after

Same fixtured surface, same harness (website/scripts/capture-settings-redirects-{a,c}.mjs), run against a base-branch dist and this branch's dist. Each shot asserts the target sentence is visible before capturing.

# Surface Before After
A2 Remote-instance viewport error footer before after
A7 STT prerequisites — redundant route parenthetical removed before after
C1 Mochi — MCP empty state (Settings → MCP ⇒ Agent Capabilities → Connections) before after
C2 Mochi — MCP server disabled error before after
C3 Mochi — MCP probe failed error before after
C6 md-notebook — Connect Vault help (Settings ⇒ Agent Capabilities → Knowledge) before after

Not captured (stated, not faked): C7 ProjectSkillsTrustDialog only opens from a live skill-picker selection.

Testing

  • New settingsLinkMigrations.test.tsx (2): /settings/instances via catalog value + idiom; the three Capabilities sentences render exactly nav.agent_capabilities → <tab label> and carry only placeholders.
  • SettingsLink.test.tsx (+3): a vetoing leave guard prevents the navigation and skips onPlainClick; onPlainClick runs only for an allowed unmodified primary click; a same-address target never asks the guard.
  • Updated pinning test: InstancesViewport.test.tsx (link returns to Local on plain click, not on Cmd/Ctrl click).
  • I18N_BASE_REF=origin/main node scripts/i18n-check.mjs: 19 checks PASS (changed-values, changed-passthrough at zero); every catalog shows exactly 7 modified lines and no new key.
  • tsc -b clean, eslint 0 errors on changed files.

Pattern harvest

Rule candidate: lint
Pattern: a user-facing string that names a Settings tab ("Settings → X", "in Settings") without a <SettingsLink>, a hand-written /settings/ literal outside settingsPath.ts, or a catalog value that spells a rail / tab label (Agent Capabilities →, Capabilities →) instead of interpolating {{capabilities}} → {{tab}} — all three let the 7 wrong-destination strings drift unnoticed, and all three are greppable. The backend half (43 strings with no catalog path) needs a settings_target field convention first and is out of scope here.

@CrysisDeu
CrysisDeu requested a review from a team September 3, 2026 20:16
@CrysisDeu
CrysisDeu requested a review from a team as a code owner September 3, 2026 20:16
@github-actions github-actions Bot added the readiness: checking Automated validation is still running label Sep 3, 2026
@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

GPT 5.6 Review — ✅ human override accepted

Human judgment by @CrysisDeu overrides the GPT 5.6 finding for 0fdc5453aeeb81c66936740997b5eff603314215; the recorded reason is authoritative for this commit.

This comment is updated in place on each push.

The model was not re-run because an authorized human decision supersedes it.

False positive or not applicable? A repository writer can comment:
/ai-review override gpt 0fdc5453aeeb81c66936740997b5eff603314215: <one-sentence reason>

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Design Review (Fable 5) — ✅ PASS

Design-level review of 0fdc5453aeeb81c66936740997b5eff603314215 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All hunks are accounted for by the description, both temp-screenshots/ and capture scripts are established repo conventions, and the guard-wiring of SettingsLink is deliberate, documented in NavigationLeaveGuard.tsx's inventory, and pinned by tests. The one design-level signal: the PR builds destinationVars precisely so catalog values never re-spell rail/tab labels, yet the new instancesViewport catalog value hardcodes <0>Settings → Remote Instances</0> in all 13 locales — the same drift class, mitigated only by the fact that a stale-labeled link still lands correctly.

Design-Verdict: PASS

Guard-aware SettingsLink centralizes the leave-guard ask at the right layer; destination copy now reads live labels, closing the drift class it fixes.

Suggestions

  • The new instancesViewport value spells <0>Settings → Remote Instances</0> literally in 13 catalogs — the drift class destinationVars.ts exists to prevent ("prose that names them must read the same keys instead of re-spelling the words"). A relabel leaves stale text (the link still lands right, so harm is confusion, not a dead end), and it is a built-in exception to the PR's own proposed lint. Interpolating label vars inside the <0>…</0> fragment closes it.

[DESIGN-REVIEWED] 0fdc545

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

First Principles Review (Fable 5) — ✅ PASS

Premise-level review of 0fdc5453aeeb81c66936740997b5eff603314215 — why this exists and whether the shipped surface is the smallest honest version. Updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

All checks are done. The change survives every lens: the copy fixes sit at cause level (labels interpolated from the same keys the Capabilities page renders), the deletions are real, the literal sweep is verifiably complete, and the evidence artifacts follow the repo's own recorded convention.

First-Principles-Verdict: PASS

A fix that lands at cause level — wrong destinations become label interpolations, prose becomes the one shared link, and two things get deleted.

What this change ships

Intent: stop telling users to go to Settings destinations they can't click or that don't exist — a FIX.

  1. Remote-instance error footer's "Settings → Remote Instances" is now clickable and returns to Local first — justified
  2. Every prose Settings link now asks the page's leave guard; modified clicks untouched — declared; derived (new exits must not discard drafts)
  3. "Settings → MCP" / "in Settings" / "Skills settings page" corrected to Agent Capabilities → tab, 13 locales — justified, cause-level ({{capabilities}} → {{tab}} reads the rendering page's own label keys)
  4. STT "(Settings → About → Restart gateway)" parenthetical removed — justified deletion (button is inline)
  5. Update modal/pill, mobile connect, chat voice route through settingsPath() — justified; sweep verified complete (remaining literals: builder itself + 2 declared App.tsx redirects)
  6. TipCard uses SettingsLink; TIPS_SETTINGS_PATH deleted — justified deletion (0 other importers)
  7. SettingsLink.children optional for the <Trans> self-closing idiom — derived (react-i18next platform rule)
  8. onPlainClick hook — one consumer (InstancesViewport), but the minimal seam for the overlay rule; no smaller shape exists in a shared component
  9. Two capture scripts + 12 before/after PNGs — convention-mandated evidence (PR template names temp-screenshots/<feature>/; 422 sibling capture scripts; cleanup workflow prunes)
  10. NavigationLeaveGuard exit inventory updated same-commit — mandated by the docs-in-same-commit rule

Watch

  • CAPABILITIES_TAB_LABEL_KEY (destinationVars.ts) re-states the tab→label-key mapping CapabilitiesPage.tsx:50-65 defines inline (3 keys in each, counted). A value relabel can't drift, but swapping a tab to a different key on the page would — settingsLinkMigrations.test.tsx pins literals, not the page's defs. Having CapabilitiesPage read its three labels through this map would close it; the standalone module itself is correct (Mochi's separate Vite entry can't import the page).

[FIRST-PRINCIPLES-REVIEWED] 0fdc545

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

UX Review (Fable 5) — ✅ PASS

UX-level review of 0fdc5453aeeb81c66936740997b5eff603314215 — updated in place on each push. A BLOCK verdict blocks PR readiness; PASS/CONCERNS are advisory.

UX-Verdict: PASS

Every rewritten pointer now names a destination that exists, and the one new link keeps its promise: it leaves the remote tab first, then navigates, or stays put when a draft is at stake.

Suggestions

  • apps.mochi.settingsPanel.mcp_empty / mcp_error_disabled / mcp_error_probe_failed render as "…in Kiro Crew Agent Capabilities → Connections" (screenshot after/c2-mochi-mcp-disabled.png), which reads as one proper noun; insert the preposition — "in Kiro Crew, under {{capabilities}} → {{tab}}" — so the product name and the rail entry stay separable.

[UX-REVIEWED] 0fdc545

@github-actions

github-actions Bot commented Sep 3, 2026

Copy link
Copy Markdown
Contributor

Opus 4.8 Review — ✅ no blocking findings

Reviewed 0fdc5453aeeb81c66936740997b5eff603314215 — this comment is updated in place on each push.

Review details

No findings.

[OPUS-REVIEWED] 0fdc545

Verdict parsed from the review's SHA-scoped output markers for commit 0fdc5453aeeb81c66936740997b5eff603314215.

False positive or not applicable? A repository writer can comment:
/ai-review override fable 0fdc5453aeeb81c66936740997b5eff603314215: <one-sentence reason>

@CrysisDeu
CrysisDeu force-pushed the feat/settings-link-migrations branch from fa1a9da to 4702193 Compare September 3, 2026 21:21
@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 3, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/settings-link-migrations branch from 4702193 to ebda78c Compare September 3, 2026 23:05
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 3, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/settings-link-migrations branch from ebda78c to 13b7b01 Compare September 4, 2026 01:09
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 4, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/settings-link-migrations branch from 13b7b01 to 47c958d Compare September 4, 2026 02:09
@github-actions github-actions Bot added readiness: checking Automated validation is still running readiness: action required A blocking check or review needs attention and removed readiness: action required A blocking check or review needs attention readiness: checking Automated validation is still running labels Sep 4, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/settings-link-migrations branch from 47c958d to 5946601 Compare September 4, 2026 02:47
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Sep 4, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/settings-link-migrations branch from c06a255 to 74c758f Compare September 4, 2026 18:57
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: passed Eligible automated validation passed for the current revision labels Sep 4, 2026
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt 74c758f: ErrorNotice cannot be used here — Mochi's Settings window is a separate Vite entry (settings.html, bare createRoot) that ships no Tailwind stylesheet (its 20 renderer components use inline styles and hand-named classes only, and its own PanelErrorBoundary hand-rolls role="alert" for that reason), so ErrorNotice's Tailwind-class inline variant would render unstyled; this PR only interpolates the destination label into the existing live-region string and does not add or move the error surface (F1 span=SettingsPanel.tsx:851 / :1205).

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

AI-review override not recorded: keep the reason to 500 characters or fewer.

@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

Status at 74c758f53 (rebased onto main after #8471 superseded the AWS Control copy fixes; those two strings are out of this PR now). All 5 review lanes PASS; the two remaining reds are inherited from main, not from this diff:

I will rebase once after those land and let CI re-run; no change to this branch is planned in the meantime.

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed merge conflict Branch has merge conflicts with its base — author must resolve before merge readiness: checking Automated validation is still running labels Sep 4, 2026
@CrysisDeu
CrysisDeu force-pushed the feat/settings-link-migrations branch from 74c758f to a0cb3db Compare September 4, 2026 22:27
@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Sep 4, 2026
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt a0cb3db: ErrorNotice cannot be used here — Mochi's Settings window is a separate Vite entry (settings.html, bare createRoot) that ships no Tailwind stylesheet (its 20 renderer components use inline styles and hand-named classes only, and its own PanelErrorBoundary hand-rolls role="alert" for that reason), so ErrorNotice's Tailwind-class inline variant would render unstyled; this PR only interpolates the destination label into the existing live-region string and does not add or move the error surface (F1 span=SettingsPanel.tsx:851 / :1205).

@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

AI-review override not recorded: keep the reason to 500 characters or fewer.

@github-actions github-actions Bot added readiness: action required A blocking check or review needs attention and removed readiness: checking Automated validation is still running labels Sep 4, 2026
…inations

An audit of every place the product sends the user to Settings found 96
sites; only 21 were clickable, and 7 frontend strings named a destination
that does not exist. This lands the frontend half that needs no new
infrastructure.

Prose that names a real tab now renders the tab name as a <SettingsLink>
through the react-i18next Trans idiom (<0>...</0> in every catalog): the
remote-instance viewport error footer, which returns to the Local tab
before the link navigates the local SPA underneath the opaque remote
overlay. SettingsLink is a navigation surface, so it now asks the
leave-guard channel (useGuardedLeave) on an unmodified primary click (never for a
same-address target or a modified click) and stays put when the page
vetoes; onPlainClick fires only for a click that is going to navigate.
It is the fourth wired exit on that channel by design -- one declarative
link covering every prose link -- and NavigationLeaveGuard's inventory
says so; the imperative navigate(settingsPath()) callers stay with the
general fix tracked in #8010.
The STT prerequisites paragraph drops its "(Settings -> About -> Restart
gateway)" route since the restart button sits right beside it. Five
audit sites stay as they are: the Ops Mission Control panel holds
unsaved provider secrets behind no leave guard, the session color picker
is mounted nowhere, the update-failed sentence is unreachable, the
onboarding header sits inside an overlay a link would navigate under,
and the voice modal already has a primary "Open settings" button two
lines below the sentence.

Hand-written /settings literals in UpdateFoundModal, UpdatePill,
MobileConnectModal, ChatPage's voice branch and TipCard go through
settingsPath() / <SettingsLink>. App.tsx's two legacy redirects keep
their literals: the feature-map gate reads a rewritten <Route> line as
a route swap, and two never-changing redirects do not earn that edit.

Copy fixes across all 13 catalogs: Mochi's MCP strings and the md-notebook
vault help pointed at "Settings -> MCP" / "Settings" where the real home
is Agent Capabilities -> Connections / Knowledge. Those sentences, and the
project skills trust dialog's withdraw hint, interpolate
{{capabilities}} -> {{tab}} from the rail and tab label keys
(capabilitiesVars) instead of re-spelling the words, so a relabel cannot
turn them into wrong destinations again.

SettingsLink's children become optional because Trans passes the element
self-closing and injects the translated fragment at render time.

Evidence: website/scripts/capture-settings-redirects-{a,c}.mjs shoot the
same fixtured surfaces against a base-branch dist and this branch's dist;
6 before/after pairs are committed under temp-screenshots/settings-redirects/.
@CrysisDeu
CrysisDeu force-pushed the feat/settings-link-migrations branch from a0cb3db to 0fdc545 Compare September 4, 2026 22:55
@CrysisDeu

Copy link
Copy Markdown
Collaborator Author

/ai-review override gpt 0fdc545: ErrorNotice cannot render here: Mochi's Settings window is a separate Vite entry (settings.html, bare createRoot) with no Tailwind stylesheet, so ErrorNotice's Tailwind-class inline variant would be unstyled (Mochi's own PanelErrorBoundary hand-rolls role=alert for the same reason); the flagged span is pre-existing and this PR only interpolates the destination label into its string.

@github-actions github-actions Bot added readiness: checking Automated validation is still running and removed readiness: action required A blocking check or review needs attention labels Sep 4, 2026
@github-actions

github-actions Bot commented Sep 4, 2026

Copy link
Copy Markdown
Contributor

Human judgment recorded

@CrysisDeu marked the gpt AI finding as false positive, not applicable, or explicitly accepted for 0fdc5453aeeb81c66936740997b5eff603314215.

ErrorNotice cannot render here: Mochi's Settings window is a separate Vite entry (settings.html, bare createRoot) with no Tailwind stylesheet, so ErrorNotice's Tailwind-class inline variant would be unstyled (Mochi's own PanelErrorBoundary hand-rolls role=alert for the same reason); the flagged span is pre-existing and this PR only interpolates the destination label into its string.

This decision applies only to this commit. A new push requires a new judgment.

@github-actions github-actions Bot added readiness: passed Eligible automated validation passed for the current revision and removed readiness: checking Automated validation is still running labels Sep 4, 2026
@iamwhatever
iamwhatever merged commit 1ee3822 into main Sep 5, 2026
64 of 65 checks passed
@iamwhatever
iamwhatever deleted the feat/settings-link-migrations branch September 5, 2026 00:31
@github-actions github-actions Bot removed the readiness: passed Eligible automated validation passed for the current revision label Sep 5, 2026
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.

3 participants