fix(plugin-webhooks,plugin-audit,plugin-security): re-translate the object leaves that contradict their current en source - #20684
Conversation
…dict their current en source sys_webhook.fields.definition_json.help told a ja-JP / es-ES / zh-CN admin that the JSON carries the full headers / auth / retry / payload config; en says credentials are NOT stored there (signing_secret and headers_secret are the encrypted fields). sys_webhook.description named an HTTP connector plugin as the executor; en names the webhook auto-enqueuer and the shared HTTP outbox. Values only. Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H Co-authored-by: Claude <noreply@anthropic.com>
…r current en source sys_activity.fields.environment_id.label / .help still named the retired v5.0 term project (ja-JP / es-ES / zh-CN), where en says Environment; the v5.0 rename ships no alias. sys_audit_log.fields.user_id.label still called the sys_user lookup the actor, where en relabelled it User when the object gained its own `actor` principal field (ADR-0014 D2): es-ES showed two fields labelled "Actor", ja-JP / zh-CN two synonyms. Values only. Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H Co-authored-by: Claude <noreply@anthropic.com>
…its current en source The ja-JP / es-ES / zh-CN leaves still described positions as definitions "for RBAC access control": the ADR-0090 P1 rename replaced the word role and kept the old framing. en says positions distribute capability (ADR-0090: capability = permission_set, distribution = position). The es-ES leaf was edited after en moved, so only the penultimate-edit check sees it. Values only. Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H Co-authored-by: Claude <noreply@anthropic.com>
…rity for the re-translated leaves Claude-Session: https://claude.ai/code/session_01XY5uCwTjZj7884yYtyur4H Co-authored-by: Claude <noreply@anthropic.com>
…ugin-bundle-leaves
📓 Docs Drift CheckThis PR changes 3 package(s): 13 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 9 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 22 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 ed20046e47d58f22f8eb01c455f6fadd81f7a773 && git checkout ed20046e47d58f22f8eb01c455f6fadd81f7a773
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 139bef809cda0084d56544bce1e6c58783da1a8e 5444bb130b1ed024c63208e0880796e116643b96 && git checkout -B drift-repro 139bef809cda0084d56544bce1e6c58783da1a8e && git merge --no-ff 5444bb130b1ed024c63208e0880796e116643b96
node scripts/docs-audit/affected-docs.mjs --json 139bef809cda0084d56544bce1e6c58783da1a8e
|
Fixes #20653
Clause-②: no
What changed
A translated leaf in a plugin's
src/translations/{ja-JP,es-ES,zh-CN}.objects.generated.tsthat a translator wrote by hand keeps its value when itsensource changes later. This PR measures that set in the four plugin bundles the card names (plugin-webhooks,plugin-audit,plugin-approvals,plugin-security), then re-translates the leaves whose meaning now contradicts the currenten: 18 leaves, six paths in all three locales (ja-JP 6, es-ES 6, zh-CN 6). The triage-ordered leaf,sys_webhook.fields.definition_json.help, is the first commit.enfile is edited, and no provenance companion (*.source-hashes.generated.ts) changes: the repo's own tooling was run and writes nothing (measured below)..changeset/20653-stale-authored-plugin-bundle-leaves.md:@objectstack/plugin-webhooks,@objectstack/plugin-audit,@objectstack/plugin-security, eachpatch.@objectstack/plugin-approvalshas no change and is not named.platform-objectsmetadata-forms leaves are the engine lane's card, i18n(platform-objects): authored ja-JP / es-ES / zh-CN metadata-forms leaves contradict their moved en source (the metadata-forms half of #20653) #20666, which remains open and is not touched here.The measurement (base
6bff748bb, before any edit)Instrument
PR #20652's condensed instrument, ported with one change: the bundle directory comes from argv instead of the
platform-objectsconstant. Population = every string leaf of the locale's objects bundle, minus echoes of the currentenand paths recorded in*.source-hashes.generated.ts; 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. Full history (the clone is not shallow:git rev-parse --is-shallow-repositoryanswersfalse).Four widening checks ran beside it:
packages/platform-objects/src/apps/translations/at44045721c(ADR-0029 D8: webhooks, approvals, security) andbe1b9165f(K2: audit). The condensed walk starts at the carve-out, so it dates every carried leaf there and reads theenof that day. The widened walk replays the platform-objects file's first-parent history (from its birth at6bacbced2, the horizon fix(platform-objects): re-translate the object leaves that contradict their current en source #20652 covered) before the plugin file's own. It re-dated every candidate the condensed walk had dated at a carve-out commit (for exampledefinition_json.help, to7bb92056e) and changed no candidate set.enis also read at the second parent. 0 hits.enat its previous edit, and whetherenmoved in the last-edit commit itself. Every flag whereenmoved EARLIER than the last edit was read by hand:sys_webhook.fields.method.help,sys_position.fields.name.helpandsys_position._actions.clone_position.params.name.helpTextalready say whatensays; es-ESsys_position._actions.deactivate_position.confirmTextdiffers by rewording only; es-ESsys_position.descriptioncontradicts (it was edited at4ea921ca8, afterenmoved, and kept the old framing), so it is re-translated.projectordepartmentwhereenat the same path does not carry the English term; the locale's word forroleorRBACanywhere in the four bundles; and a leaf whose path was born at its last edit while the same value sat under a sibling path of the same object that disappeared in that commit (a renamed key). One path, found by both the term scan and the renamed-key check:sys_activity.fields.environment_id.help. The key was renamed fromproject_idat944f18758with the value carried, so the since-last-edit instrument dates it at the rename, whereenalready said Environment, and cannot see it.Known-positive control
plugin-webhookssys_webhook.fields.definition_json.help, line 72 of all four bundles. The source has said "Credentials are NOT stored here" since160294963(the custom headers moved onto the encrypted channel, aftere3a6f6e7emoved the signing secret), and theenbundle since8af76aebf. The three translations were last edited at7bb92056e, whenensaid "full headers/auth/retry/payload config". The ported instrument flags it in all three locales. A1 held: the port is live before anything is counted.Counts per bundle (ja-JP / es-ES / zh-CN)
environment_id.help)sys_position.description)The before candidate counts equal the #20539 dev's raw counts exactly (A2). After = at
5444bb130, both instruments: each after-candidate set is exactly the before set minus the re-translated paths (0 added), the echo counts are unchanged (no new value equals itsenleaf), and the term scan and renamed-key check return 0. The penultimate-edit flags after are the before set minus es-ESsys_position.description, plus the 14 re-translated leaves that were candidates (their last edit is now this PR, afterenmoved), which is the expected shape.The judgment rule
As in PR #20652. A leaf contradicts the current
enwhen a reader who acts on it would believe something about the current field or object thatennow says is false:ennow denies what the leaf asserts; the object was re-modelled, so the leaf describes a different thing; or the leaf names the record's entity by a term a rename retired from it. Added detail, narrowing, rewording, punctuation and title-casing are not contradictions.Re-translated (18): before and after, with the
eneach now matches(ja-JP / es-ES / zh-CN, in each bundle's existing terms: 署名シークレット / カスタムヘッダー / アウトボックス / ケイパビリティ; secreto de firma / cabeceras personalizadas / outbox / capacidades / entorno; 签名密钥 / 自定义请求头 / 发件箱 / 授权能力 / 环境.)
plugin-webhooks·sys_webhook.fields.definition_json.help: said the JSON carries the full headers / auth / retry / payload config.ensays the opposite, on a security field.en: 「Serialised Webhook JSON (see @objectstack/spec/automation/webhook) — timeout and the rest of the authored envelope. Credentials are NOT stored here: the signing secret lives in the encryptedsigning_secretfield and the custom headers in the encryptedheaders_secretfield.」signing_secretフィールドに、カスタムヘッダーは暗号化されたheaders_secretフィールドに保存されます。」signing_secrety las cabeceras personalizadas, en el campo cifradoheaders_secret.」signing_secret字段中,自定义请求头保存在加密的headers_secret字段中。」plugin-webhooks·sys_webhook.description: said an HTTP connector plugin executes the webhook.69f1dfd5creplaced that executor in the source with the webhook auto-enqueuer and the shared HTTP outbox (service-messaging), and no HTTP connector plugin exists in the tree (packages/plugins,packages/services). The leaf also omitted thedefineStack({ webhooks })door, which is additive.en:Outbound HTTP webhook subscription. Declared in code via defineStack({ webhooks }) / defineWebhook() (materialized into rows on boot) or authored directly in the Studio editor; dispatched by the webhook auto-enqueuer onto the shared HTTP outbox.plugin-audit·sys_activity.fields.environment_id.label: the v5.0 rename project to environment ships no alias.en:Environmentplugin-audit·sys_activity.fields.environment_id.help: same rename; found by the term scan and the renamed-key check, invisible to the since-last-edit instrument.en:Environment context (multi-environment deployments)plugin-audit·sys_audit_log.fields.user_id.label:7fe7e85d6gavesys_audit_logits ownactorprincipal field (label Actor; ADR-0014 D2) and relabelled the strictsys_userlookupuser_idfrom Actor to User, because a service-token action leavesuser_idnull and records the principal inactor. The leaves still calleduser_idthe actor: es-ES showed two fields both labelled 「Actor」, and ja-JP (操作者 beside 実行者) and zh-CN (执行人 beside 操作者) showed two synonyms.en:Userplugin-security·sys_position.description: the ADR-0090 P1 commit (6d83431cf) changedenfrom "Role definitions for RBAC access control" to capability distribution; the translations were find-replaced role to position and kept "for RBAC access control" (ADR-0090: capability =permission_set, distribution =position, and the word role is retired from UI copy).en:Position definitions for capability distribution (ADR-0090)The two closest calls on this side are
sys_webhook.descriptionandsys_audit_log.fields.user_id.label; the reasons are above.Stale but not contradicting (listed, left as written)
endidsys_webhook.fields.triggers.helpenbundle began tracking its source (8af76aebf). The leaf's longer "bulk_update / bulk_delete fire on predicate writes and deliver a count" is still true (the field's own source comment says the same).sys_audit_log.fields.user_id.helpsys_approval_request.fields.status.options.*(5),sys_approval_action.fields.action.options.*(12)pendingtoPending,request_infotoRequest Info,ooo_substitutetoOut-of-Office Substitution). Every leaf already carried the meaning. Triage: not a contradiction.sys_position.fields.managed_by.help,sys_capability.fields.managed_by.help,sys_permission_set.fields.managed_by.helpsys_capability.descriptionsys_position._actions.deactivate_position.confirmTextsys_permission_set.fields.name.helpDispatch hypotheses, measured
6bff748bbare 3/3/3, 3/3/3, 17/17/16 and 7/5/7.sys_activity.fields.environment_id.label) is a positive in all three locales (es-ES 「Proyecto」 too).node scripts/check-i18n-bundles.mjs --write --filter=plugin-NAMEfor webhooks, audit, security and approvals printedregeneratedfor each; the files were rewritten on disk andgit status --porcelainstayed empty, so the tooling owes no companion orenchange. Control (a commit-first ablation throughscripts/ablation-replace.mjs): with ja-JPsys_webhook.fields.definition_json.helpset to theenstring,check-i18n-bundles --filter=plugin-webhooksgoes red,plugins/plugin-webhooks DRIFTED (1); the tool restored it (blob88583c2ea5f9== HEAD,git diff HEADempty).dist(built at5444bb130).plugin-webhooks: the built chunkdist/translations-KQ72WOMS.js, the module the plugin'skernel:readyhook imports, was imported and its served value (afterwithSourceFallback) read at each path: 6 of 6 equal the HEAD source and differ from the base, and 3 unchanged-leaf controls equal.plugin-auditandplugin-securityinline their bundles: each locale's object literal was cut out ofdist/index.mjsanddist/index.jsand read by path: 24 of 24 rows equal the HEAD source and differ from the base, and 12 controls equal. A plain byte grep was not a usable reading here: esbuild escapes non-ASCII text, and the old short labels are shared by other fields.Verification (all at
5444bb130, after mergingorigin/mainat9a4b2bb38)The merge brought PR #20658, a comment-only edit that includes
plugin-security/src/translations/index.ts, a file this PR does not edit.turbo run build --filter=@objectstack/cli... --filter=@objectstack/plugin-webhooks... --filter=@objectstack/plugin-audit... --filter=@objectstack/plugin-security..., 59/59 tasks,VERDICT command-exit 0.pnpm --filtertest, for the three changed plugins: plugin-webhooks 13 files / 160 tests passed; plugin-audit 25 files / 363 tests passed; plugin-security 147 files / 3202 passed, 23 skipped (the translation testsbundle-ownership.test.tsandposition-rename-consistency.test.tsincluded).typecheckfor the three: exit 0, eachcheck:test-typecheck: OK.node scripts/pm/dispatch-gates.mjs --commands(no paths) derived 57 commands against the real diff; the dispatch-time list had 56, and the one added ispnpm check:logger-receiver-detach. All 57 exit 0.--ranprinted "57 derived famil(ies) accounted for — 57 run, 0 NOT-MEASURED".pnpm check:dual-build-cjs-loadsfirst refused with exit 3 (nine packages outside this diff had nodist/). Those were built and the gate re-ran: exit 0.node scripts/check-changeset-fixed.mjs,pnpm check:authz-resolver,pnpm check:error-code-casing,pnpm check:filter-alias-parity, all 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-bytesOK.eslint --no-inline-config --format jsonread 9 files, 0 errors, 0 warnings.ESLint#isPathIgnoredanswersfalsefor all nine, read from the repo's own config. The config enables no type-aware linting (noparserOptions.project;eslint.config.mjsstates it at lines 327-328), so a change to string values in these files cannot move the verdict on any other file. The fullpnpm lintis left to CI.Acceptance notes
position-rename-consistency.test.tsmatches the retired term as\brole?s?\b/\brol(es)?\b/ 角色 / ロール. None of those matches the acronym RBAC, which is howsys_position.descriptionkept "for RBAC access control" in all three locales under a green ADR-0090 guard. This PR fixes the values; the test's blind spot remains. It is outside this card's file surface and is not changed here.project_idtoenvironment_id). The renamed-key check above covers that shape. i18n(platform-objects): authored ja-JP / es-ES / zh-CN metadata-forms leaves contradict their moved en source (the metadata-forms half of #20653) #20666 runs the same instrument on the metadata-forms bundles and may want the same check.Generated by Claude Code