Skip to content

i18n(field help): the extractor's help ?? inlineHelpText ?? description stops at inlineHelpText: '', and a field authoring both texts gets the inlineHelpText translation on description #29221

Closed

Description

@objectstack-fleet

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Filing gate: ① two edges of the field-help derivation named by the #29153 implementer (os-dev-report 6573912237: a finding to file, plus open question [0], which the seat kept as ruled). They are out of PR #29217's claimed surface. ⛔ Not a claim. No grade: triage sets it.

The one derivation, three places

  • The extractor scaffolds objects.O.fields.F.help from field.help ?? field.inlineHelpText ?? field.description (packages/cli/src/utils/i18n-extract.ts ≈L1489 on main).
  • The console draws inlineHelpText || description (fieldHelpText in @object-ui/fields).
  • After PR fix(spec): serve a field's translated help on its authored inlineHelpText #29217, the resolver serves the help entry on description, and also on inlineHelpText when that is non-empty.

Edge 1: inlineHelpText: '' (extractor)

?? does not skip an empty string, so for a field with inlineHelpText: '' and a description, the extractor seeds help from '': no usable entry is scaffolded. The console treats '' as absent and draws description, so that description is never offered for translation. The implementer probed this with collectExpectedEntries. Wanted: the extractor skips an empty inlineHelpText the way the console does (|| semantics for that link, or an explicit non-empty check). Reader: packages/cli owner.

Edge 2: both texts authored and different (resolver)

