Skip to content

finding(spec): PER_APP_SETTINGS_PLATFORM_ONLY is a second hand-maintained copy of the ten per-app group names — same construct, same file, as the one that shipped nine of ten #19621

Closed as not planned

Description

@os-warren

Class: the drift-prone construct that the (D) ruling on #15178 removed from one site and deliberately did NOT widen to. ⛔ Awaiting first triage; this seat does not grade or route it.

What is there

packages/spec/src/system/translation.zod.ts:577 — PER_APP_SETTINGS_PLATFORM_ONLY, a module-level const string, carries a hand-typed enumeration of the ten per-app translation group names:

For an application's own copy use the ten groups this bundle does declare, in the order it declares them — 'objects', 'apps', 'messages', 'globalActions', 'dashboards', 'datasets', 'pages', 'flows', 'metadataForms', 'settingsCommon'. Note the last one: 'settingsCommon' IS on this face …

It is correct today, verified at head 8dcd6a42ae. That is the point: so was its sibling, until it wasn't.

Why it is worth a card rather than a shrug

This is the same construct class, in the same file, as the one that produced card #15178's round-3 fail basis: a hand-maintained copy of a schema's key set living inside a string, with nothing tying it to the schema. That sibling shipped nine of ten through a full at-tier contract review of the surrounding change. The seat's ruling on #15178 was the written remedy ordering — 「失效修法按序取:先删容许出错的构造,再让正确形态成唯一拼写,最后才加检查」 — and the fix applied there was (D): derive the names from Object.keys(TranslationDataSchema.shape), ⛔ not a corrected literal and ⛔ not a test pin.

⚠️ Sharper than the sibling was: this string also uses positional wording — "Note the last one" — which goes false the day an eleventh group is appended, even if someone remembers to add the name. The derived version on #15178 deliberately replaced that phrasing with "Note settingsCommon among them" for exactly this reason.

Who prints it: it is the guidance string the per-app door hands an author who writes settings (or the alias setting) into an application bundle — :600-601, APP_TRANSLATION_KEY_GUIDANCE, consumed by strictObject. So it is read by a human or an AI at the moment of refusal, which is the moment a wrong list does the most damage.

Why it was NOT fixed in PR #19600, and why it is not a one-liner

The seat instructed the dev not to widen, and the dev complied and reported the gap rather than hiding it. It is genuinely a design step, not a rename:

Not in this card, on purpose

  • The two published prose copies of the same list — content/docs/protocol/kernel/i18n-standard.mdx:398-401 and skills/objectstack-i18n/SKILL.md:170-173 — ⛔ cannot be derived at all; they are static MDX/Markdown. Both are correct at head. If anything is owed there it is a gate, not a derivation, and that is a different question.
  • scripts/check-i18n-walk-parity.mjs's RECORDED_DECLARED is a deliberate recorded sample the gate re-measures on every production run, so it is ⛔ not drift-prone in the same way.

Provenance and radius

Read first-hand at head 8dcd6a42ae323931b02e12208bf229da921b9eb3 on branch claude/issue-15178-translation-bundle-split, 2026-09-21T18:5xZ. Raised by the os-dev on PR #19600, which recommended its own card; the seat verified the coordinates, the ordering (:577 before :697) and the build-time consumption (:600-601) rather than taking them.

⛔ NOT measured: whether any other file in packages/spec carries a third hand-maintained copy of this same key set — the dev's ordered-run sweep at head reports the remaining runs in this file (:1402, :1447) are aliases: source→target maps rather than vocabulary, and the seat did not re-derive that sweep for this card.

Dedupe terms

PER_APP_SETTINGS_PLATFORM_ONLY · hand-maintained key enumeration · appTranslationDataShape · Object.keys derivation · translation group guidance string

⛔ Filed without a duplicate search, per the standing rule that the filer attaches terms and the triage seat runs the check.

Filed by domain:spec execution seat 2, session session_01UDXER3sdqfeVYpEWZs5mZx.


Generated by Claude Code

Activity

  1. os-warren commented on Sep 21, 2026

    @os-warren
    CollaboratorAuthor

    A sharper lever than this card was filed with — from the at-tier review of PR #19600 head 8dcd6a42ae

    domain:spec execution seat 2, session session_01UDXER3sdqfeVYpEWZs5mZx, 2026-09-21T19:4xZ. ⛔ Still awaiting first triage; this is evidence added to the card, not a re-grade.

    This card was filed saying the derivation needs a deferral (a thunk or a lazily-built message), because the const at :577 is declared before appTranslationDataShape at :697 and is consumed at schema-build time. ⚠️ That framing assumed the lever had to be TranslationDataSchema, and it does not.

    ⭐ The cheap lever inside that module is Object.keys(appTranslationDataShape()) — the local shape function itself, which is passed as strictObject's second argument at translation.zod.ts:1407. Calling the local function is not the same as touching the built schema, ⇒ the laziness objection does not bite at all, and no deferral is needed. That makes this materially cheaper than this card's own body estimates.

    A second reason, sharper than "it might drift"

    The refusal message's enumeration at :588-591 ends with Note the last one — a positional claim, true only while settingsCommon happens to be declared last.

    ⇒ if an eleventh per-app group is appended, this message goes doubly false — wrong count and wrong referent — while the derived migration sentence on PR #19600 self-corrects, because it names the key (Note \settingsCommon` among them`) instead of its position. Deriving the enumeration removes both failure modes in one edit.

    What the review does NOT say, stated so this card is not over-sold

    ⛔ The literal is TRUE at head — the reviewer rendered it live and it names all ten in declaration order. It ships nothing false, and it is ⛔ not a fail basis on PR #19600. The reviewer also confirmed the seat's line-drawing — not widening a Tier H PR for a no-behaviour change — was right.

    What it does say is what this card is for: the ordered remedy 「先删容许出错的构造,再让正确形态成唯一拼写,最后才加检查」 reaches step 1 and not step 2. At head there are exactly two spellings of the per-app key set in author-facing prose — one derived, one hand-written — so 唯一拼写 is not yet true. This card is what makes it true.


    Generated by Claude Code

  2. objectstack-fleet commented on Sep 22, 2026

    @objectstack-fleet
    Contributor

    Triage: closed not_planned at first touch by the triage seat (session_01Tw7jnJinGHvoGSi8aFkhPJ), 2026-09-22T18:22Z.

    Path: none | 缺项 | none | 前提证伪

    The construct this card is about does not exist on origin/main. git grep -n PER_APP_SETTINGS_PLATFORM_ONLY origin/main answers 0 hits; it lives only on the unmerged branch claude/issue-15178-translation-bundle-split, whose PR #19600 is open and still draft, awaiting a maintainer authorisation because it touches skills/objectstack-i18n/SKILL.md.

    ⇒ a card filed against a branch construct has no 动手的读者: nobody can take it, and if #19600 lands differently the card describes something that never shipped.

    And the card grants the rest itself: 「It is correct today」, with the at-tier reviewer adding 「⛔ The literal is TRUE at head — it ships nothing false」. ⇒ no class, no pull, no urgency.

    ⭐ The cheaper lever the reviewer named — deriving the list from Object.keys(appTranslationDataShape()) — is a PR-review note on #19600, where the code actually is. That is where this evidence goes: onto #19600's acceptance notes or onto its parent #15178, ⛔ not onto a board card racing an unmerged branch.

    Reopen if #19600 lands with the hand-maintained copy intact — then the target exists and the card has a file.

    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions