docs(adr): record that author-written validation-rule messages are translatable again (ADR-0049 amendment) - #15438
Merged
os-zhuang merged 1 commit intoSep 5, 2026
Conversation
…able again
ADR-0049 gets a status-line note and a dated amendment recording that an
author-written validation rule's `message` became translatable in 17.3.0
under the object-scoped bundle key
`objects.<object_name>._validations.<rule_name>.message` — the enforce-or-remove
gate being enforced, not reversed. The 17.0.0 retirement of the top-level
`validationMessages` group stands and the two are not the same route.
`content/docs/ui/translations.mdx` carried the sentence that change falsified
("Validation messages are not translated through bundles"). The surface table
gains the `_validations` row and the boundary bullet is rewritten to the limit
that is actually current: the authored sentence is substituted whole, with no
interpolation.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G4138K1EG7kQ81FNba5Kp4
This was referenced Sep 4, 2026
os-zhuang
approved these changes
Sep 5, 2026
os-zhuang
marked this pull request as ready for review
September 5, 2026 01:30
This was referenced Sep 5, 2026
os-zhuang
approved these changes
Sep 5, 2026
os-zhuang
deleted the
claude/issue-14402-adr-0049-validation-message-record
branch
September 5, 2026 03:56
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #14402
docs/adr/**is a governed surface (Prime Directive #14). No agent seat marks this PR ready, queues it, arms auto-merge on it, or approves it. A human merges it, and that merge is the review record. It is left as a draft deliberately; a draft here is the finished state of the task, not an unfinished one.What this records
PR #14381 (issue #14253) gave an author-written validation rule's
messagea bundle key,objects.OBJECT._validations.RULE.message, with its reader on the write path in the same change. That made a recorded 17.0.0 sentence false, and until now the only trace of the decision it falsified was a retired-key tombstone and a changeset — the shape Prime Directive #13 warns is easy to miss.The ruling being recorded was settled on #14381 and is not reopened here: this is ADR-0049 being enforced, not reversed. The 17.0.0 retirement of the top-level
validationMessagesgroup (#4667) stands, and the two are not the same route.Form: amended in place, no new ADR
House convention left the choice of form to the
domain:specseat. The seat ruled amend the existing records, on this reasoning: the reader who is harmed is the one who lands on ADR-0049 or on the 17.0.0 retirement sentence and believes it. That reader has no reason to go looking for a new ADR, so a new document would leave the false sentence sitting exactly where it is read. Amending puts the correction on the path the misled reader is already walking, and it is the non-proliferating option.Two sites, and the second is the one that carried the falsehood
1.
docs/adr/0049-no-unenforced-security-properties.md— a status-line note plus a dated## Amendment (2026-09-04)section in this repo's existing amendment shape (ADR-0045 is the worked example). It carries the card's four-bullet reasoning, all four verified againstmainrather than restated:validationMessageswas removed because nothing read it;packages/objectql/src/validation/rule-validator.ts#authoredRuleMessage, over the existingValidationMessageContext.translatehook (Field validation messages are hardcoded English + API field name —penalty_amount must be ≥ 0reaches end users verbatim #3957);packages/spec/src/system/i18n-resolver.ts#objectValidationMessageKey;The amendment also carries a scope note, because measurement contradicted the routing premise in a way worth recording rather than papering over: ADR-0049's own text is scoped to security properties, and its Non-goals place the non-security clusters elsewhere —
validationMessagesis a translation key. The record still lands here because the repo cites this ADR as the enforce-or-remove policy for spec-property retirement generally, including in the prescription an author sees on writing the retired key (packages/spec/src/system/translation.zod.ts#TRANSLATION_KEY_GUIDANCE). The amendment says explicitly that no new scope is claimed for the ADR.2.
content/docs/ui/translations.mdx— the only file onmaincarrying the falsified sentence. Under "Current boundaries" it read "Validation messages are not translated through bundles." Replaced with the limit that is actually current — the authored sentence is substituted whole, with no{variable}interpolation, because an authored message has no parameter contract — plus the record of what was retired and why the new route is not it. The "What you can translate" table gains the_validationsrow.Version: 17.3.0, derived not guessed
The card required naming the version #14381 shipped in and the dispatching seat had not measured it.
b2eab95sits under## 17.3.0inpackages/spec/CHANGELOG.md,packages/objectql/CHANGELOG.md,packages/lint/CHANGELOG.mdandpackages/cli/CHANGELOG.md.packages/spec/package.jsonandpackages/objectql/package.jsonboth read17.3.0, so the version bump has landed.@objectstack/spec@17.3.0and@objectstack/objectql@17.3.0exist onorigin.git merge-base --is-ancestor b2eab9594bcb9816e65d834523d286b28f1d6196 refs/tags/@objectstack/spec@17.3.0exits 0 — a positive ancestry read, which is self-proving on a shallow checkout (a control leg on the same target answered 0 as required).Verification — union re-run on the final commit
815478bc6node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackderived the change set from git and named 43 runnable families. All 43 were run against this exact tree, exit codes captured before any pipe, working tree clean:check:doc-formula-expressionsandcheck:doc-security-postureexit 3,check:docs(missingpackages/spec/json-schema) andcheck:skill-examples(missing.d.tsinpackages/spec/dist, then inpackages/client-react/dist) exit 1. Those are NOT MEASURED, not failures. Afterturbo run buildfor@objectstack/spec,@objectstack/lint,@objectstack/formula,@objectstack/client-reactand@objectstack/client(both build runs throughscripts/pm/os-verify-lock.sh, VERDICTcommand-exit 0), all four print their own green verdicts —check:skill-examplesends✅ 257 prose examples type-check across 3 surface(s).check:adr-symbol-anchorsgreen (the two newpath#symbolanchors resolve),check:adr-anchors,check:adr-links,check:doc-authoring,check:docs-single-h1,check:corpus-claim-drift,check:nul-bytes.grep -naPfor control bytes over both changed files: no match.git status --porcelainis empty after the spec build, sogen:schemarewrote nothing that needed committing.Declared narrowing:
pnpm lintThe repo-wide ESLint scan is CI's run. It was narrowed here, and the narrowing is a measurement rather than a skip:
pnpm exec eslint --no-inline-config --format jsonon both changed files returns, for each,"File ignored because no matching configuration was supplied."— ESLint's own resolution, not an assumption about which files count.--format json: 2 results, 0 files linted. Everyfiles:block ineslint.config.mjstargets{ts,tsx,mts,cts,js,jsx,mjs,cjs}; no markdown or MDX processor is configured (package.jsonandeslint.config.mjscontain nomarkdown/mdxentry).git diff --name-only origin/main...HEAD) and contains noeslint.config.mjschange and no file in ESLint's population.eslint.config.mjsdeclares noproject:/projectService:, so type-aware linting is not enabled and no untouched file's verdict can move because of this diff.Changeset
None. This PR publishes nothing from any released package:
docs/adr/**is a governance record andcontent/docs/**feeds the private@objectstack/docssite. Theskip-changesetlabel is applied by this seat, additively, and read back.Out-of-scope findings, filed rather than ridden along
bulkActionsanddatasetsgroups that shipped live in 17.3.0 #15435 — the same guide's "What you can translate" table omits thebulkActionsanddatasetsgroups, the other two surfaces i18n: give bulk-action defs, custom validation messages and dataset labels a bundle key #14381 shipped live in 17.3.0. A different defect (missing inventory, not a false sentence) on the same page.translation-validation-messages-removedmigration text still stops at the authored literal — it never names the object-scoped bundle key that shipped in 17.3.0 #15437 — the ADR-0087 conversion text that renders thetranslation.validationMessagesrow ofdocs/protocol-upgrade-guide.mdstill stops at the authored literal and never names the bundle key, while its sibling prescription intranslation.zod.tsdoes. Lands inpackages/specsource plus a regenerated artifact, so a different gate family.Neither is touched here.
content/docs/releases/is untouched: release notes are written centrally at release time.🤖 Generated with Claude Code
Generated by Claude Code
Generated by Claude Code