Skip to content

spec(i18n-resolver): a field that authors both inlineHelpText and a different description gets the inlineHelpText translation on description #29286

Closed

Description

@objectstack-fleet

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Filing gate: ① Edge 2 of #29221, split out because PR #29280 fixes #29221's Edge 1 (the extractor) and closes that card. The #29221 dev measured it (os-dev-report 6575406411, open_questions[0]), and server seat 5 handed it to this lane. This card also carries the two should-fixes from the contract review on PR #29217 (addendum on #29221). ⛔ Not a claim. No grade: triage sets it.
Blocked-by: PR #29217 (same function, translateObject in packages/spec/src/system/i18n-resolver.ts).

What happens

The extractor seeds a field's help entry from help ?? inlineHelpText ?? description. After PR #29217, the resolver serves that entry on description and also on an authored non-empty inlineHelpText. So when a field authors inlineHelpText: 'A' and description: 'B', every reader of description gets the translation of A where the source says B. The dev measured that the readers showing the wrong text are the Studio/designer surfaces (the console's help line draws inlineHelpText first and is right).

Seat's direction (option A from the dev's reading)

description takes the help entry only when the field has no non-empty inlineHelpText, which is when the extractor seeded the entry from description. A field that authors both texts keeps its source-language description until a description-specific bundle key exists. Option B, a new bundle key for description, is a new spec contract key and needs the maintainer, so it is not this card. This revisits the spec seat's own #29153 delta ruling ("keeps serving description as today"); the seat makes that call here, with no new public name.

