fix(platform-objects): re-translate the metadata-form leaves that contradict their current en source - #20707
Conversation
…tradict their current en source Twelve authored ja-JP / es-ES / zh-CN leaves in the metadata-forms bundles said what a superseded English source said: the agent Capabilities section still offered tools, the permission-set Tab & Row-Level Security section still offered custom context variables (zh-CN named it after sharing rules), the report blocks help still described a join of several objects, the email-template Identity section still sent the template by id with a content type, and the zh-CN Joined blocks label named related objects. Values only; no key added or dropped, no en file or provenance table edited. Claude-Session: https://claude.ai/code/session_01DEvba2nBuD4tWzfq8r8NFY Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 3 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 7aa799e489a4c8adbc6f0da95bbc4d8a323cd705 && git checkout 7aa799e489a4c8adbc6f0da95bbc4d8a323cd705
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin defc7f7b504e22b9e2c12a5374ebb255efe9b7da aaee46778305b33d8afaf19c8243ccc930d04840 && git checkout -B drift-repro defc7f7b504e22b9e2c12a5374ebb255efe9b7da && git merge --no-ff aaee46778305b33d8afaf19c8243ccc930d04840
node scripts/docs-audit/affected-docs.mjs --json defc7f7b504e22b9e2c12a5374ebb255efe9b7da
|
Contract reviewServed-tier: Read: card #20666 (body and all four comments: triage 5893971675, the widening-check note 5894872722, the claim 5896670403, the os-dev-report 5897252407), PR #20707 (body, file list, Check-runs on the head, read once, not polled: 31 runs, 0 failed. Completed 19: 16 success (Auto Label, Dogfood Verify CLI, Build Core, Type Check debt ledger, Governed Surface Queue Guard, single-writer path, Type Check consumer gates, Flag docs, Type Check source gates, filter, card-claims-branch, single-issue, Check PR Size, Part-of, Check Changeset, Check Documentation Links), 3 skipped (Console Pin Gate, Build Docs, Packed-tarball smoke, all opt-in or path-gated). Still ① Derived judgmentsAccept-set: no change — right. The diff touches no schema, no form declaration and no Public surface: 12 customer-visible runtime strings in a released package — right to publish under a changeset.
No new value byte-equals its Stale-but-not-contradicting leaves left as written — right on each. Read against Ruling compliance: values only ✓; only contradicting leaves ✓; title-case ruling honoured ✓; no new gate (no script, test or workflow in the file list) ✓; file surface as claimed (5896670403) ✓: not the object bundles, not the plugin bundles, not PR body, factual sentences: line numbers (2251, 2347, 1856, 2151, 1801) true; 12 = 4 + 4 + 4 true; 1116 leaves per locale true; 69 / 70 / 70 first-parent commits per translated bundle before this PR and 56 for ② Semver level
③ Boundary flags
Nothing escalated. No FAIL item. Implemented-by: VERDICT: PASS Generated by Claude Code |
Fixes #20666
Clause-②: no
What changed
A translated leaf in
packages/platform-objects/src/apps/translations/{ja-JP,es-ES,zh-CN}.metadata-forms.generated.tsthat a translator wrote by hand keeps its value when itsensource changes later. This PR measures that set first, with PR #20652's instrument and the two widening checks the services seat named, then re-translates the leaves whose meaning now contradicts the currenten: 12 leaves (ja-JP 4, es-ES 4, zh-CN 4).enfile is edited, and no provenance companion or echo-decision ledger changes (measured below; the tooling requires none)..changeset/20666-stale-authored-metadata-form-leaves.md:@objectstack/platform-objectspatch.metadata-formsbundles and the changeset. Not the object bundles, not the plugin bundles, and not{en,ja-JP,es-ES,zh-CN}.tsor*.source-hashes.ts(PR fix(platform-objects,plugin-audit): nav entries for the console's Audit Log and Integrations & APIs pages #20699).The measurement (base
a8acee28d, before any edit)Instruments
The clone is not shallow (
git rev-parse --is-shallow-repositoryanswersfalse, 15122 commits), so every walk below reads full history.objects.generated.tsbecomesmetadata-forms.generated.ts, and the recorded-copy test reads"metadataForms.PATH"in bothLOCALE.source-hashes.generated.tsandLOCALE.source-hashes.ts). Population: every string leaf of the locale's metadata-forms bundle, minus echoes of the currentenand recorded byte copies. Last edit: the first-parent commit where the parsed value last changed. A leaf is a candidate whenenat that commit differs fromentoday. Meaning is then judged by hand.enat the old path's last edit is compared withenat the new path today.enat its previous edit, and whetherenmoved in the last-edit commit itself. Every flag was read by hand, including the ones whereenmoved in the same commit.enis also read at the second parent.project,department,role(ADR-0090) orprofile(ADR-0090 D2), whereenat the same path does not carry the English term. The raw ja-JProlepattern hit four leaves, all false positives (ロールアップ roll-up three times, コントロール control once); the refined pattern excludes both and hits 0.enat the same path does not carry it: agent tools (ADR-0109 removedagent.tools[], scopeagent.*);PermissionSet.contextVariables(removed by the ADR-0105 commit879ea1304); sharing rules named for RLS; an email template sent byidwith a content type (47a92f427re-modelled the type); a report block that joins objects (ADR-0021 dataset-bound reports,18178454c, scopereport.*).e0077ea36were carried in from a hand overlay,packages/platform-objects/src/metadata-translations/zh-CN.ts, born atdc721729aand consolidated ate0077ea36the same day. So the instrument dates them at the carve-in. Between those two commitspackages/spec/srcchanged no form label, description or help string (git diff dc721729a e0077ea36 -- packages/spec/src: two changedlabel/descriptionlines, both schema declarations, no string). The carve-in dating therefore hides no source move inside the overlay's lifetime.Known-positive controls
permission.sections.tab_and_row_level_security.description(line 2251 of all four bundles) andagent.sections.capabilities.description(line 2347). The since-last-edit instrument flags both in all three locales. In ja-JP and es-ES both promise whatendropped (custom context variables; tools). zh-CN's agent leaf promises tools too, but zh-CN's permission leaf never promised context variables: it names the section after sharing rules, read below.dashboard.fields.refreshIntervalSeconds.label, renamed fromrefreshIntervalate9fcd6bbdwith the value carried. It fires in all three locales.agent.sections.capabilities.descriptionset to theenstring,check-i18n-bundles --filter=platform-objectsgoes red,platform-objects DRIFTED (1)(throughscripts/ablation-replace.mjs: anchor 1 to 0, blob1b912e07c279to70cb7a0e1ba3, restored: blob equals HEAD andgit diff HEADis empty). In hold mode,--writeadds exactly one row,"metadataForms.agent.sections.capabilities.description", toja-JP.source-hashes.generated.ts. Both files were restored withgit checkout HEAD --, and their blobs equal HEAD's (1b912e07c279,2429910c839c).Population and radius
metadata-formsbundles of@objectstack/platform-objectsfor ja-JP, es-ES and zh-CN. There are 1116 leaves per locale. Echoes of the currentennumber 0 / 0 / 0, recorded byte copies 0, and authored leaves 1116 / 1116 / 1116. History: every first-parent commit since the bundles were created atae2da1e7d(69 / 70 / 70 commits touching each locale file, 56 foren), plus the zh-CN overlay's lifetime (instrument 7).ennever moved, outside the vocabularies of instruments 5 and 6; where the zh-CN overlay's strings came from beforedc721729a(the file was born with them); the object bundles, the plugin bundles and the other packages' bundle sets.Counts per locale
enmoved since last edit), beforeaaee46778)The raw candidate counts equal the #20653 dev's 9 / 9 / 6 exactly. After, both walks re-run at
aaee46778: each after-candidate set is exactly the before set minus the re-translated paths (0 added), the echo count is still 0 (no new value equals itsenleaf), and the renamed-key flag is the same one. The penultimate-edit flags after are the before set plus the 11 re-translated candidates (their last edit is now this PR, afterenmoved), which is the expected shape.The judgment rule
As in PR #20652 and PR #20684. A leaf contradicts the current
enwhen a reader who acts on it would believe something about the current form thatennow says is false:ennow denies what the leaf asserts; the type was re-modelled, so the leaf describes a different thing; or the leaf names a mechanism the section does not hold. Added detail, narrowing, rewording, punctuation and title-casing are not contradictions.Re-translated (12): before and after
agent.sections.capabilities.description, all three. ADR-0109 removedagent.tools[](e2616e0cf); an agent's tools come from its skills.en:Skills and knowledge sources the agent can use.permission.sections.tab_and_row_level_security.description, all three.879ea1304removedPermissionSet.contextVariables(enforce-or-remove, zero consumers) and its form row.en:Tab visibility and RLS policies.sys_sharing_ruleobject (plugin-sharing) and its own Setup entrynav_sharing_rules. The section holdstabPermissionsandrowLevelSecurity. The new value uses the bundle's own words: 标签页 (this section's label), 行级安全策略 (the bundle's rendering of an RLS policy, as inobject.fields["access.default"].helpText).report.fields.blocks.helpText, all three. The 9.0 single-form cutover (ADR-0021,18178454c) made every report block a dataset-bound sub-report; no block joins objects.en:Dataset-bound sub-reports (joined report only)email_template.sections.identity.description, ja-JP and es-ES.47a92f427promotedemail_templateto a first-class metadata type and rewrote its form. The Identity section now holdsname/label/category/locale/description, with noidand no content type, andIEmailService.sendTemplateresolves the template byname. A reader who copied the old sample would passtemplate: id. zh-CN already said whatensays.en:Template identifier resolved by IEmailService.sendTemplate({ template: name, locale, ... }).report.sections.joined_blocks.label, zh-CN only. It was found by the retired-concept scan, not by the since-last-edit instrument, becauseen(Joined blocks) never moved. The zh-CN label said 关联对象 ("related objects"), the pre-9.0 model in which blocks joined objects. The section holds theblocksrepeater of dataset-bound sub-reports. ja-JP 結合ブロック and es-ES Bloques unidos renderenliterally and are unchanged.report.fields.blocks.label, andjoinedstays the report-type token, as in 仅 joined 报表).Stale but not contradicting (listed, left as written)
endidobject.sections.fields.description9f8ec35c8). Rewording.hook.fields.condition.helpText48efe915b, which changed the row's editor language fromjavascripttoexpression). The runtime gate isif (!conditionFn(ctx))inpackages/objectql/src/hook-wrappers.ts, whose own docblock says "skip when the formula evaluates FALSE", and the leaf makes no JavaScript claim. This is the closest call among the leaves left alone.app.fields.defaultAgent.helpTextask/builddefaults added. Narrowing and detail. zh-CN already says whatensays.report.sections.joined_blocks.descriptionenlabel still says Joined blocks. The second closest call. zh-CN already says whatensays.report.sections.filter_and_chart.descriptiondashboard.fields.refreshIntervalSeconds.label(renamed key)helpTexton the same field already says seconds (自動更新(秒), Actualización automática (segundos), 自动刷新间隔(秒)).Penultimate-edit flags, all read by hand. Every one already says what
ensays:enmoved EARLIER than the last edit:object.fields.isSystem.helpText,object.fields.fields.reference.helpText,object.fields.fields.trackHistory.helpText,view.fields.filter.helpText,page.fields.type.helpText,dashboard.fields.gap.helpText,action.sections.advanced.description,action.fields.body.helpText,report.sections.basics.description,report.fields.columns.helpTextanddataset.fields.measures.helpText(all three locales); plus, zh-CN only,app.fields.defaultAgent.helpText,report.sections.joined_blocks.description,email_template.sections.identity.descriptionandemail_template.fields.variables.helpText.enmoved IN the last-edit commit:object.fields.indexes.fields.helpText,field.fields.precision.helpText,field.fields.maskingRule.helpText,page.fields.variables.source.label,app.sections.content.description,app.sections.access_and_sharing.descriptionandpermission.sections.identity.description(all three locales).Dispatch hypotheses, measured
en.metadata-forms.generated.ts. Both known leaves are candidates in all three locales, and the raw counts reproduce as 9 / 9 / 6 ata8acee28d. Judged, 4 / 4 / 3 contradict. Two more paths besides the known two contradict:report.fields.blocks.helpText(all three) andemail_template.sections.identity.description(ja-JP, es-ES). zh-CN's permission leaf contradicts for a different reason than the known one (sharing rules). The retired-concept scan added one zh-CN label.collectFilledFromHashesrecords ametadataFormsleaf only while it is a byte copy of the currentenor of a recorded digest. Today that is 0 rows in all three locales, and a hand translation records nothing. Ataaee46778,node scripts/check-i18n-bundles.mjs --write --filter=platform-objectsprintedregeneratedand rewrote all eleven bundle and companion files on disk (every mtime moved), andgit status --porcelainstayed empty. The control that shows the tool really reads these leaves is in "Known-positive controls" above. No echo-decision ledger row and no test names any of the 12 paths (git grepover the ledgers).metadata-forms-vocabulary.test.tsasserts group keys only.dashboard.fields.refreshIntervalSeconds.label), stale but not contradicting. Penultimate edit: 18 / 18 / 22 flags, 0 contradicting.Verification (all at
aaee46778)turbo run build --filter=@objectstack/cli... --filter=@objectstack/platform-objects... --concurrency=2: 59/59 tasks,VERDICT command-exit 0.pnpm --filter @objectstack/platform-objects test: 58 files, 942 tests passed.pnpm --filter @objectstack/platform-objects typecheck: exit 0,check:test-typecheck: OK.dist/metadata-translations/index.mjsandindex.jswere imported, andMetadataFormsTranslationswas read by path afterwithSourceFallback. In both, 12 of 12 re-translated rows equal the HEAD source and differ from the base, and 9 of 9 unchanged-leaf controls equal both.node scripts/pm/dispatch-gates.mjs --commands(no paths) derived 55 commands from the real diff, and all 55 exit 0.--ranprinted "55 derived famil(ies) accounted for — 55 run, 0 NOT-MEASURED (a DERIVED zero — all 55 recorded an exit code and none of them is 3)".pnpm check:dual-build-cjs-loadsfirst refused with exit 3 (PREREQUISITE NOT MET: nine packages outside this diff had nodist/). Those were built and the gate re-ran: exit 0.check:i18n"OK (9 package(s) — all bundles in sync, no undeclared authoring keys)";check:i18n-stale-fill"OK (10 bundle set(s) — no new stale fills, 0 baselined)";check:nul-bytesexit 0.eslint --no-inline-config --format jsonread 3 files, 0 errors, 0 warnings.ESLint#isPathIgnoredanswersfalsefor all three, read from the repo's own config. The config enables no type-aware linting (noparserOptions.projectorprojectService,eslint.config.mjsstates it at line 328), so a change to string values in these files cannot move the verdict on any other file. The fullpnpm lintis left to CI.origin/mainmoved two commits past the base (defc7f7b5). Neither touches a form declaration or a translation bundle, so the measurement stands on it.Acceptance notes
dataset-panel-echo-decisions.test.ts, the reason on theincludelabel row, cites "report.sections.joined_blocks.label is 关联对象" as a precedent for the word 关联. After this PR that label reads joined 报表分块, so the citation is out of date. It is prose: no assertion reads it, and theincludedecision stands on its own, since 关联 keeps authored precedents such assys_email.fields.related_object.label关联对象 in the objects bundle. The ledger is outside this card's file surface and is not edited here.page.sections.data_context.descriptionreads 关联对象与变量 ("related objects and variables") againsten"Record binding and page-local state." It is loose but does not contradict: the bound record's object is the related object, and the variables are the page-local state. No instrument flags it, and it is left as written.ennever moved. Instruments 5 and 6 cover only the vocabularies they name. Instruments were run from the session scratchpad.Generated by Claude Code