Skip to content

fix(platform-objects): decide the hook panel's execution en-echoes per leaf, and pay round 5's cross-panel exclusion - #19530

Merged
huangyiirene merged 5 commits into
mainfrom
claude/issue-19403-round6-en-echoes
Sep 21, 2026
Merged

huangyiirene merged 5 commits into
mainfrom
claude/issue-19403-round6-en-echoes

Conversation

@huangyiirene

Copy link
Copy Markdown
Collaborator

Part of #19403

Clause-②: no

Round 6 of #19403. The hook metadata-form panel's ten remaining en-echoes, decided one leaf at a time, with the reason recorded for each. With them the panel is finished: zero of its 47 string leaves now echoes its English source in all three locales.

The family, and why the leaf count did NOT decide it

Re-measured on this branch's base 0e671d20c — the four remaining families, in both counts:

family keys leaves
six bare type-display pairs (seed·mapping·api·doc·book·capability) 6 12
object.fields.enable.* (+ validations) 9 11
hook.fields.retryPolicy.* + body.memoryMb + timeoutMs ← taken 5 10
report.fields.drilldown + runtimeFilter + sections.dataset_binding 3 6

This family is third of four by leaves, so the tie-break is written down — in the ledger's header and here. Two of the four reasons are ones no other row can offer:

  1. It is the only family that makes the LANDED instrument stronger rather than longer. PR fix(platform-objects): decide the action body/ai en-echoes per leaf, and close the one-schema-two-forms blind spot #19509's cross-panel invariant compares 5 shared HookBodySchema children × 2 props × 3 locales = 30 pairs and excluded 6 of them, because hook.fields.body.memoryMb was itself an en-echo and an unauthored twin carries no evidence. That file asserts the exclusion by name and states that a later round of this card owes it. Deciding body.memoryMb here pays it: the exclusion set is empty, 30 of 30 pairs are compared, and memoryMb is guarded on both panels. Ablation D reds that landed assertion, which is the proof the discharge is real.
  2. It is the remaining half of a measured blind spot, on the panel where the existing pin is blind through a control that is CORRECT. Round 5 measured hookForm's enumerated-but-unwalked children at seven — the five body.* plus retryPolicy.maxRetries and retryPolicy.backoffMs — and closed the five on the action side only. The two retryPolicy children are what was left.
  3. Evidence density forces per-leaf work: body.memoryMb takes a twin that exists only because round 5 created it; timeoutMs takes an authored twin one level down the same panel at a byte-identical en; retryPolicy.* has no twin anywhere and is composed from this catalog's authored answers for its separate words.
  4. It completes a panel — recorded as a reason that did not decide, because object and report would complete theirs too.

And why not the six bare pairs, which lead by leaves: round 5's refusal stands unchanged — only a real panel keeps the DERIVED-POPULATION property with a working dark control, and six unrelated types degenerate the derivation into six one-entry lookups with nothing for the control to exclude.

The ten decisions

Every verdict is translate in all three locales; every row records the authored leaf its wording came from.

leaf en zh-CN / ja-JP / es-ES evidence shape
body.memoryMb.label Memory Mb 内存(MB) · メモリ(MB) · Memoria (MB) the twin round 5 created — copied verbatim
body.memoryMb.helpText Per-invocation memory cap (MB, max 256) 单次调用内存上限(MB,最大 256) · 呼び出しごとのメモリ上限(MB、最大 256) · Límite de memoria por invocación (MB, máx. 256) same twin; 256 kept as a numeral (ScriptBodySchema.max(256))
timeoutMs.label Timeout Ms 超时(毫秒) · タイムアウト(ms) · Tiempo de espera (ms) authored twin one level down the same panel
timeoutMs.helpText Abort the hook after N milliseconds 超过 N 毫秒后中止该钩子 · N ミリ秒経過後にフックを中止 · Abortar el hook después de N milisegundos the #19430 near-miss, cleared at the schema; N kept
retryPolicy.label Retry Policy 重试策略 · 再試行ポリシー · Política de reintentos composed from two authored answers in this catalog
retryPolicy.helpText Retry on failure — most useful for async hooks 失败时重试——对异步钩子最有用 · 失敗時に再試行 — 非同期フックで特に有用 async read at the schema: a boolean, not a token
retryPolicy.maxRetries.label Max Retries 最大重试次数 · 最大再試行回数 · Reintentos máximos extractor humanize rendered as the concept
retryPolicy.maxRetries.helpText Maximum retry attempts 最多可重试的次数 · 再試行の最大回数 · Número máximo de reintentos the schema default 3 deliberately not rendered
retryPolicy.backoffMs.label Backoff Ms 退避(毫秒) · バックオフ(ms) · Retroceso (ms) sys_job_queue.fields.backoff_type.label's authored answer
retryPolicy.backoffMs.helpText Delay between retries (ms) 两次重试之间的延迟(毫秒) · 再試行間の遅延(ms) · Retraso entre reintentos (ms) same vocabulary; default 1000 not rendered

