Skip to content

fix(spec): a field authoring inlineHelpText keeps its source-language description - #29363

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-s6t212
Nov 2, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-s6t212

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Steve · project thread
Fixes #29286

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:translateObject 把字段的 help 译文只放到它的来源槽位:字段(服务端或打包声明)写了非空 inlineHelpText 时只译 inlineHelpText,description 保持原文;都没写时才译 description。另在 ObjectFieldLike 上声明 inlineHelpText,并让源语言的 CONTROL 测试真正可失败。
  • 为什么改:抽取器按 help ?? inlineHelpText ?? description 取 help 原文;同时写了两段不同文字的字段,Studio 和设计器读 description 时显示的是 inlineHelpText 的译文,一句话被换成了另一句话。
  • 风险与回滚:只影响已翻译的对象读取;只写 description 的字段照旧被翻译,租户改过的值照旧保留,作者能写什么不变。仓库里没有发布的对象同时写这两段文字(只有 showcase lead_score 写了 inlineHelpText,它没有 description)。回滚即撤掉本 PR。
  • 先看:packages/spec/src/system/i18n-resolver.ts 中 translateField 的 help 分支与新的 authorsInlineHelpText;i18n-resolver.test.ts 中两个 translateObject help describe;.changeset/29153-field-help-on-inline-help-text.md 改的那一句。
  • 两分钟验证:pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/system/i18n-resolver.test.ts,应看到 383 条全过。
  • 需要你做的:无,席位落地。

What changes

translateObject (packages/spec/src/system/i18n-resolver.ts) serves a field's objects.OBJECT.fields.FIELD.help translation on ONE slot, the one the i18n extractor seeded the entry from (seat direction A on #29286, no new public name):

  • a field whose served def authors a non-empty inlineHelpText gets the translation there, under the per-slot divergence rule as before, and keeps its source-language description; a field with only inlineHelpText gains no description;
  • description takes the translation only when neither the served field nor the packaged field authors a non-empty inlineHelpText (an empty string reads as absent, as in the extractor and the console), and still only while it equals the packaged field's description (valueOverridesPackagedBase, unchanged);
  • the packaged leg: a served inlineHelpText blanked over a packaged one leaves an entry that still translates the packaged inlineHelpText, so description stays in its source language. With no packaged base, only the served field is asked.

The rule lives in one new private helper, authorsInlineHelpText(field), asked of the served and the packaged field. The translateObject docblock section is rewritten to state it, and the ObjectFieldLike docblock no longer states the old both-slots rule.

S1. ObjectFieldLike declares inlineHelpText?: string beside inlineTitle. It was reached only through the index signature.

S2. The source-locale CONTROL test could not fail: the en bundle's lead_score.help repeated the authored text, so serving it and leaving the field untouched gave the same answer. The en help entry is dropped (a comment says why), and the test is renamed to what it pins now: the source locale, with no help entry for the field while zh-CN has one, serves the authored inlineHelpText and never another locale's. Ablation below.

