You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: land machine translations post-merge instead of in the PR (#2115)
* feat: land machine translations post-merge instead of in the PR
The locale pipeline moves from committing translations onto the PR branch
(same-repo PRs only; fork PRs were skipped) to a daily post-merge run that
pushes them straight to master with the release App credential. The
completeness checks in test_locale_parity.py gate behind
LOCALE_COMPLETENESS_CHECKS=1 and run in the workflow as its verification;
PR CI keeps only deterministic, engine-free obligations.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgWpy7arov56hET1PzoeCS
* fix: address review findings — restore two-job token isolation, split verification, close fail-open gate
Codex P1s: the push credential moves back to a fresh job consuming a
patch artifact through the rename pre-checks and locale allowlist; the
component placeholder check returns to PR CI, restricted to keys whose
English matches the baseline.
Review-agent findings: the staleness check (held gated-stub keys) no
longer blocks the push — it reddens the job instead of discarding every
translation and re-burning quota daily; both verification steps assert
zero junit skips and test_locale_sync_gate_shape.py pins the gate wiring
pre-merge; the filled-tool-sections asserts split out of
test_shipped_catalog_loads_and_is_registered so a meta-only stub
language can merge; wrong-ref dispatches fail loudly; docs now state
that hand-translating a changed English string requires a baseline
repin in the same PR (AGENTS.md, locales README, settings_ui AGENTS.md,
CONTRIBUTING.md).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgWpy7arov56hET1PzoeCS
* fix: harden the push path per bot review round two
Codex P1: the push job now refuses any settings.js change outside the
generated FEATURE_META block (byte-compare against master with the
region stripped) — generate_locales preserves everything outside the
markers, so the whole-file allowlist entry was a smuggling channel for
served client-side JS. Codex P2s: the master-write concurrency group
moves to the short push job so the translate leg cannot make a hotfix
release queue behind it (a locale-sync group prevents self-overlap),
and the dispatch guard compares the full ref so a tag named after the
default branch cannot pass. CodeRabbit: the guard's ref values reach
the shell through env, never expanded (zizmor template-injection); the
rebase-retry fetches through the same authenticated URL as the push;
the shape test's export assertion narrows to the git-add step; the
baseline-drift set is computed once, cached, across the placeholder
test's parametrization.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgWpy7arov56hET1PzoeCS
* fix: drop settings.js from the sync patch and pin gate semantics, per review
Patch76's review, both concerns. settings.js leaves the export and the
allowlist entirely: its generated FEATURE_META block derives from
en.json alone, which the pipeline never touches and PR CI keeps
current, so the sync never legitimately stages the file — the marker
region byte-compare it replaces guarded only outside the markers while
the block itself is executed JavaScript. With no executable file on the
patch, the no-code property holds by construction.
The shape test now pins semantics instead of tokens: the push predicate
is asserted with its negation, the allowlist arms are compared as an
exact set, the dispatch guard's actual ref comparison is required, and
every junit report written must be consumed. Replayed the review's
mutation matrix — inverting the predicate, widening the allowlist,
hollowing the guard, and deleting the skip-check call sites each now
fail exactly one assertion.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgWpy7arov56hET1PzoeCS
* test: pin the catch-all's refusal and the credential-free checkout
Patch76's second matrix pass: gutting the catch-all arm to '*) ;;'
leaves the allowlist's parsed arm SET unchanged while admitting every
path — its exit 1 is the entire allowlist — and nothing read the
checkout steps, so removing persist-credentials: false survived too.
Both pinned; both mutations now fail exactly one assertion each.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NgWpy7arov56hET1PzoeCS
---------
Co-authored-by: kingpanther13 <kingpanther13@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
|`locale-sync.yml`|Same-repo PR touching locale catalogs, tool sources, or the locale scripts | Machine-translate stale/missing strings and commit them to the PR branch|
339
+
|`locale-sync.yml`|Daily schedule + manual dispatch | Machine-translate stale/missing strings post-merge and push them straight to master|
340
340
341
341
**Docker image tags** (`ghcr.io/homeassistant-ai/ha-mcp`): stable releases push `:latest` + `:stable` + semver tags (`release-publish.yml`); dev builds push only `:dev` + `:dev-<sha>` (`publish-dev.yml`) — **never `:latest`**, which is reserved for stable. The HA add-on images live in separate repos (`-addon-{arch}`, `-addon-dev-{arch}`) and are selected by an explicit `version:` pin, not by `:latest`.
342
342
@@ -745,10 +745,9 @@ lacks: nothing renders it. `tool_groups` and `tools` may do neither: each locale
745
745
must carry exactly the renderable group headings and every tool name, no key
746
746
more and none fewer. The check derives the tool set from
747
747
the sources (`scripts/extract_tools.py`), not from the committed
748
-
`site/src/data/tools.json` that `sync-tool-docs.yml` regenerates only after
749
-
merge — so the PR adding a tool goes red, rather than the next PR someone
750
-
opens. Separately from those key rules, both authored surfaces cap how much
751
-
*text* a catalog
748
+
`site/src/data/tools.json` — the check must not depend on a generated
749
+
artifact that a separate post-merge workflow keeps current. Separately from
750
+
those key rules, both authored surfaces cap how much *text* a catalog
752
751
may leave byte-identical to English or omit outright, so a stub cannot ride the
753
752
fallbacks: 5% for the settings UI `messages`, its `tools` titles and
754
753
descriptions, and each generated add-on projection (per flavor, computed from
Copy file name to clipboardExpand all lines: src/ha_mcp/settings_ui/AGENTS.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -37,7 +37,7 @@ Any reachable HA instance works for `HOMEASSISTANT_URL` / `HOMEASSISTANT_TOKEN`.
37
37
-`settings.html` — the page markup. `__HA_MCP_CSS__` and `__HA_MCP_JS__` are filled once at import. `__HA_MCP_THEME_PREFS__`, `__HA_MCP_I18N__`, `__HA_MCP_LANG__`, and `__HA_MCP_DIR__` are filled per request by `_render_settings_html()`.
38
38
-`settings.js` — the client script, injected into `<script>__HA_MCP_JS__</script>`. Not served as a separate asset.
39
39
-`settings.css` — the stylesheet, injected into `<style>__HA_MCP_CSS__</style>`.
40
-
-`_i18n.py` and `locales/*.json` — auto-discovered translation catalogs. English is the per-key fallback for `messages`. Adding a language is not a single-file change: it ships on all four translated surfaces or not at all, its`tool_groups` and `tools` sections are mandatory and exact, and `en.json` is the wrong starting point because it carries both of those empty. See `locales/README.md` for the procedure and the repository-root `AGENTS.md` § Translations for the rules CI enforces. The wheel, sdist and binary declarations match the locale directory by pattern, so a new catalog needs no packaging edit — but keep those patterns intact when touching packaging.
40
+
-`_i18n.py` and `locales/*.json` — auto-discovered translation catalogs. English is the per-key fallback for `messages`. Adding a language is not a single-file change: it ships on all four translated surfaces or not at all. Its`tool_groups` and `tools` sections must end up exact — the post-merge locale-sync workflow fills and verifies them, so a `meta`-only stub may merge — and `en.json` is the wrong starting point because it carries both of those empty by design. See `locales/README.md` for the procedure and the repository-root `AGENTS.md` § Translations for the rules CI enforces. The wheel, sdist and binary declarations match the locale directory by pattern, so a new catalog needs no packaging edit — but keep those patterns intact when touching packaging.
0 commit comments