What was refused. Four of the five labels are the extractor's humanize of a camelCase key, not authored English — exactly where round 5's phantom-translation reading bites. Memory Mb → Memory (MB) or Max Retries → Max Retries (3) would differ in bytes, pass the echo predicate in all three locales, drop the census by a key and tell a zh-CN author nothing. Every one is rendered into the locale's own writing system instead, and the enumerated verdicts — not the census — are what shows it.

The #19430 discipline, and the near-miss this family had to clear

Read at the schema before a word was rendered, and asserted against the live HookSchema rather than described:

  • timeoutMs.helpText says "Abort the hook after N milliseconds", and abort is a legal value of HookSchema.onError (z.enum(['abort','log'])). The near-miss is real. It is cleared because the key this tooltip describes takes a number — the schema accepts 5000 and refuses "5000 毫秒" — so no rendered word can land in it, and the schema's own description uses the word as the runtime's verb ("before the hook is aborted"). Rendered.
  • retryPolicy.helpText names async. HookSchema.async is z.boolean().default(false) — accepts true, refuses "异步" — so it is not a A metadata-form tooltip spells a strict enum's legal values in translated locales, so the value an author is shown is one the schema refuses #19430 token. Rendered, taking this panel's own authored 异步 / 非同期 / Asíncrono one entry up.
  • retryPolicy is a strictObject, not an enum; its alias map governs KEY spellings, which no label renders. Its defaults are {maxRetries: 3, backoffMs: 1000} and neither tooltip carries a number — asserted both ways.
  • N and 256 are kept verbatim, and the token guard now judges Unicode word boundaries rather than substring containment: 'Número máximo de reintentos'.includes('N') is true, so round 5's containment check would have passed a locale that lost the placeholder entirely. That is a control, and ablation E reds it.

A second act: body.capabilities reworded on both panels

Round 5 recorded rather than improved that zh-CN 功能 and ja-JP 機能 read "feature" for what is a capability token from the HookBodyCapability enum — and left the reword to the hook family, because both forms declare the same schema key and diverging is the defect the cross-panel invariant guards. This round is the hook family.

The replacement is derived, not invented: every authored leaf of the objects catalog whose English names a capability renders it 能力 (zh-CN) and ケイパビリティ (ja-JP), and none of them uses 功能 or 機能. The ledger asserts that derivation over the catalog rather than quoting it. es-ES already read Capacidades — the same word those leaves use — and is unchanged, which is why the zh-CN and ja-JP bundle diffs are two lines larger than es-ES's. The neighbouring senses (object.sections.capabilities = 功能开关, the feature CHECKBOXES; agent.sections.capabilities = 能力配置) are deliberately untouched and pinned as such.

The measurements, each with its control in the same run

reading base 0e671d20c head
en string leaves / .label leaves 893 / 538 893 / 538 — same population
label keys echoing in ALL THREE 23 ⇒ 69 .label leaves 18 ⇒ 54
POSITIVE CONTROL — labels genuinely translated 515 · 499 · 499 520 · 504 · 504
decidable sibling remainder (label + its helpText/description) 39 29
hook panel leaves echoing in all three 10 of 47 0 of 47

Echoes −5 keys, control +5 in each locale, same population, same run. Two counts for two questions — the headline moves by 5 because only labels are counted, while this round decided 5 labels and 5 helpTexts.

  • No key added or removed. Full flattened key sets, base vs head, all four bundles: 893 / 893, 0 added, 0 removed — with a negative control proving the comparator sees a one-key delta in both directions (hook.fields.__probe__.label). en is untouched.
  • Regenerated with pnpm i18n:extract, never by hand. It dropped exactly the 10 decided leaves' provenance rows in each of the three locales (30 rows, listed in full in the report comment) and added none; the metadata-forms bundles round-tripped byte-identical.
  • Bundle diffs: zh-CN 12/12, ja-JP 12/12, es-ES 10/10 — insertions equal deletions in every bundle. The two extra lines per CJK bundle are the capabilities reword on the two panels; es-ES needed none.