Pending changeset corrected. .changeset/29153-field-help-on-inline-help-text.md (unreleased, from PR #29217) said the translation is served on inlineHelpText "and on description as before". This PR makes that false, so its Now. bullet is corrected in the same stroke. check-empty-changeset.mjs refuses this by design as the DELIBERATE CORRECTION class: please confirm it on the PR; do not restore the old sentence. The new changeset is .changeset/29286-field-help-description-slot.md (spec patch).

Forced test edits (old behaviour pinned)

All in packages/spec/src/system/i18n-resolver.test.ts:

  1. a field declaring both description and inlineHelpText gets the translation on both… (fixture phone) now asserts description stays Contact number.; renamed to …gets the translation on inlineHelpText only, the slot the entry was seeded from.
  2. keeps a description that diverged…: the per-field sibling assertion moves from phone.description to phone.inlineHelpText.
  3. judges an array-shaped field list…: the same move for phone.
  4. serves the showcase lead_score translation on its authored inlineHelpText…: asserts lead_score gains no description (was the translation).
  5. The S2 CONTROL above (bundle fixture and name).

New tests (fixture vat_number, authoring both texts): the zh-CN read keeps description; the same with no packaged base; a served inlineHelpText blanked over the packaged one keeps description.

Tests

All readings at head b639a5b4, on objectstack-ai/objectstack, merge base 5a2bdf9c1.

  • Red first, on the base. The three new vat_number tests plus a lead_score gains-no-description test, run against the unfixed resolver: Tests 4 failed | 11 passed in the …reaches the slot the console draws first describe (expected '个人客户请留空。' to be 'Tax id used on invoices.').
  • pnpm --filter @objectstack/spec exec vitest run --maxWorkers=2 src/system/i18n-resolver.test.ts: Tests 383 passed (383).
  • pnpm --filter @objectstack/spec test (under os-verify-lock, VERDICT command-exit 0): Test Files 791 passed (791), Tests 23394 passed | 1 todo.
  • pnpm --filter @objectstack/spec typecheck: VERDICT command-exit 0 (test layer: 52 files / 240 errors held in test-typecheck-debt.json, unchanged).
  • pnpm --filter @objectstack/spec check:generated: All 14 generated artifacts are up to date. Nothing to regenerate: no schema, .describe() or export changed.
  • Consumer pnpm --filter @objectstack/rest test (the served object reads, meta-item-read-gate.ts / form-routes.ts, run translateObject): Test Files 368 passed (368), Tests 6982 passed | 332 skipped.
Ablations (one-shot, through scripts/ablation-replace.mjs, restored to the HEAD blob)

Spec tests import the resolver from src/, so no dist leg applies.

  1. S2 CONTROL can fail now, and could not before. Mutation: if (translatedHelp) { becomes if (true as boolean) { (the no-entry guard dropped; anchor 1 to 0, blob 848830f5 to 5ad5b046).
    • New CONTROL: × CONTROL: the source locale, which carries no help entry… (Tests 1 failed).
    • The base's CONTROL (git show 5a2bdf9c:…/i18n-resolver.test.ts as a temporary copy, deleted after), same mutation: Tests 1 passed. Its en entry repeated the authored text, so the mutation was invisible to it.
    • Restored: blob == HEAD, git diff HEAD empty.
  2. The packaged leg is pinned. Mutation: !authorsInlineHelpText(packagedField) && becomes true &&. Result: × a served inlineHelpText blanked over a packaged one still keeps description in its source language (1 failed | 12 passed). Restored: blob == HEAD.

Acceptance notes

  • Equal texts: a field whose inlineHelpText and description are the same string now keeps its source-language description, although the entry translates that same text. The seat's rule is applied as written; whether to also translate description when it equals the seeded text is in the report's open questions.
  • Option B (a description-specific bundle key) is a new contract key and is not this PR.

Verification

Derived gate families: 79 derived, 79 run, 78 exit 0, 1 designed red

node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack at b639a5b4 (4 paths vs merge base 5a2bdf9c1), each command run with stdin closed, then --ran:

✓ dispatch-gates --ran: 79 derived famil(ies) accounted for — 79 run, 0 NOT-MEASURED (a DERIVED zero — all 79 recorded an exit code and none of them is 3).

The one non-zero exit is node scripts/check-empty-changeset.mjs --base origin/main :: exit 1, the DELIBERATE CORRECTION refusal for .changeset/29153-field-help-on-inline-help-text.md described above. It is red by design; do not restore the old sentence.

Offline PR-body check: node scripts/check-changeset-no-major.mjs --base origin/main --event FILE with this body: ✓ This diff introduces no major bump, ✓ LEVEL AXIS: … clause-② no and metadata-protocol none … a non-protocol change at patch.

Dogfood: not run. The title has no ! and Clause-②: has no (narrowing) arm.


Generated by Claude Code

… description

translateObject served a field's `help` translation on `description` and
on an authored `inlineHelpText`. The extractor seeds that entry from
`help ?? inlineHelpText ?? description`, so on a field authoring both
texts every reader of `description` showed the inlineHelpText's
translation. The entry is now served on the one slot it was seeded from:
`inlineHelpText` when the served or packaged field authors a non-empty
one, `description` only otherwise.

Also declares `inlineHelpText` on ObjectFieldLike, and makes the
source-locale CONTROL test able to fail (its `en` help entry repeated
the authored text).

Claude-Session: https://claude.ai/code/session_01ADHkmTFqMHMhCKttxJqEQk
Co-authored-by: Claude <noreply@anthropic.com>
@github-actions github-actions Bot added size/m documentation Improvements or additions to documentation protocol:system tests tooling labels Nov 2, 2026
@github-actions

github-actions Bot commented Nov 2, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 1 package(s): @objectstack/spec, touching 5 documentable anchor(s).

6 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:

  • content/docs/automation/flows.mdx (via inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))
  • content/docs/data-modeling/field-types.mdx (via inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))
  • content/docs/data-modeling/fields.mdx (via inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))
  • content/docs/data-modeling/object-extensions.mdx (via inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))
  • content/docs/getting-started/quick-reference.mdx (via inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))
  • content/docs/ui/translations.mdx (via inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))