A field that authors inlineHelpText: 'A' and description: 'B' gets one help entry, seeded from A, and the resolver serves its translation on BOTH slots. So any reader of description (not the console's help line, which draws inlineHelpText first) sees the translation of A where the source says B. This predates PR #29217: the entry was always served on description. Ruling for #29153 kept it ("keeps serving description as today"). Wanted: a reading of whether description should take the help entry only when the extractor seeded it from description (no non-empty inlineHelpText), and which readers of a field's description exist besides the help line. Reader: domain:spec (packages/spec/src/system/i18n-resolver.ts, translateObject).

Dedupe: searched inlineHelpText extractor empty, field help translation description inlineHelpText. Only #29153 and #25683. New.

Activity

  1. added
    area:i18nThe customer's own language, across UI, metadata and notifications
    domain:serverDomain lane — seat card indexed by label:pm:seat
    and removed on Nov 2, 2026
  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p2 · domain:server · area:i18n · pm:queue (from finding) · 2026-11-02T09:55Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1

    Claim: PM loop round 3 · card thread · 2026-11-02T10:05Z
    Session: session_01ADHkmQKwKFCp1m6Pb6Q8c1 (the seat); the card thread is named in a follow-up claim once it reports its branch
    Account: os-steve (the seat's linked user; the card's assignee)
    Branch: pending — the card thread's harness-pinned branch, written into a follow-up claim before the dev starts
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#5
    Ruling-ref: no maintainer ruling on this card; triage grade p2 (6574191883: os i18n extract lives in packages/cli; read #29153 before claiming).
    File surface: packages/cli/src/utils/i18n-extract.ts (the field help derivation: Edge 1), its tests, changeset. Edge 2 is a reading reported back to the seat, no code. ⛔ No packages/spec/**: the resolver belongs to #29153 / PR #29217 (spec lane).
    Container & model: S, mode:thread, model: the thread's default judgement tier, effort: medium (p2)
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the code is the cli i18n extractor · a field authored with an empty inlineHelpText and a description gets no usable help entry scaffolded, while the console draws the description · reached by app authors running os i18n extract
    Thread-read: 6574191883
    Premise: holds (read at origin/main 0d15f8953: L1489 reads field.help ?? field.inlineHelpText ?? field.description)
    Serial constraints cleared: PR #29217 (#29153, spec seat 1) touches only packages/spec/src/system/i18n-resolver*.ts; no open PR touches packages/cli/src/utils/i18n-extract.ts (file lists read at claim time).
    Resume-from: none — fresh from origin/main

    State: pm:queue → pm:dispatched, assigned to os-steve, recorded by this claim.

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1

    Claim: PM loop round 3 · card thread · branch named · 2026-11-02T10:08Z (supersedes 6574410115, which had the branch pending)
    Session: session_01ADHkmQKwKFCp1m6Pb6Q8c1 (the seat); the card thread is session_01ADHkmT5Q35nWM5fCTsoR5H
    Account: os-steve (the seat's linked user; the card's assignee)
    Branch: claude/project-thread-eps5bg (the card thread's harness-pinned branch; it names no issue, so this claim is the identity record)
    Worktree: the card thread's own container checkout
    Domain: domain:server
    Seat: domain:server#5
    Ruling-ref: no maintainer ruling on this card; triage grade p2 (6574191883: os i18n extract lives in packages/cli; read #29153 before claiming).
    File surface: packages/cli/src/utils/i18n-extract.ts (the field help derivation: Edge 1), its tests, changeset. Edge 2 is a reading reported back to the seat, no code. ⛔ No packages/spec/**: the resolver belongs to #29153 / PR #29217 (spec lane).
    Container & model: S, mode:thread, model: the thread's default judgement tier, effort: medium (p2)
    Clause-②: no
    Metadata-protocol: none
    Responsibility: the code is the cli i18n extractor · a field authored with an empty inlineHelpText and a description gets no usable help entry scaffolded, while the console draws the description · reached by app authors running os i18n extract
    Thread-read: 6574410115
    Premise: holds (read at origin/main 0d15f8953: L1489 reads field.help ?? field.inlineHelpText ?? field.description)
    Serial constraints cleared: PR #29217 (#29153, spec seat 1) touches only packages/spec/src/system/i18n-resolver*.ts; no open PR touches packages/cli/src/utils/i18n-extract.ts (file lists read at claim time).
    Resume-from: none — fresh from origin/main

    State: pm:queue → pm:dispatched, assigned to os-steve, recorded by this claim.

  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-steve · session_01ADHkmT5Q35nWM5fCTsoR5H
    os-dev-report

    {
      "issue": 29221,
      "status": "done",
      "branch": "claude/project-thread-eps5bg",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29280",
      "head": "3298a9c9dfc478feb88bfb9e3fb5158782501bd4",
      "session": "session_01ADHkmT5Q35nWM5fCTsoR5H",
      "premise_still_valid": true,
      "summary": "Edge 1: collectExpectedEntries seeds objects.O.fields.F.help from the first AUTHORED link of help, inlineHelpText, description (asAuthoredLabel, the file's one authored test), so an empty inlineHelpText or help no longer stops the chain and the description the console draws is scaffolded. Whitespace-only text stays authored, matching the console's || and PR #29217's non-empty check. The field help chain is the only fallback derivation of help text in the extractor; every other help key reads one key. Edge 2 is a reading only (open_questions[0]); no packages/spec edit.",
      "tests": "head 3298a9c9 (merge of origin/main 01252a45). cli unit on a6ea00b0: Test Files 372 passed (372), Tests 5259 passed (5259); cli typecheck + check:test-typecheck OK; VERDICT command-exit 0. After the merge (no cli file moved; spec + service-analytics rebuilt): i18n-extract-inline-help-text + i18n-extract, Test Files 2 passed, Tests 39 passed. New pins: 9 tests in test/i18n-extract-inline-help-text.test.ts. Ablation via ablation-replace.mjs restoring `field.help ?? field.inlineHelpText ?? field.description` (anchor 1->0, blob 21178839abf6->1ccf82f67d58; src import, no build): Tests 5 failed | 10 passed (15), e.g. `expected undefined to be 'B'` and the coverage case `expected [ { severity: 'error', ... } ] to deeply equal []`; restored, git diff HEAD empty.",
      "gates": "dispatch-gates --commands on 3298a9c9: 61 commands, stdin closed; 58 exit 0 first pass; 3 exit 3 (prerequisites) then exit 0: plugin-teardown self-test after fetching its pinned fixture commit, check:dual-build-cjs-loads and check:i18n-coverage after turbo build packages+examples (VERDICT 0). check:i18n-coverage: OK (14 configs, 426 baselined, none new); check:i18n exit 0; tree clean, nothing regenerated. --ran with exit codes: 61 derived, 61 run, 0 NOT-MEASURED (derived zero), exit 0. Lint: eslint --no-inline-config on the 2 touched cli files exit 0, no output. CI check-runs: in_progress at report time.",
      "dogfood_battery": "n/a — no `!` in the PR title and no (narrowing) arm",
      "line_budget": "+94 / -1 over 3 files (extractor +11/-1, test +69, changeset +14)",
      "files_changed": [
        "packages/cli/src/utils/i18n-extract.ts",
        "packages/cli/test/i18n-extract-inline-help-text.test.ts",
        ".changeset/29221-i18n-extract-field-help-empty-link.md"
      ],
      "locale_bundle_measurement": "0 committed bundles or fixtures change: no non-test source authors inlineHelpText: '' or help: '' (git grep on 3298a9c9); check:i18n and check:i18n-coverage (14 configs incl. showcase) green with a clean tree.",
      "deviations": [
        "PR body first two lines are the harness attribution block (marker + requested-by line); Fixes #29221 is line 3, as os-dev allows.",
        "The harness asked for an MCP assignee/reviewer write after pr_create; not done, the standard order forbids MCP writes and os-dev forbids PR assignees.",
        "Gate first pass had 3 exit-3 prerequisites; cleared and rerun as listed in gates."
      ],
      "mcp_calls": "5 — all reads: issue_read get (#29221), issue_read get_comments (#29221), pull_request_read get_diff (#29217), pull_request_read get (#29227, body shape), pull_request_read get (#29280, read-back)",
      "api_writes": "2 — relay pr_create (#29280, run 41432621544) and this os-dev-report comment via post-stamped.mjs",
      "open_questions": [
        {
          "question": "Edge 2: a field authoring a non-empty inlineHelpText and a different description gets one help entry seeded from the inlineHelpText, and translateObject serves it on description too. Readers of a served field description besides the console help line: Studio designer surfaces (ObjectFieldInspector description box, ObjectFormCanvas preview, DataModelDesigner row tooltip, plugin-designer PropertyEditor, MetadataService.toFieldPayload writing it back on save); RecordDetailPanel copies it onto detail fields but no plugin-detail renderer draws it; runtime summarizeActionParams (MCP tool list) uses it as param help but reads the registry object, not a localized serve. Should description keep receiving the help entry for such a field?",
          "options": [
            "A: resolver only (spec seat 1, translateObject): serve the help entry on description only when the field authors no non-empty inlineHelpText; such a field's description stays source text. No new bundle key, no extractor change. Reverses what the #29153 ruling kept, so it needs that ruling revisited.",
            "B: extractor + spec: scaffold a separate fields.F.description entry for such fields and have the resolver serve it. Needs a FieldTranslationSchema key (packages/spec, Metadata-protocol: added) plus the extractor and coverage changes; largest cost.",
            "C: keep today's behaviour (the #29153 ruling): description shows the inlineHelpText translation; no work."
          ],
          "recommendation": "A, because the only readers that show the wrong text are Studio/designer surfaces that render description as its own meaning, a source-language description is truer than a translation of different text, and the fix is one condition in translateObject with no contract key; it routes to spec seat 1 as the delta says."
        }
      ],
      "out_of_scope_findings": []
    }

    Stamped 2026-11-02T10:56Z.


    Generated by Claude Code

  6. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

    Addendum from the contract review on PR #29217 (PASS, same head e1451dc) · 2026-11-02T10:59Z

    Two should-fixes, carried here so the reviewed head lands unchanged:

    • S1. ObjectFieldLike in packages/spec/src/system/i18n-resolver.ts (≈L3604) declares inlineTitle?: string but not inlineHelpText, which the translator now writes. The slot is reached only through the [key: string]: any index signature. Declare inlineHelpText?: string beside inlineTitle (additive, patch).
    • S2. The test "CONTROL: the source locale serves the authored inlineHelpText untouched" can't fail on what it names. The en bundle entry equals the authored text, and localeChain consults the requested locale's own bundle even for the default locale, so the slot is rewritten with an identical string. Rename the test to what it pins, or drop the en help entry so the control is real.
  7. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1

    Landed · #29221 · 2026-11-02T11:58Z

    reading value
    PR #29280 MERGED by the merge queue at 2026-11-02T11:58:28Z, merge commit 6dd6a534e5 (head 3298a9c9, ACCEPT 6575427910)
    this card closed completed by the PR's Fixes line

    State: pm:dispatched removed; the remaining labels stay. Edge 1 (the extractor) is fixed by this PR. Edge 2 (the resolver serving the help entry on description) was handed to the domain:spec lane, which holds translateObject and the #29153 ruling.

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

Metadata

Metadata

Assignees

Labels

area:i18nThe customer's own language, across UI, metadata and notificationsdomain:serverDomain lane — seat card indexed by label:pm:seatpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions