Skip to content

fix(platform): green the automations workbench i18n and lint gates - #3185

Merged
Israeltheminer merged 2 commits into
mainfrom
fix/automations-switcher-i18n-and-lint
Sep 3, 2026
Merged

fix(platform): green the automations workbench i18n and lint gates#3185
Israeltheminer merged 2 commits into
mainfrom
fix/automations-switcher-i18n-and-lint

Conversation

@Israeltheminer

@Israeltheminer Israeltheminer commented Sep 3, 2026

Copy link
Copy Markdown
Collaborator

main is red on four CI jobs. All of it traces to one landed change: the
automations workbench shipped its breadcrumb switcher without adding the
automations.switcher.* namespace to the base locale.

What was failing

Job Failure
Unit lib/i18n/messages.test.ts — 4 referenced-but-undefined keys, 3 defined-but-unread keys
UI automation-breadcrumbs + automation-breadcrumb-switcher — 8 assertions
Lint 6 oxlint errors in the new components
Playwright (platform 4/16) automations.spec.ts — all 3 retries on messages key is not a string

The UI failures are the same defect, not a separate one. Those two suites
don't mock useT, so they resolve real messages — the switcher trigger could
not produce the accessible name they look for, because switcher.ariaLabel
didn't exist. Every other automations suite mocks useT to echo ns.key,
which is why they stayed green and hid it.

This is user-visible, not just a red gate: the switcher's title, search
placeholder, empty state and aria-label all rendered as raw key paths.

What this changes

Adds the four switcher keys to en, de and fr, mirroring
projects.switcher key-for-key — the only existing instance of this
component's contract. Same wording shape, same quoting convention (fr uses
double quotes around the apostrophe and a plain space before the colon,
matching its neighbours), same {name} placeholder. de-CH is a sparse
overlay with no automations block, so it needs nothing.

Drops three dead keystrigger.enabledBadge, trigger.disabledBadge,
bindings.orgBadge. Nothing renders them, and no hardcoded English stands in
their place: the trigger editor uses a labelled Switch
(trigger.enabledLabel), the bindings panel a count badge
(bindings.countBadge), and project-bindings-section.test.tsx asserts the
org badge is absent for an unbound automation. They're leftovers from an
earlier design. Flagging it explicitly in case one was meant as UI that never
got wired — say so and I'll build the badge instead.

Fixes the e2e locator key. automations.spec.ts looked for a button named
automations.list.createButton; the list labels that button builder.new.
The spec now asks for the key the component renders.

Six lint fixes, all mechanical:

  • three effects that return a cleanup now return undefined on their
    early-out, matching the house pattern in organization-settings.tsx and
    preferences-settings.tsx
  • enabled !== true!enabled, and trigger.blocked !== true
    !trigger.blocked; both are non-optional booleans. trigger?.dirty === true
    stays — that one reaches through an optional chain
  • the version menu items build in a block body, so the conditional trailing
    is a ternary instead of a spread inside map

New guard

usage-missing could not have caught the e2e break: it reads only t aliases
bound by useT/useTranslation to a known namespace, and the e2e helper's t
takes a whole key path. I tried widening its scanRoots to tests first — it
changes nothing, for that same reason, so it isn't in this diff.

lib/i18n/e2e-keys.test.ts guards it where the reference actually lives: every
static t() literal under tests/e2e/** goes through the specs' own resolver.
Same function, same catalog, so there's no second parser to drift. It currently
covers 333 references across 21 files, and a floor on that count keeps it from
passing vacuously if the pattern stops matching.

Verification

Each gate observed red before and green after, on this branch:

  • oxlint --type-aware: exit 1 on main → exit 0 here
  • lib/i18n/: 2 failed / 22 passed → 50 passed (50)
  • automations client suites: 8 failed → 165 passed (24 files)
  • full client project: 3439 passed
  • typecheck 0 errors, oxfmt --check clean

Both new assertions mutation-tested: restoring the bad key fails the guard and
names it (automations.list.createButton (specs/automations.spec.ts)), and
breaking the extraction pattern fails the floor.

One unrelated pre-existing failure remains in
app/components/ui/forms/date-picker.test.tsx (a pointer-events
computed-style assertion). It fails identically on unmodified main and does
not fail in CI, so it's out of scope here.

The automations workbench landed with its switcher namespace missing from
the base locale, so `automations.switcher.*` rendered as raw keys and three
CI jobs went red on main:

- Unit: `usage-missing` flagged all four `t('switcher.*')` calls as
  referenced-but-undefined, and `usage` flagged three keys defined but
  never read.
- UI: the breadcrumb suites resolve real messages (they do not mock
  `useT`), so eight assertions looked for an accessible name the switcher
  could not produce.
- Lint: six oxlint errors in the new components.

Add the four `switcher` keys to en/de/fr, mirroring `projects.switcher`
key-for-key — same wording shape, same quoting, same placeholder. de-CH is
a sparse overlay with no `automations` block and needs none.

Drop `trigger.enabledBadge`, `trigger.disabledBadge` and
`bindings.orgBadge`. No component renders them: the trigger editor shows a
labelled Switch, the bindings panel shows a count badge, and its test
asserts the org badge is absent for an unbound automation. They are
leftovers from an earlier design, not missing UI.

For lint: give the three cleanup-returning effects an explicit
`return undefined` on their early-out, compare the two plain booleans
directly, and build the version menu items in a block body so the
conditional `trailing` no longer needs a spread inside `map`.
…class

The automations spec builds its create-menu locator from
`automations.list.createButton`, which is not in the catalog — the list
labels that button `builder.new`. The spec failed all three Playwright
retries on `messages key is not a string`.

Point it at the key the component actually renders.

The `usage-missing` check could not see this: it reads only `t` aliases
bound by `useT`/`useTranslation` to a known namespace, and the e2e helper's
`t` takes a whole key path. Widening its `scanRoots` to `tests` changes
nothing for the same reason.

So guard it where the reference lives — run every static `t()` literal in
`tests/e2e/**` through the specs' own resolver. Same function, same
catalog, so there is no second parser to drift. A missing key is now named
in milliseconds instead of costing a Playwright shard. A floor on the
reference count keeps the check from passing vacuously if the pattern
stops matching.
@Israeltheminer
Israeltheminer merged commit 1c8dcf9 into main Sep 3, 2026
48 checks passed
@Israeltheminer
Israeltheminer deleted the fix/automations-switcher-i18n-and-lint branch September 3, 2026 16:31
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