⛔ 3 release-owned page(s) also name something this change touched. These are read-only:

  • content/docs/releases/v17/17-5.mdx (via inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))
  • content/docs/releases/v17/17-7.mdx (via ObjectFieldLike (symbol, a top-level interface), inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))
  • content/docs/releases/v18/18-2.mdx (via inlineHelpText (symbol, a field of interface ObjectFieldLike), inlineHelpText (literal, a string literal in translateObject))

content/docs/releases/ is RELEASE-OWNED (AGENTS.md "Documentation Guardrails"): release
notes are written centrally at release time, and a code PR that edits them is the exact PR
that guardrail exists to stop. They are still audited — read-only. If one of them is actually
wrong, file an issue or open a dedicated docs-only PR; do not edit it here.

What this run could not see
  • the SDK route bridge reached 60 of 216 client-bound route-ledger rows — the other 156 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 156: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 101 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 168 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5924e5002f4a38346ad435514a1282312927658b → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 5320b2addc210077072a7a2a15002653cacd0994 — the merge of head 320fead6d983a0d843b2a2c04acad038024a29b1 into base 5924e5002f4a38346ad435514a1282312927658b, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 5320b2addc210077072a7a2a15002653cacd0994 && git checkout 5320b2addc210077072a7a2a15002653cacd0994
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 5924e5002f4a38346ad435514a1282312927658b 320fead6d983a0d843b2a2c04acad038024a29b1 && git checkout -B drift-repro 5924e5002f4a38346ad435514a1282312927658b && git merge --no-ff 320fead6d983a0d843b2a2c04acad038024a29b1

node scripts/docs-audit/affected-docs.mjs --json 5924e5002f4a38346ad435514a1282312927658b

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

