Repository navigation
Commit c736eaa
fix(platform-objects): decide the action body/ai en-echoes per leaf, and close the one-schema-two-forms blind spot (#19509)
Part of #19403
Clause-②: no
## What this is
Round 5 of this card. One panel family, decided **leaf by leaf**. The
deliverable is a per-leaf judgement with its reason recorded, not twelve
translations; every leaf below was decided on its own evidence, and the
verdicts with their reasons live in a ledger the suite reads
(`action-body-panel-echo-decisions.test.ts`), not only in this body.
**The family: the five children of `action.fields.body` plus
`action.fields.ai`** — the `body` composite on the action metadata form,
and the AI-exposure block one section over. Both string leaves of each
key are decided.
Not `Fixes` — this is one family of the card's population, and the card
outlives this round. **Four families remain** (23 label keys / 39
decidable sibling leaves), tabled at the foot of this body.
## The tie at the top of round 5's table, and how it was broken
Round 4 fixed the sizing rule as **largest by LEAVES**. Re-derived on
this branch's base `4045781fa`, two rows tie at 12:
| family | keys | leaves |
|:--|--:|--:|
| **`action.fields.body.*` + `action.fields.ai`** — what this round took
| 6 | **12** |
| 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` | 5 | 10 |
| `report.fields.drilldown` + `runtimeFilter` +
`sections.dataset_binding` | 3 | 6 |
The tie-break is written into the ledger's header, four reasons, none of
them preference:
1. **The instrument survives only one of them.** The card's second
property is a population DERIVED from `en` with a dark control. `action`
is one panel: one derivation over one metadata type, and the dark
control has something to exclude (it asserts `retryPolicy`,
`valueDomain`, `drilldown`, `enable` and the `hook` section headings are
*not* action leaves). The six type-display pairs are six unrelated types
with no panel around them — the derivation degenerates into six
one-entry lookups and the control has nothing to be dark about.
2. **Evidence density forces per-leaf work.** Four of the six keys have
an authored twin at a byte-identical `en` one metadata type over; one
has a twin that is ITSELF an echo; one has no twin at all.
3. **The #19430 trap is live here, on three of the twelve leaves**, and
is discharged at the schema below rather than deferred.
4. **Leaving it costs more.** A bare type-display pair has no siblings,
so deferring it leaves nothing half-done. Deferring this one leaves the
action panel's Behavior and Advanced sections reading half Chinese and
half English around a single composite.
## The census — this branch's own reading, base `4045781fa`
| reading | base | this branch |
|:--|--:|--:|
| `en` string leaves / `.label` leaves | 893 / 538 | 893 / 538 — same
population |
| label keys echoing in ALL THREE locales | **29** | **23** |
| ⇒ as `.label` leaves | 87 | 69 |
| ⇒ as decidable sibling leaves (label + its `helpText`/`description`) |
51 | 39 |
| POSITIVE CONTROL — labels genuinely translated (`zh-CN`) | 509 |
**515** |
| POSITIVE CONTROL (`ja-JP` · `es-ES`) | 493 · 493 | **499 · 499** |
Echoes fall 6 while the control rises 6 in each locale, same population,
same run. A parser matching too broadly cannot produce that agreement.
**87 and 69 count `.label` leaves; 51 and 39 count decidable sibling
leaves** — two questions, two right answers, and this body states which
it means at every number.
## The evidence, per key — and the one key that had none
`actionForm` and `hookForm` declare the **same composite over the same
schema**: `HookBodySchema` (`packages/spec/src/data/hook-body.zod.ts`),
five children, identical field names, byte-identical `helpText` sources.
So the precedent is not a same-string match found elsewhere in the
catalog — it is the other rendering of this very schema key.
| key | evidence | verdict |
|:--|:--|:--|
| `body.language` | authored twin, byte-identical `en`, **and it names
both tokens** | translate ×3 |
| `body.source` | authored twin; the bare word `Source` has three
authored senses in this catalog and the twin picks the code one |
translate ×3 |
| `body.capabilities` | authored twin, byte-identical `en`, keeps all
four enum members | translate ×3 |
| `body.timeoutMs` | authored twin; the `en` is the extractor's humanize
of `timeoutMs`, and the twin renders the concept | translate ×3 |
| `body.memoryMb` | ⛔ **NO TWIN — the hook twin is itself an echo in all
three locales.** Composed from the sibling key's authored twin instead,
and the row says so | translate ×3 |
| `ai` | no twin of any kind (`hookForm` declares no `ai`); the authored
**section description one entry up the same panel** names the concept,
the **schema** settles the tokens | translate ×3 |
⭐ **Round 4's lesson, read the other way round.** Round 4 recorded that
a precedent answers only the question it actually contains: its twin
settled the prose and named no token, so the schema had to settle the
tokens. Here the twin settles **both** halves for `language` and
`capabilities` — `hook.fields.body.language.helpText` is authored AND
names `expression` and `js` AND keeps both English. Same rule, opposite
reading: the twin is sufficient *precisely because the question is
inside it*. For `ai.helpText` there is no twin at all and only the
schema answers. Each row says which half its evidence covers.
⭐ **And one leaf shows why a wholesale answer is refused.**
`action.fields.ai.label` reads `Ai` — the extractor's humanize of the
two-letter key. The obvious repair is the case fix `Ai` to `AI`, which
differs from the source in bytes, **passes the echo predicate in every
locale, and tells a zh-CN author exactly as much as the echo did**.
Rejected as a phantom translation; the label takes the concept the
panel's own authored section description already names, with `es-ES`
rendering the acronym `IA` and the other two keeping `AI`, exactly as
that description does.
## The #19430 trap was live on three leaves, and every one was read at
the schema first
`#19430 is not addressed here` and remains open — this is the discipline
it asked for, applied before a word was rendered.
| leaf | tokens named in prose | what the schema says | done |
|:--|:--|:--|:--|
| `body.language.helpText` | `expression`, `js` | the two `z.literal`
discriminators of `HookBodySchema` | kept English |
| `body.capabilities.helpText` | `api.read`, `api.write`, `crypto.uuid`,
`log` | four of the five `HookBodyCapability` `z.enum` members
(`api.transaction` is the fifth and the prose names it not at all) |
kept English |
| `ai.helpText` | `ai.exposed=true`, `ai.description` |
`ActionAiSchema`'s two canonical keys — a `strictObject` that declares
`enabled`/`enable`/`aiEnabled`/`expose`/`visible` as **aliases** of
`exposed`, so a rendered spelling is a spelling the schema refuses |
kept English |
Also kept: `ctx` and `import` (the sandbox binding and the reserved word
`ScriptBodySchema` forbids), and the schema bounds `256` (`.max(256)`)
and `40` (`.min(40)`). All of it is **asserted**, not described — a
machine-token guard reds when any of them stops being carried verbatim,
and ablation C reds it specifically.
## ⭐ The blind spot's FIFTH shape: one schema, two forms, invisible in
OPPOSITE ways
Rounds 1–4 measured `record`, `composite`, a pin green one level **up**
from what it walks, and a pin's own vacuity control passing **to the
side**. This round measured it across two forms.
`repeater-row-properties.test.ts` derives a row property for every child
of a `type: 'repeater'` field. Measured on this base:
| form | covered by that pin | invisible to it | state before this round
|
|:--|--:|--:|:--|
| `actionForm` | **18** (`params.*`) | **5** (`body.*`, a `composite`) |
all 18 authored · all 5 echoing |
| `hookForm` | **0** | **7** (`body.*` + `retryPolicy.*`) | 4 of 5
`body` children authored · `memoryMb` and both `retryPolicy` children
echoing |
⇒ the same composite is invisible to the same pin **in two opposite
ways**. On `action` it is the **lit** vacuity control
`carrying.has('action') === true` that passes — supplied by `params`,
the repeater that was never broken (round 4's shape, reproduced). On
`hook` it is the **dark** control `carrying.has('hook') === false`,
which is **true and correct** — `hookForm` enumerates no repeater at all
— while seven children sit enumerated and outside it. A correct control
and a passing control produce the same green, and neither can be
repaired by deriving harder on one panel.
⭐ **Because the half that matters lives BETWEEN the two derivations.**
Before this round `action.fields.body.*` echoed on 5 of 5 children and
`hook.fields.body.*` on 1 of 5: the same five schema keys, the same five
`en` sources, two different states, and no assertion anywhere that they
should agree. This PR adds one — wherever the `hook` twin is authored,
`action` renders it identically in every locale — with its own lit
control proving it compared real leaves (30 pairs, 6 excluded because
`memoryMb` carries no authored twin in any locale), and the exclusion
set asserted to be exactly `['memoryMb']`. When the `hook` family lands
in a later round, this assertion starts covering `memoryMb` too and reds
if that round renders it differently from this one.
`ablation D` is the one worth reading: it makes `action` disagree with
its authored twin and **only** that assertion reds. Every echo rule
stays green, because the mutated string is not the `en` source.
## The instrument — five independent assertions, proven by four
ablations
Mutation, run and restore inside **one** `ablation-replace.mjs` process
per ablation. Every restore verified: `git diff HEAD` empty and the blob
back to `HEAD`'s, checked independently afterwards as well.
| ablation | what it mutates | reds |
|:--|:--|:--|
| A | a decided leaf reverted to its `en` source in one locale | the
enumerated verdict **and** the derived panel pin — **2**, independently
|
| B | a provenance row re-pointed at a decided leaf | a **third** — the
second witness |
| C | a kept spec key rendered as words | a **fourth** — the
machine-token guard |
| D | the `action` rendering made to disagree with its authored `hook`
twin | a **fifth** — the new cross-panel invariant, and nothing else |
⇒ 2 + 1 + 1 + 1 = **five assertions that fail on five different
triggers**, not five spellings of one. All four dark controls carried
from the earlier rounds are present and fire: the echo predicate flags
all 12 rows when fed `en`; the derived predicate flags all 79 panel
leaves when fed `en`; the provenance lookup is proved to be able to say
"still a fill", matched by **pattern** so a later round cannot red it by
fixing a family; and the machine-token guard's negative uses
`api.transaction` — a **real** `HookBodyCapability` member this prose
deliberately does not name — so a green cannot come from an `includes`
that matches anything.
## ⛔ The silent-loss hazard: values only, measured with a discriminating
control
`*.metadata-forms.generated.ts` is generator-owned but `git check-attr
merge` reads `unspecified`, so it is NOT routed to `merge=os-regen`.
Regenerated with **`pnpm i18n:extract`**, never by hand, and no key was
added or removed:
```
en / zh-CN / ja-JP / es-ES: base 893 keys | head 893 | added 0 | removed 0
values changed per bundle: en 0 | zh-CN 12 | ja-JP 12 | es-ES 12 (exactly the decided leaves)
provenance rows: 12 removed per locale, 0 added (exactly the decided leaves)
NEGATIVE CONTROL (drop one key by hand): removed 1 => the comparator CAN see a 1-key delta
```
1 parent cf464f6 commit c736eaa
8 files changed
Lines changed: 808 additions & 72 deletions
File tree
- .changeset
- packages/platform-objects/src/apps/translations
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
Lines changed: 759 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 12 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1239 | 1239 | | |
1240 | 1240 | | |
1241 | 1241 | | |
1242 | | - | |
1243 | | - | |
| 1242 | + | |
| 1243 | + | |
1244 | 1244 | | |
1245 | 1245 | | |
1246 | | - | |
1247 | | - | |
| 1246 | + | |
| 1247 | + | |
1248 | 1248 | | |
1249 | 1249 | | |
1250 | | - | |
1251 | | - | |
| 1250 | + | |
| 1251 | + | |
1252 | 1252 | | |
1253 | 1253 | | |
1254 | | - | |
1255 | | - | |
| 1254 | + | |
| 1255 | + | |
1256 | 1256 | | |
1257 | 1257 | | |
1258 | | - | |
1259 | | - | |
| 1258 | + | |
| 1259 | + | |
1260 | 1260 | | |
1261 | 1261 | | |
1262 | 1262 | | |
| |||
1345 | 1345 | | |
1346 | 1346 | | |
1347 | 1347 | | |
1348 | | - | |
1349 | | - | |
| 1348 | + | |
| 1349 | + | |
1350 | 1350 | | |
1351 | 1351 | | |
1352 | 1352 | | |
| |||
Lines changed: 0 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | 21 | | |
34 | 22 | | |
35 | 23 | | |
| |||
Lines changed: 12 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1239 | 1239 | | |
1240 | 1240 | | |
1241 | 1241 | | |
1242 | | - | |
1243 | | - | |
| 1242 | + | |
| 1243 | + | |
1244 | 1244 | | |
1245 | 1245 | | |
1246 | | - | |
1247 | | - | |
| 1246 | + | |
| 1247 | + | |
1248 | 1248 | | |
1249 | 1249 | | |
1250 | | - | |
1251 | | - | |
| 1250 | + | |
| 1251 | + | |
1252 | 1252 | | |
1253 | 1253 | | |
1254 | | - | |
1255 | | - | |
| 1254 | + | |
| 1255 | + | |
1256 | 1256 | | |
1257 | 1257 | | |
1258 | | - | |
1259 | | - | |
| 1258 | + | |
| 1259 | + | |
1260 | 1260 | | |
1261 | 1261 | | |
1262 | 1262 | | |
| |||
1345 | 1345 | | |
1346 | 1346 | | |
1347 | 1347 | | |
1348 | | - | |
1349 | | - | |
| 1348 | + | |
| 1349 | + | |
1350 | 1350 | | |
1351 | 1351 | | |
1352 | 1352 | | |
| |||
Lines changed: 0 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | 21 | | |
34 | 22 | | |
35 | 23 | | |
| |||
Lines changed: 12 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1239 | 1239 | | |
1240 | 1240 | | |
1241 | 1241 | | |
1242 | | - | |
1243 | | - | |
| 1242 | + | |
| 1243 | + | |
1244 | 1244 | | |
1245 | 1245 | | |
1246 | | - | |
1247 | | - | |
| 1246 | + | |
| 1247 | + | |
1248 | 1248 | | |
1249 | 1249 | | |
1250 | | - | |
1251 | | - | |
| 1250 | + | |
| 1251 | + | |
1252 | 1252 | | |
1253 | 1253 | | |
1254 | | - | |
1255 | | - | |
| 1254 | + | |
| 1255 | + | |
1256 | 1256 | | |
1257 | 1257 | | |
1258 | | - | |
1259 | | - | |
| 1258 | + | |
| 1259 | + | |
1260 | 1260 | | |
1261 | 1261 | | |
1262 | 1262 | | |
| |||
1345 | 1345 | | |
1346 | 1346 | | |
1347 | 1347 | | |
1348 | | - | |
1349 | | - | |
| 1348 | + | |
| 1349 | + | |
1350 | 1350 | | |
1351 | 1351 | | |
1352 | 1352 | | |
| |||
Lines changed: 0 additions & 12 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
21 | | - | |
22 | | - | |
23 | | - | |
24 | | - | |
25 | | - | |
26 | | - | |
27 | | - | |
28 | | - | |
29 | | - | |
30 | | - | |
31 | | - | |
32 | | - | |
33 | 21 | | |
34 | 22 | | |
35 | 23 | | |
| |||
0 commit comments