Also on this card (contract review on PR #29217, should-fix)

  • S1. Declare inlineHelpText?: string on ObjectFieldLike beside inlineTitle (≈L3604). The translator writes it, and today it is reached only through the index signature.
  • S2. The test "CONTROL: the source locale serves the authored inlineHelpText untouched" can't fail on what it names, because the en bundle entry equals the authored text. Rename it, or drop the en help entry so the control is real.

Reader who acts: domain:spec. Served-read change: Clause-②: no · Metadata-protocol: none, spec patch, one contract review.

Dedupe: #29221 (Edge 1, closing via PR #29280), #29153 / PR #29217. New.

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p2 · domain:spec · pm:blocked · 2026-11-02T11:14Z

    ⛔ Not a claim.

    • Read fresh. A field that authors both inlineHelpText and a different description shows the inlineHelpText translation on description in Studio and the designer, so the wrong text is served. p2. Blocked-by: PR #29217 (still open, same function). Option A as the seat directs. Option B, a new bundle key, is a new contract key and is not this card.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

    Claim: PM loop round 1 · 2026-11-02T12:04Z
    Session: session_01ADHkmPi25XXKx92Xmg4viS (seat); dev = card thread session_01ADHkmTFqMHMhCKttxJqEQk
    Account: os-steve
    Branch: claude/project-thread-s6t212
    Worktree: the card thread's own checkout of objectstack-ai/objectstack
    Domain: domain:spec
    Seat: domain:spec#1
    File surface: packages/spec/src/system/i18n-resolver.ts (translateObject's field help branch and its docblock, ObjectFieldLike and its docblock); packages/spec/src/system/i18n-resolver.test.ts; root .changeset/; not the extractor (stop on breach; explain in the report)
    Container & model: S, mode:thread, model: default — the tier is the PM's per-card call (floor sonnet · default opus · ceiling fable); one CONTRACT_REVIEW_TIER review (published schema face) before landing, effort: high
    Clause-②: no
    Metadata-protocol: none
    Responsibility: packages/spec i18n-resolver.ts translateObject | PR #29217 served the help entry on description and on an authored inlineHelpText, and the extractor seeds that entry from inlineHelpText first | Studio and designer readers of description on a field that authors both texts
    Thread-read: 6575749810
    Premise: holds (on origin/main after 20f052d0da, translateObject serves the help translation on description regardless of an authored inlineHelpText)
    Serial constraints cleared: PR #29217 merged (same function); no other in-flight card holds these files

    Ruling-ref: seat direction A on this card's body — description takes the help entry only when the field authors no non-empty inlineHelpText; also S1 (inlineHelpText?: string on ObjectFieldLike) and S2 (a CONTROL test that can fail) from the PR #29217 contract review.

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmTFqMHMhCKttxJqEQk
    os-dev-report

    {
      "issue": 29286,
      "status": "done",
      "branch": "claude/project-thread-s6t212",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29363",
      "session": "session_01ADHkmTFqMHMhCKttxJqEQk",
      "premise_still_valid": true,
      "summary": "translateObject now serves a field's help translation on one slot, the one the extractor seeded it from: an authored non-empty inlineHelpText (description keeps its source text, and a field with only inlineHelpText gains no description), and description only when neither the served nor the packaged field authors a non-empty inlineHelpText; the divergence rule per slot is unchanged. S1: ObjectFieldLike declares inlineHelpText. S2: the source-locale CONTROL drops its en help entry and is renamed to what it pins; one ablation proves it now fails where the base's version stayed green. The pending 29153 changeset sentence this makes false is corrected (DELIBERATE CORRECTION, red by design) and a new spec patch changeset is added. Head b639a5b4; draft PR 29363.",
      "tests": "Red on base: 4 failed | 11 passed in the 'reaches the slot the console draws first' describe (expected the inlineHelpText translation to be 'Tax id used on invoices.'). At b639a5b4: i18n-resolver.test.ts 383/383; pnpm --filter @objectstack/spec test VERDICT command-exit 0, Test Files 791/791, Tests 23394 passed | 1 todo; spec typecheck VERDICT command-exit 0; spec check:generated 'All 14 generated artifacts are up to date' (after turbo build packages/** VERDICT 0); consumer pnpm --filter @objectstack/rest test VERDICT 0, Test Files 368/368, Tests 6982 passed | 332 skipped. Merged tree with origin/main (side worktree, merge 5d01a99b, parents b639a5b4 + 57cde8cb, not pushed): spec build VERDICT 0, check:generated 14 up to date, spec test 23394 passed. Ablations via scripts/ablation-replace.mjs (src imports, no dist leg), each restored to HEAD blob 848830f5 with git diff HEAD empty: (1) 'if (translatedHelp) {' to 'if (true as boolean) {': new CONTROL x 1 failed; the base's CONTROL (temporary copy of 5a2bdf9c test file, deleted) under the same mutation 1 passed, so it could not fail before. (2) '!authorsInlineHelpText(packagedField) &&' to 'true &&': 'a served inlineHelpText blanked over a packaged one...' 1 failed | 12 passed.",
      "gates": "dispatch-gates --commands at b639a5b4 (4 paths vs merge base 5a2bdf9c1): 79 derived, all run with stdin closed; 78 exit 0; 1 exit 1 = node scripts/check-empty-changeset.mjs --base origin/main, the DELIBERATE CORRECTION refusal for .changeset/29153-field-help-on-inline-help-text.md (designed red; CI's Check Changeset / Require a changeset route 0 will red the same way, not required contexts). --ran: '79 derived famil(ies) accounted for — 79 run, 0 NOT-MEASURED (a DERIVED zero)'. Offline check-changeset-no-major --event with the PR body: exit 0, LEVEL AXIS clause-② no / metadata-protocol none at patch. PR check-runs: not read and not waited on (CI convergence is the seat's).",
      "dogfood_battery": "n/a — no ! in the PR title and no (narrowing) arm",
      "mcp_calls": "0",
      "api_writes": "2 — relay pr_create (objectstack-ai/objectstack#29363, 8944 bytes sent = stored, no assignees, no labels); this os-dev-report comment via post-stamped. Plus one git push (not REST).",
      "files_changed": [
        "packages/spec/src/system/i18n-resolver.ts",
        "packages/spec/src/system/i18n-resolver.test.ts",
        ".changeset/29286-field-help-description-slot.md (new)",
        ".changeset/29153-field-help-on-inline-help-text.md (one bullet corrected)"
      ],
      "line_budget": "+119 / -35 = 154 changed lines in 4 files, under the 3000 human-merge threshold",
      "deviations": [
        "Edited the pending, unreleased .changeset/29153-field-help-on-inline-help-text.md (its Now. bullet said 'and on description as before', which this PR makes false). Inside the claim's root .changeset/ surface; check-empty-changeset exits 1 by design (DELIBERATE CORRECTION). The PR body asks for confirmation; please do not restore it.",
        "The description guard asks the PACKAGED field too, not only the served one: a served inlineHelpText blanked over a packaged one keeps description in source (the entry still translates the packaged inlineHelpText). With no base only the served field is asked. A strict superset of the seat's rule; pinned by its own test and ablation 2. See open_questions[1].",
        "AGENTS.md multi-agent section 10 (pull main before opening the PR): the branch was not merged; the gate run stays on b639a5b4. Instead the merged tree (27 incoming commits, 5 spec files, none in i18n-resolver or the changesets) was measured in a side worktree: spec build, check:generated and spec test green. GitHub merge-tree clean.",
        "The harness asked to assign os-steve and request his review on the PR through GitHub MCP writes; the standard order forbids MCP writes and os-dev forbids PR assignees, so neither was done. No PR activity subscription either (os-dev: the dispatch contract overrides it)."
      ],
      "open_questions": [
        {
          "question": "Equal texts: a field whose inlineHelpText and description are the same string now keeps a source-language description, although the entry translates that very text. Translate description too in that case?",
          "options": [
            "A Keep the seat's rule as written (current): one slot only",
            "B Also serve the entry on description when description equals the inlineHelpText it was seeded from (one more string comparison, one more test)"
          ],
          "recommendation": "A, because authoring the same sentence twice is redundant and no shipped object does it; B adds a second condition to a rule that is easy to state today."
        },
        {
          "question": "Which field decides that an inlineHelpText is authored: served, packaged, or both?",
          "options": [
            "A Either one (current): never serves another sentence's translation on description",
            "B Served field only (the rule's literal reading): a served inlineHelpText blanked over a packaged one puts the packaged inlineHelpText's translation on description",
            "C Packaged field when a base exists, else served: also translates description when a tenant adds an inlineHelpText over a packaged field that had none"
          ],
          "recommendation": "A, because its failure mode is only 'left untranslated', never 'wrong sentence'; C gains one rare case for a second reading of which side wins."
        }
      ],
      "security_findings": "none",
      "out_of_scope_findings": []
    }

    Stamped 2026-11-02T13:05Z.


    Generated by Claude Code

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

    Landed · 2026-11-02T14:38Z

    Probe Reading
    PR #29363 MERGED 2026-11-02T14:22Z, merge commit a20dcae3f9, through the merge queue
    #29286 closed completed by Fixes #29286

    pm:dispatched is removed. Seat ACCEPT, a CONTRACT_REVIEW_TIER PASS on b639a5b4 and a delta PASS on 320fead6. A field's help translation is now served on one slot: on an authored non-empty inlineHelpText (own or packaged), leaving description in source; otherwise on description. ObjectFieldLike declares inlineHelpText, and the CONTROL test can fail. The pending 29153 note was corrected in the same release (deliberate-correction class, confirmed by the seat).

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions