Skip to content

fix(app-bundle): guard tool-count-label split() against undefined translations (#987) - #988

Merged
aarontrowbridge merged 1 commit into
mainfrom
967-tool-count-guard
Sep 10, 2026
Merged

fix(app-bundle): guard tool-count-label split() against undefined translations (#987)#988
aarontrowbridge merged 1 commit into
mainfrom
967-tool-count-guard

Conversation

@aarontrowbridge

Copy link
Copy Markdown
Member

Fixes #987 — the production hub-panel crash Aaron hit live during #955's cutover smoke.

What

TypeError: Cannot read properties of undefined (reading 'startsWith') on cold page load, recurring and restart-masked. Mechanism: the base session-ui/src/components/tool-count-label.tsx renders via split(i18n.t(...)) — with the i18n dict not yet loaded (async resource) or a key missing, i18n.t(...) returns undefined; split(undefined) produced {before: "", after: undefined} and the memos' one().after.startsWith(...) threw inside a Solid effect.

The fix (overlay twin)

  • overlay/packages/session-ui/src/components/tool-count-label.tsx — the base file plus a guard: split(text: string | undefined) returns {before: "", after: ""} for falsy text (honest empty render until the translation exists, the language.tsx fallback discipline), with a header comment naming the bug and mechanism.
  • Overlay mechanism verified (the step-3 check): materialize.mjs walks the entire overlay/ tree recursively and applies every package — session-ui is a first-class overlay package (25A/29M→30M in the manifest). The twin materializes byte-identical into the composed tree.
  • Manifest re-registered via refresh_manifest.mjs (620 files); drift gate PASS.

Tests

packages/extension/test/tool_count_label_guard_987.test.ts (vitest, the #964 contract/source pattern — the app has no render harness):

  • the twin's actual split/common code is extracted from the file, transpiled, and exercised — not a re-typed copy;
  • the memo derivations that threw in production run against a missing key (t → undefined) across all six plural categories — no throw, empty render;
  • the unguarded base file reproduces the exact production crash under the same harness (verified), the twin does not;
  • manifest registration asserted at the exact hash (drift-gate invariant).

Verification

Refs #955, #964, #842.

…nslations (#987)

The hub panel threw `TypeError: Cannot read properties of undefined
(reading 'startsWith')` on cold page load (recurring, restart-masked),
hit live during #955's cutover smoke: when the i18n dict hasn't loaded
yet or a key is missing, i18n.t(...) returns undefined and the base
tool-count-label.tsx's split() coerced it into {after: undefined},
throwing inside a Solid effect.

The fix rides as an overlay twin (session-ui materializes from the
overlay like every other app-graph package): split() guards falsy text
and returns the honest empty render {before: "", after: ""} — the
language.tsx fallback discipline — until the translation exists.

Manifest re-registered (refresh_manifest); drift gate PASS; the twin
materializes byte-identical into the composed tree. Test guard
(#964 contract/source pattern) extracts the twin's real split/common
and runs the memo derivations for missing keys — the unguarded base
reproduces the production crash under the same harness, the twin does
not. NOTE: the fork→overlay sync treats the fork as authoritative for
session-ui files — mirror this fix to the fork's local/amicode branch
(per #964) so the next sync brings the fix, not the regression.
@coderabbitai

coderabbitai Bot commented Sep 10, 2026

Copy link
Copy Markdown

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@aarontrowbridge
aarontrowbridge marked this pull request as ready for review September 10, 2026 22:07
@aarontrowbridge
aarontrowbridge merged commit 500a7d9 into main Sep 10, 2026
10 checks passed
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.

fix(ui): tool-count-label throws on unloaded i18n dict — guard split() against undefined translations

1 participant