Repository navigation
Commit 4e4111c
fix(platform-objects): sys_email field help names no service interface; QA clause requotes the package-id refusal (#22309)
Part of #22093
Clause-②: no
This PR delivers remainders (b) and (c) of #22093, as the seat's
partial-landing record (`6049519522`) names them. Remainder (a), the
governed `submitBehavior` describe, is not in this PR and stays on the
card. Wording only: no field, option, key, type or export changes. It
ships a patch changeset for `@objectstack/platform-objects`. The
`docs/qa` change publishes nothing.
## (b) The `sys_email` field help no longer names a service interface
Studio shows a field's `description` as its help in the object forms:
the `help` leaf in each locale's `objects` bundle. Two `sys_email`
fields named the `IEmailService.send` service interface there. Each one
now says what the field holds and when it is set, in product words, and
keeps every fact it stated before. The implementation reference moves
into the code comment beside each field (`sys-email.object.ts`), in the
same form PR #22125 used for the other 22 rows.
| Field | Locale | Before | After |
| :--- | :--- | :--- | :--- |
| `headers_json` | en (source) | "Custom headers supplied to
IEmailService.send, as a JSON object of name → value." | "Custom headers
supplied with the message when it was sent, as a JSON object of name →
value." |
| `headers_json` | zh-CN | "传给 IEmailService.send 的自定义邮件头,…" |
"发送邮件时随附的自定义邮件头,…" |
| `headers_json` | ja-JP | "IEmailService.send に渡されたカスタムヘッダーを、…" |
"メッセージの送信時に指定されたカスタムヘッダーを、…" |
| `headers_json` | es-ES | "Cabeceras personalizadas facilitadas a
IEmailService.send, como un objeto JSON …" | "Cabeceras personalizadas
facilitadas con el mensaje al enviarlo, como un objeto JSON …" |
| `status` | en (source) | "Lifecycle state — queued by
IEmailService.send before transport call" | "Lifecycle state — queued
when the message is submitted for sending, before the first delivery
attempt" |
| `status` | zh-CN | "生命周期状态——在调用传输层之前由 IEmailService.send 排队" |
"生命周期状态——邮件提交发送时即进入排队,早于首次投递尝试" |
| `status` | ja-JP | "ライフサイクル状態 — トランスポート呼び出し前に IEmailService.send
がキューに入れます" | "ライフサイクル状態 — 送信が要求された時点で、最初の配信試行の前にキューに入ります" |
| `status` | es-ES | "Estado del ciclo de vida; se pone en cola mediante
IEmailService.send antes de la llamada al transporte." | "Estado del
ciclo de vida; queda en cola al solicitarse el envío del mensaje, antes
del primer intento de entrega." |
For `headers_json`, only the first sentence changes. The rest of each
leaf is unchanged. The `status` wording uses the vocabulary of the
neighbouring `attempt_count` help in each locale ("delivery attempts",
投递尝试, 配信試行, intentos de entrega).
### How the bundles were produced
- **en:** regenerated by the package's documented generator, `pnpm
i18n:extract`, after the source edit. It rewrote exactly the two `en`
leaves.
- **zh-CN, ja-JP, es-ES:** the translated leaf is itself where the
translated text lives. The generator's merge mode never overwrites an
existing translated leaf. The bundle header ("Edit translations in place
… Do not hand-edit the structure — only the leaf string values") and
AGENTS.md's Documentation Guardrails row both name re-translating the
leaf in place as the maintenance path. So I re-translated the two leaves
in place and then ran the generator. It wrote all 11 files and left the
three translated bundles and their `*.source-hashes.generated.ts` tables
byte-identical. That shows the edit changed leaf values only, never
structure. Neither leaf had a recorded source hash, so no provenance
entry moves. A second `pnpm i18n:extract` at the head leaves `git
status` empty.
- The dispatch named es-ES and ja-JP. zh-CN carried the same phrase, so
it is rewritten too.
### Pin
`packages/platform-objects/src/apps/translations/objects-help-no-service-interface.test.ts`
walks every string leaf of the four `objects` bundles. It asserts that
none matches the service-interface pattern the notify Template help pin
already uses (`\bI[A-Z]\w*Service\b`). It also checks the two
`sys_email` source descriptions. A positive control asserts that the
walk reaches both rewritten leaves in every locale, so a walk that
reaches nothing cannot pass. Today no other leaf in the four bundles
matches, so the pin covers the whole class for this package's object
help, not just these two rows.
Ablation (one-off, no file kept): `scripts/ablation-replace.mjs` put the
old zh-CN `status` leaf back, landing confirmed on disk (anchor 1 → 0,
blob `5cf8f2e7e81d` → `64f05c216782`). The pin went red as 1 failed and
5 passed, naming `sys_email.fields.status.help` in zh-CN only. The file
was restored with the blob equal to HEAD and `git diff HEAD` empty.
## (c) The QA clause quotes the current package-id refusal
`docs/qa/platform-checklist/areas/cli.json`, item
`cli.plugin-manifest-build-contract`, acceptance clause A2:
| Before | After |
| :--- | :--- |
| "a located Zod error ('Invalid package id '' on `manifest.id`.
Expected reverse-domain notation …')" | "a located Zod error ('Invalid
package id ''. A package id (`manifest.id`) is written in reverse-domain
notation, like …')" |
The new quote is taken from `manifestIdRefusal`
(`packages/spec/src/kernel/manifest.zod.ts`) at `6729e107e`. I checked
it against the live refusal: `ManifestSchema.safeParse` with `id: ''`
answers on path `id` with "Invalid package id ''. A package id
(`manifest.id`) is written in reverse-domain notation, like
'com.acme.crm' or 'org.example.help-desk' — …". The item's `revision`
moves from 2 to 3, with one `history` entry in the file's convention
(`revision`, `date`, `change`, `ref`). The scored property is unchanged,
and so is A2's `verify` text: probe (d) still reads a located
reverse-domain refusal that names `manifest.id` and echoes the received
`''`.
## Verification (at `acc26751b`)
- **Build:** the extract closure under the verify lock, `pnpm turbo run
build --filter='@objectstack/lint...'
--filter='@objectstack/platform-objects...' --concurrency=2`: 8 of 8
tasks, `VERDICT command-exit 0`.
- **Tests:** `pnpm --filter @objectstack/platform-objects exec vitest
run --maxWorkers=2 src/apps/translations src/audit/sys-email`: 27 files,
443 tests passed.
- **Typecheck:** `pnpm --filter @objectstack/platform-objects
typecheck`, all three legs including `check:test-typecheck`: exit 0.
- **Lint:** `eslint --no-inline-config --format json` on the 6 changed
TS files: 6 files, 0 errors, 0 warnings. The population comes from
`eslint.config.mjs`: `**/*.{ts,…}` minus `NEVER_LINTED`. Type-aware
linting is not enabled, so this diff cannot move the verdict on any
untouched file.
- **Gates:** `node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 65 commands. I ran them together
with the 52-row artifact-roster block, 115 unique commands. 107 exited
0.
- Three are PR-context gates that print NOT WIRED (exit 2) without
`PR_BODY` or `PR_NUMBER`. `check:partof-closing-keyword` was re-run
against this body.
- Four exited 3 with PREREQUISITE NOT MET, because they read a
whole-workspace build this run did not make:
`check:dual-build-cjs-loads`, `check:i18n` (the built CLI),
`check:lean-entry-closure` and `check:published-readme-exports`. For
`check:i18n`, the documented command it runs for this package (`pnpm
i18n:extract`) was run directly, and it is idempotent at the head.
- `check:type-check-debt` was not run locally: its re-measure is a
workspace build outside the verify lock. CI reads it.
## Acceptance notes
- The zh-CN, ja-JP and es-ES `headers_json` help leaves omit the last
English sentence ("Never returned on the generic data path — …"). This
translation lag predates this PR, and the source-hash mechanism treats a
leaf with no recorded hash as legacy-trusted, so nothing flags it. This
PR re-translates only the sentence that named the interface. Noted, not
filed. Carrier: none.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01RPo7FUd6bSnAfkWMAKi848)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent dc4a5c6 commit 4e4111c
8 files changed
Lines changed: 89 additions & 12 deletions
File tree
- .changeset
- docs/qa/platform-checklist/areas
- packages/platform-objects/src
- apps/translations
- audit
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1499 | 1499 | | |
1500 | 1500 | | |
1501 | 1501 | | |
1502 | | - | |
| 1502 | + | |
1503 | 1503 | | |
1504 | 1504 | | |
1505 | 1505 | | |
| |||
1536 | 1536 | | |
1537 | 1537 | | |
1538 | 1538 | | |
1539 | | - | |
| 1539 | + | |
1540 | 1540 | | |
1541 | 1541 | | |
1542 | 1542 | | |
| |||
1593 | 1593 | | |
1594 | 1594 | | |
1595 | 1595 | | |
| 1596 | + | |
| 1597 | + | |
| 1598 | + | |
| 1599 | + | |
| 1600 | + | |
| 1601 | + | |
1596 | 1602 | | |
1597 | 1603 | | |
1598 | 1604 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2500 | 2500 | | |
2501 | 2501 | | |
2502 | 2502 | | |
2503 | | - | |
| 2503 | + | |
2504 | 2504 | | |
2505 | 2505 | | |
2506 | 2506 | | |
2507 | 2507 | | |
2508 | 2508 | | |
2509 | 2509 | | |
2510 | 2510 | | |
2511 | | - | |
| 2511 | + | |
2512 | 2512 | | |
2513 | 2513 | | |
2514 | 2514 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2500 | 2500 | | |
2501 | 2501 | | |
2502 | 2502 | | |
2503 | | - | |
| 2503 | + | |
2504 | 2504 | | |
2505 | 2505 | | |
2506 | 2506 | | |
2507 | 2507 | | |
2508 | 2508 | | |
2509 | 2509 | | |
2510 | 2510 | | |
2511 | | - | |
| 2511 | + | |
2512 | 2512 | | |
2513 | 2513 | | |
2514 | 2514 | | |
| |||
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2500 | 2500 | | |
2501 | 2501 | | |
2502 | 2502 | | |
2503 | | - | |
| 2503 | + | |
2504 | 2504 | | |
2505 | 2505 | | |
2506 | 2506 | | |
2507 | 2507 | | |
2508 | 2508 | | |
2509 | 2509 | | |
2510 | 2510 | | |
2511 | | - | |
| 2511 | + | |
2512 | 2512 | | |
2513 | 2513 | | |
2514 | 2514 | | |
| |||
Lines changed: 55 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
Lines changed: 2 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2500 | 2500 | | |
2501 | 2501 | | |
2502 | 2502 | | |
2503 | | - | |
| 2503 | + | |
2504 | 2504 | | |
2505 | 2505 | | |
2506 | 2506 | | |
2507 | 2507 | | |
2508 | 2508 | | |
2509 | 2509 | | |
2510 | 2510 | | |
2511 | | - | |
| 2511 | + | |
2512 | 2512 | | |
2513 | 2513 | | |
2514 | 2514 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
150 | 150 | | |
151 | 151 | | |
152 | 152 | | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
153 | 158 | | |
154 | 159 | | |
155 | 160 | | |
156 | 161 | | |
157 | 162 | | |
158 | | - | |
| 163 | + | |
159 | 164 | | |
160 | 165 | | |
161 | 166 | | |
| |||
184 | 189 | | |
185 | 190 | | |
186 | 191 | | |
187 | | - | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
188 | 195 | | |
189 | 196 | | |
190 | 197 | | |
| |||
0 commit comments