Advisory only, and a precision-first one (#9192): a page is listed because it names a
symbol, wire route or SDK method this diff touched — not because it mentions a changed
package. Each row says which anchor put it there, so a wrong row is reportable rather than
merely annoying. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs 5924e5002f4a38346ad435514a1282312927658b → pass the list as
args.docs, on the commit named under Which tree this was computed on.

…read

The Before. bullet described an unreleased state; both notes publish in
the same release, so it now states what released 18.2.0 serves.

Claude-Session: https://claude.ai/code/session_01ADHkmTFqMHMhCKttxJqEQk
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Head-sha: 320fead6 · read 2026-11-02T13:56Z

维护者速读

  • 改了什么:字段帮助文字的翻译只落一个槽:字段写了非空 inlineHelpText 时只翻它,description 保留原文;否则照旧翻 description。
  • 为什么改:18.2.0 里同时写两段文字的字段,在 Studio 和设计器里 description 显示的是另一句话的译文(spec(i18n-resolver): a field that authors both inlineHelpText and a different description gets the inlineHelpText translation on description #29286)。
  • 风险与回滚:只改服务端输出,无 schema、键、导出变化(spec patch)。回滚即撤销本 PR。
  • 先看:packages/spec/src/system/i18n-resolver.ts 的 translateObject 帮助分支。
  • 两分钟验证:pnpm --filter @objectstack/spec exec vitest run src/system/i18n-resolver.test.ts。
  • 需要你做的:无,席位落地。

席位意见:可落地。

席位核对 — ACCEPT · domain:spec#1 · head 320fead6

  1. Shape: draft, base main, Fixes #29286, Clause-②: no / Metadata-protocol: none at line start in the body and the changeset (spec patch). Within claim 6576682789. Not governed.
  2. Diff, read on the head: translateObject serves the field help translation on one slot: on inlineHelpText when the field (or its packaged base) authors a non-empty one, leaving description in source; otherwise on description as before. ObjectFieldLike declares inlineHelpText?: string (S1). The CONTROL test can now fail (its en help entry is gone; S2, proved by one ablation).
  3. Deviations accepted: (1) the pending .changeset/29153-field-help-on-inline-help-text.md "Now." bullet is corrected for the same release. This is the deliberate-correction class: Check Changeset is red by design on every head, it is not a required context, and the seat confirms the correction here. (2) The guard also reads the packaged field. (3) The merged tree was measured in a side worktree. (4) No MCP writes. Open questions: both answered A by the seat.
  4. Readings: red on base (4 failed), spec 23394 passed, typecheck 0, check:generated current, rest 6982 passed; 79/79 derived gates with one designed red. Check-runs on 320fead6: 54 success, 9 skipped, 1 failure (Check Changeset, by design); every required context green.
  5. Landing: CONTRACT_REVIEW_TIER review PASS on b639a5b4 and a delta PASS on 320fead6 (records follow). The seat readies and queues.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Contract-review-claim: session_01ADHkmPi25XXKx92Xmg4viS · head 320fead · 2026-11-02T13:57Z

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

Contract review

Served-tier: CONTRACT_REVIEW_TIER
Head-sha: 320fead6d983a0d843b2a2c04acad038024a29b1
Local-runs: none
Scope: packages/spec/src/system/i18n-resolver.ts + packages/spec/src/system/i18n-resolver.test.ts, .changeset/29286-field-help-description-slot.md, .changeset/29153-field-help-on-inline-help-text.md, packages/cli/src/utils/i18n-extract.ts (the help seed, on origin/main after PR #29280 and at the released 18.2.0), ui/packages/fields/src/fieldHelpText.ts (the console's help line), ui/packages/app-shell/src/views/metadata-admin/inspectors/ObjectFieldInspector.tsx (the Studio reader of description), PR #29217's merged change (20f052d0), the @objectstack/spec@18.2.0 tag commit (27f38ada), docs/adr/0029 D9.2a, scripts/check-empty-changeset.mjs (the DELIBERATE CORRECTION class)

Delta review over the head reviewed at b639a5b4 (PASS, one should-fix). This head is one commit over it, docs(changeset): state the description-slot fix against the released read, touching only .changeset/29286-field-help-description-slot.md (1 insertion, 1 deletion). The resolver, the test file and the corrected 29153 note are byte-identical to the reviewed head (blobs 848830f5, 6ee5ef93, 587d4937), so every judgment of the first record on served output, tests, deviations and open questions stands on this head and is restated below in brief. Inputs: card #29286 body and every comment (triage 6575749810, the seat's claim 6576682789 with direction A, the dev report 6577888705); PR #29363 body, file list and net diff against origin/main (eef116e4, merge base 5a2bdf9c; 4 files, +119 / -35); the 64 check-runs on this head, complete at 2026-11-02T13:54Z. Read-only: nothing built, run or re-run.

① Derived judgments

The delta — the "Before." bullet of .changeset/29286-field-help-description-slot.md, now: "The translation was served on description. The extractor scaffolds the entry from help ?? inlineHelpText ?? description, so on a field that authors both a non-empty inlineHelpText and a different description, the entry translates the inlineHelpText, and every reader of description (Studio, the designer) showed that other sentence's translation." Judged against the released read, at the @objectstack/spec@18.2.0 tag commit (27f38ada; neither PR #29217 20f052d0 nor PR #29280 6dd6a534 is an ancestor of it, so 18.2.0 is the state before both):

  • the released translateObject served the field help entry on description alone (if (!valueOverridesPackagedBase(..., 'description', def.description)) { … lookupObjectFieldAttr(..., 'help', opts) … next.description = … }), and on no other slot — "served on description" is TRUE, and dropping the former "too" removes the reference to the unreleased intermediate state;
  • the released extractor seeded the entry from field.help ?? field.inlineHelpText ?? field.description, the exact spelling the bullet quotes (on origin/main it is the same order through asAuthoredLabel, which differs only on an empty string, and the bullet speaks of a non-empty inlineHelpText) — TRUE;
  • so on a field authoring both texts the entry was the inlineHelpText's translation and landed on description, where the Studio inspector reads def.description raw — TRUE; the card's defect existed in 18.2.0, and the bullet now says so about the released state rather than about the post-fix(spec): serve a field's translated help on its authored inlineHelpText #29217 tree.

Consistency with the corrected 29153 note (unchanged on this head). Both "Before." bullets describe 18.2.0 from the two readers' sides: 29153 from the console's (the inlineHelpText masked the translation served on description), 29286 from Studio's (description showed another sentence's translation). Both "Now." bullets state the one rule on this tree: the entry is served on an authored non-empty inlineHelpText, description keeps its source text, and description takes the entry only when no inlineHelpText is authored (29286 adds the packaged-side half). No sentence in either note contradicts the other or the tree; publishing both in one release reads as one change told twice from two surfaces, not as a reversal.

Carried forward from the record at b639a5b4, re-read on this head's identical code and tests: a field authoring a non-empty inlineHelpText keeps its source description (the description write is unreachable in that branch); a field with only inlineHelpText gains no description; a field with only description is translated there as before, behind the unchanged valueOverridesPackagedBase; '' reads as absent in resolver, console and the extractor on origin/main; the packaged-field guard keeps description in source when a served inlineHelpText is blanked over a packaged one (pinned by test and ablation 2); a tenant-ADDED inlineHelpText over a packaged field that had none now leaves description untranslated where main translated it — accepted under the seat's answer A to open question 2, failure mode "left untranslated", never "wrong sentence"; a locale with no help entry and the source locale leave both slots untouched, and the rewritten en CONTROL can fail; help is never served; ADR-0029 D9.2a stays one comparison; S1 and S2 done; the four deviations accepted as before; both open questions implemented as the seat's A (equal texts kept strict).

Check-runs on this head, complete at 2026-11-02T13:54Z: 64 total, 54 success, 9 skipped, 1 failure. The failure is Check Changeset at 2026-11-02T13:30:08Z, the #17712 foreign-changeset refusal on .changeset/29153-field-help-on-inline-help-text.md printed with the DELIBERATE CORRECTION remedy — red by design on every head of this PR, and not one of the ten required contexts. The ten required contexts: Lint & Repo Gates, TypeScript Type Check, Test Core (8/8 shards and the aggregate, the last at 2026-11-02T13:53:24Z), Build Core, Governed Surface Queue Guard, Type Check UI, Test UI (16/16 and the aggregate), Build & E2E UI, Live E2E UI all success; Lint UI skipped by the path filter (no ui/ path in the diff).

② Semver level

@objectstack/spec: patch. Unchanged from the first record: a served-read change with no Zod schema, .describe() or export touched (check:generated green in TypeScript Type Check); Clause-②: no and Metadata-protocol: none line-initial on the PR body and in the new changeset. Agreed.

The deliberate correction of the pending .changeset/29153-field-help-on-inline-help-text.md is unchanged on this head and still true on this tree ("…is served the translation there, the text the entry was scaffolded from, and keeps its source-language description"); the note is pending (present on the merge base; spec at 18.2.0, PR #29217 merged after the last CHANGELOG.md write). Confirmed here as the check-empty-changeset remedy prescribes. Do not restore the old sentence.

③ Boundary flags

  • No governed surface in the file list (Governed Surface Queue Guard success); no ui/ path; 154 changed lines.
  • Spec face: the published translateObject and the exported ObjectFieldLike type (one added optional key on an interface with an index signature; api-surface unchanged). No metadata-protocol, no ADR-0087 entry owed.
  • Extractor untouched, as the claim's file surface required. The 29286 "Before." quotes the released ?? chain; the resolver docblock's "an empty string reading as absent" describes the extractor on origin/main (PR fix(cli): os i18n extract seeds a field help entry from its description when inlineHelpText is empty #29280) — each true of the tree it names.
  • Release-owned content/docs/releases/v17/17-7.mdx ("served on description") stays as 17.7 shipped; not this PR's to edit.

④ Design judgment

hits: packages/spec/src/system/i18n-resolver.ts, byte-identical to the head judged PASS. The change holds against the code it cites — the extractor's first-authored-link seed, the console's inlineHelpText || description, and the Studio inspector's raw read of description — with one rule stated once in the docblock, once in authorsInlineHelpText, and asked of both the served and the packaged field, so no packaged-vs-served edge can put another sentence's translation on description. The break attempts of the first record (equal texts; '' over absent; '' over a packaged inlineHelpText; a tenant-added inlineHelpText over none; no packaged base; an undeclared field; array-shaped fields; a no-entry locale and the source locale; the fallback chain) surfaced no wrong sentence and no undeclared key, and nothing in this delta changes a served byte. The delta itself does what the should-fix asked: the release note now describes the released state, so the two notes that publish together tell one consistent story.

Findings:

  • The should-fix of the record at b639a5b4 is resolved by this head.
  • No must-fix. No should-fix.

Implemented-by: claude/project-thread-s6t212
Reviewed-by: session_01ADHkmPi25XXKx92Xmg4viS

VERDICT: PASS

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review November 2, 2026 13:58
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Nov 2, 2026
Merged via the queue into main with commit a20dcae Nov 2, 2026
64 of 65 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-s6t212 branch November 2, 2026 14:22
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:system size/m tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

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

1 participant