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
{{ message }}
Repository navigation
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
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).
?? 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.
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/main0d15f8953: 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.
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/main0d15f8953: 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.
{
"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": []
}
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 enhelp entry so the control is real.
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.
Activity
objectstack-fleet commentedon Nov 2, 2026
triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U
Path: none
Triage: p2 ·
domain:server·area:i18n·pm:queue(fromfinding) · 2026-11-02T09:55Z⛔ Not a claim.
help ?? inlineHelpText ?? descriptionand stops atinlineHelpText, the same masking that p1 Email template resolver ignores i18n.fallbackLocale and does no language-subtag folding: en-GB / zh-TW recipients never reach en / zh-CN rows #28880-family card i18n: a field's translated help never shows when the field authors inlineHelpText — the server serves fields.FIELD.help on description and the console draws inlineHelpText first #29153 fixes on the serving side.os i18n extractlives inpackages/cli, so this isdomain:server. It belongs with i18n: a field's translated help never shows when the field authors inlineHelpText — the server serves fields.FIELD.help on description and the console draws inlineHelpText first #29153's fix, so read i18n: a field's translated help never shows when the field authors inlineHelpText — the server serves fields.FIELD.help on description and the console draws inlineHelpText first #29153 before claiming. p2, andfindingis dropped (one state).Generated by Claude Code
objectstack-fleet commentedon Nov 2, 2026
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 branchAccount:
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:serverSeat:
domain:server#5Ruling-ref: no maintainer ruling on this card; triage grade p2 (6574191883:
os i18n extractlives inpackages/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. ⛔ Nopackages/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
inlineHelpTextand adescriptiongets no usablehelpentry scaffolded, while the console draws the description · reached by app authors runningos i18n extractThread-read: 6574191883
Premise: holds (read at
origin/main0d15f8953: L1489 readsfield.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 touchespackages/cli/src/utils/i18n-extract.ts(file lists read at claim time).Resume-from: none — fresh from
origin/mainState:
pm:queue→pm:dispatched, assigned toos-steve, recorded by this claim.objectstack-fleet commentedon Nov 2, 2026
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 issession_01ADHkmT5Q35nWM5fCTsoR5HAccount:
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:serverSeat:
domain:server#5Ruling-ref: no maintainer ruling on this card; triage grade p2 (6574191883:
os i18n extractlives inpackages/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. ⛔ Nopackages/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
inlineHelpTextand adescriptiongets no usablehelpentry scaffolded, while the console draws the description · reached by app authors runningos i18n extractThread-read: 6574410115
Premise: holds (read at
origin/main0d15f8953: L1489 readsfield.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 touchespackages/cli/src/utils/i18n-extract.ts(file lists read at claim time).Resume-from: none — fresh from
origin/mainState:
pm:queue→pm:dispatched, assigned toos-steve, recorded by this claim.objectstack-fleet commentedon Nov 2, 2026
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
objectstack-fleet commentedon Nov 2, 2026
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:
ObjectFieldLikeinpackages/spec/src/system/i18n-resolver.ts(≈L3604) declaresinlineTitle?: stringbut notinlineHelpText, which the translator now writes. The slot is reached only through the[key: string]: anyindex signature. DeclareinlineHelpText?: stringbesideinlineTitle(additive, patch).inlineHelpTextuntouched" can't fail on what it names. Theenbundle entry equals the authored text, andlocaleChainconsults 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 theenhelpentry so the control is real.objectstack-fleet commentedon Nov 2, 2026
domain:server#5 · os-steve · session_01ADHkmQKwKFCp1m6Pb6Q8c1
Landed · #29221 · 2026-11-02T11:58Z
6dd6a534e5(head3298a9c9, ACCEPT 6575427910)completedby the PR'sFixeslineState:
pm:dispatchedremoved; the remaining labels stay. Edge 1 (the extractor) is fixed by this PR. Edge 2 (the resolver serving thehelpentry ondescription) was handed to thedomain:speclane, which holdstranslateObjectand the #29153 ruling.