The concurrent PR that held this region

PR #19520 HAD LANDED by the time of the pre-push merge — so the required check was not vacuous, and it passes. Its leaf is view.fields.userFilters.helpText, and in all three bundles this branch carries origin/main's value, not the base's:

base  快速筛选栏:控件样式(下拉 / 标签页 / 开关)+ 暴露的字段或标签页预设
main  快速筛选栏:控件样式(dropdown / tabs / toggle)+ 暴露的字段或标签页预设
head  快速筛选栏:控件样式(dropdown / tabs / toggle)+ 暴露的字段或标签页预设

base != main (the fix moved it) and head == main (it survived) hold for zh-CN, ja-JP and es-ES. The merge brought its one-line-per-bundle change in cleanly, exactly as the dispatch's five-round measurement predicted. That changeset — 19430-user-filters-element-tokens — is this card's own round-2 finding coming back fixed by another seat, so silently reverting it would have been this lane undoing its own filed work.

The instrument — five ledgers extended, not rebuilt

hook-execution-panel-echo-decisions.test.ts carries every property the five earlier rounds established, plus two this family added:

  • the echo-reason rule as a predicate with a dark control (proved on a synthetic row, since every verdict here is translate);
  • the panel population DERIVED from the en catalog, with a dark control naming keys that exist on other types — including action's own body.memoryMb at a byte-identical en;
  • the second witness over the three *.source-hashes.generated.ts companions, with its own pattern-matched dark control;
  • the en source pinned equal to the live bundle, for the decisions and the rewords;
  • the machine-token guard, upgraded to Unicode word boundaries — the new part, forced by a bare N;
  • the cross-panel invariant, now at 30/30 with a compared counter keeping it lit;
  • the composite blind spot on the hook side, closed.

action-body-panel-echo-decisions.test.ts is updated in the same PR: its exclusion set is emptied, its lit assertion becomes a counted 30, and the prose that quoted the old capability wording now points at the derivation behind the new one.

Five ablations, ten assertions, two files

Each ran mutation → run → restore inside one scripts/ablation-replace.mjs process, which proves the mutation landed by blob hash and proves the restore by blob == HEAD plus an empty git diff HEAD. No rebuild is involved: these tests resolve the bundles as sibling sources, not through dist.

# mutation assertions reddened
A re-fill zh-CN hook.fields.retryPolicy.label with its en zh-CN: every decided leaf matches its verdict; no leaf on this panel reads its en source…
B reword the en source under the pinned row every row is pinned to the live en source; the echo predicate can say "echo"
C put a decided leaf's provenance row back zh-CN: no decided leaf is still recorded as an extractor fill
D render body.memoryMb differently on the two panels round 5's landed invariant the half NO single-panel pin can see; 30 of 30 pairs agree; the invariant can fire
E drop the N placeholder from the es-ES tooltip the machine tokens… are still verbatim; the token predicate can say NO

Changeset — measured, not assumed

@objectstack/platform-objects is private: false with files: ["dist", …], and the decided strings reach dist: each appears in 6 built files, escaped (\uXXXX upper-case hex, and \xNN for U+0080–U+00FF — Pol\xEDtica de reintentos). A raw un-escaped negative control reads 0 including for the positive controls, so a zero in the raw column means "escaped", not "absent", and a never-written string reads 0 in both columns. ⇒ a patch changeset; skip-changeset is measurably wrong.

Acceptance notes

Zero cards to file, and that is a reading rather than a silence. The leaf that could have carried the known #19430 trap is hook.fields.timeoutMs.helpText, whose abort is a real HookSchema.onError enum value — it was checked at the schema, found to describe a numeric key, and cleared, with the check asserted in the ledger so a schema change reds it. retryPolicy.helpText's async was checked the same way and is a boolean. Neither is a defect, and neither is a card.

Noted, not filed:

  • hook.label is Gancho in es-ES while every es-ES sentence on the panel says hook (hook.sections.identity.description, hook.fields.condition.helpText, hook.fields.async.helpText, and now timeoutMs.helpText, which copies that convention). This is a wording inconsistency inside one panel, not a reproducible defect, not a contract violation, and not a metadata-authoring trap — the author writes neither word. Carrier: 无 (no PR or person is queued to touch this file for it); it belongs to whichever round of 83 metadata-form label keys ship their English source in all three locales (249 leaves) and no pin sees any of them #19403 takes a family that renders the type's own display pair. Dedupe words: es-ES, Gancho, hook.label, metadata-forms, panel vocabulary.
  • permission.fields.systemPermissions.helpText renders "system capability keys" as システム機能キー in ja-JP, which is the word this PR just replaced for the hook body's capability tokens — but that leaf is a permission capability, a different sense, and it is authored and outside this family. Recorded so a later round does not read this PR's reword as a sweep. Carrier: 无. Dedupe words: ja-JP, 機能, ケイパビリティ, systemPermissions, capability wording.

Neither carries class: a|b|c evidence, so by this round's reporting contract both stay here as prose.


Generated by Claude Code

…r leaf

Round 6 of #19403 takes the `hook` panel's ten remaining en-echoes —
`body.memoryMb`, the hook-level `timeoutMs`, and the three `retryPolicy`
keys — and renders each from evidence recorded per leaf.

Also rewords `body.capabilities` on BOTH panels that declare
HookBodySchema (zh-CN 功能 -> 能力, ja-JP 機能 -> ケイパビリティ), which
round 5 recorded rather than improved because rewording is the hook
family's act. es-ES already read Capacidades and is unchanged.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcPSwnmJHczmTu6FG7NMjE
… decisions

`pnpm i18n:extract` dropped exactly the 10 decided leaves' provenance rows
in each of the three translated locales (30 rows) and added none; the
metadata-forms bundles round-tripped byte-identical.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcPSwnmJHczmTu6FG7NMjE
…harge round 5's exclusion

Adds `hook-execution-panel-echo-decisions.test.ts` — one row per decided
leaf with its verdict, its reason and the `en` source it was judged
against, carrying the echo predicate with a dark control, the population
derived from `en`, the provenance second witness, the machine-token
guard (now judged on Unicode word boundaries, because this family keeps a
bare `N`), the composite blind spot on the hook side, and the #19430
readings asserted against the live HookSchema rather than described.

Updates `action-body-panel-echo-decisions.test.ts`: its cross-panel
invariant excluded six of thirty pairs because `hook.fields.body.memoryMb`
was itself an echo, and said a later round owed it. It is paid — the
exclusion set is empty and a `compared` counter keeps the assertion lit.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcPSwnmJHczmTu6FG7NMjE
@objectstack/platform-objects is `private: false` with `files: ["dist", …]`
and the decided values reach `dist` — probed with controls, so a zero in
the raw column reads "escaped", not "absent". `skip-changeset` is
measurably wrong here.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NcPSwnmJHczmTu6FG7NMjE
@github-actions github-actions Bot added size/xl documentation Improvements or additions to documentation tests tooling labels Sep 21, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

3 anchor(s) derived from 1 changed package(s); no hand-written page names any of them, so this run has nothing to list — not a clean bill of health. This check sees only pages that NAME a derived anchor: one that documents this change in prose, or enumerates it in an authoring dialect, names none and stays invisible to it on every run.

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): node scripts/docs-audit/affected-docs.mjs --json eec56c37dfc89086658c1659bb2da869dfa08d4f → packageMentionDocs.

Which tree this was computed on

This run read content/docs from 89f9269559f0d1bcde8786452e630d9df56a76b5 — the merge of head a7ab791e912d271000b9a18d4b905c8d3621688f into base eec56c37dfc89086658c1659bb2da869dfa08d4f, 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 89f9269559f0d1bcde8786452e630d9df56a76b5 && git checkout 89f9269559f0d1bcde8786452e630d9df56a76b5
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin eec56c37dfc89086658c1659bb2da869dfa08d4f a7ab791e912d271000b9a18d4b905c8d3621688f && git checkout -B drift-repro eec56c37dfc89086658c1659bb2da869dfa08d4f && git merge --no-ff a7ab791e912d271000b9a18d4b905c8d3621688f

node scripts/docs-audit/affected-docs.mjs --json eec56c37dfc89086658c1659bb2da869dfa08d4f

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

@huangyiirene
huangyiirene marked this pull request as ready for review September 21, 2026 07:44
@huangyiirene
huangyiirene added this pull request to the merge queue Sep 21, 2026
Merged via the queue into main with commit ecf56e7 Sep 21, 2026
36 checks passed
@huangyiirene
huangyiirene deleted the claude/issue-19403-round6-en-echoes branch September 21, 2026 07:59
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 size/xl tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants