Repository navigation
Commit bab7685
Fixes #21948
Clause-②: no
## What changed
`translateObject` used to put a bundle's
`objects.OBJECT.fields.FIELD.help` entry on a `help` key that
`FieldSchema` does not declare. The served field then failed
`FieldSchema` with `unrecognized_keys`. A consumer that reads only
declared keys rendered the English `description`, and the console logged
one ingestion warning per such field.
- **Target key, measured.** The extractor writes that bundle entry from
`field.help ?? field.description`
(`packages/cli/src/utils/i18n-extract.ts:1223`). `FieldSchema` refuses
`help`, so on a spec-valid field the only source is `description`. The
nine bundle source trees author 0 `inlineHelpText` and 0 field `help`.
The nine `en` bundles carry 523 `help` entries.
- **`translateField`**
(`packages/spec/src/system/i18n-resolver.ts:3054`) now serves the
translated help on `description` and writes no `help` key.
`inlineHelpText` is not touched.
- **Precedence: ADR-0029 D9.2a**, the resolver's own rule, applied
through the existing `valueOverridesPackagedBase` predicate. There is no
second comparison. The catalog applies only while the served field's
`description` equals the packaged field's.
- No packaged base supplied: the catalog applies (the conservative edge
#8284 established).
- A field the base does not declare counts as diverged, which is
`packagedPart`'s convention. The new finder `packagedObjectField`
(`:1434`) reads both field-map shapes.
- A field's `label` is unchanged and stays a flat `catalog ?? document`,
as its existing pin scopes it.
- **`ObjectFieldLike`** (`:2453`) drops its `help?: string` member. This
is safe:
- its `[key: string]: any` index signature still accepts and types a
`help` key, so a caller that writes or reads one still compiles (probe
below);
- `packages/spec/api-surface/system.json` records only `ObjectFieldLike
(interface)`, not its members, and `check:api-surface` stays green;
- the one in-repo importer (`service-analytics`, which reads `options`
only) still typechecks.
- The `translateObject` docblock no longer says it translates a field's
`help`. A new section states the target key and the D9.2a precedence.
- `.changeset/21948-spec-field-help-served-on-description.md`:
`@objectstack/spec` `patch`.
## Clause-② — measured `no`
- No Zod schema, parse or export changed. These all stay green:
`check:authorable-surface`, `check:api-surface`, `check:export-origins`,
and `check:generated` (15 artifacts up to date).
- **Type probe** (scratch, not committed), compiled against the rebuilt
`dist/system/index.d.ts`, exit 0:
- `const legacy: ObjectFieldLike = { name: 'x', help: 'legacy' }`
compiles, and so does reading `legacy.help`;
- a declared member still refuses a wrong value (an `@ts-expect-error`
on `label: 42` is consumed);
- `const proof: number = ({} as ObjectFieldLike).help` compiles, which
shows the probe read the rebuilt declaration.
- **Control leg:** the same probe against a copy of that `.d.ts` with
BASE's `help?: string` put back gives exit 2, with exactly one error:
TS2322 on the `proof` line. Writing and reading `help` compile under
both declarations.
- So no value the type or the schemas used to accept is refused now. The
one type-level delta is that `ObjectFieldLike['help']` is now read
through the index signature (`any`) instead of `string | undefined`.
That is stated here for the at-tier review.
## Measured
All at HEAD `3ad2f22bed` unless stated.
**Corpus at the resolver seam (scratch script, not committed).** Every
object in `packages/platform-objects/scripts/i18n-extract.config.ts` (48
objects, 617 fields), with that package's real bundles, using each
object as its own packaged base:
| | served `help` keys | `help` refused by `FieldSchema` | `sys_user`
fields with `help` | zh-CN `description` equal to the bundle entry |
|---|---|---|---|---|
| BASE behaviour (ablation leg 1 below) | 332 | 332 | 18 of 26 | 0 |
| HEAD | 0 | 0 | 0 of 26 | 332 |
- At HEAD in zh-CN, `sys_user.two_factor_enabled.description` =
`该用户是否已启用双因素认证。由 better-auth 的 \`twoFactor\` 插件维护。`.
- In `en`, 0 descriptions change from source, because the en entries
repeat the source.
- **NOT MEASURED: the HTTP door** (`GET /api/v1/meta/object/sys_user`).
The spec change invalidates the showcase build closure: 62 of 63 turbo
tasks miss the cache. The pins and the corpus run read the same
`translateMetadataDocument` dispatch the REST read calls.
**Pins** (`packages/spec/src/system/i18n-resolver.test.ts:3552`, 9
cases):
- a zh-CN served field carries no `help`, has the translation on
`description`, and parses with no `unrecognized_keys`;
- the untranslated control is unchanged;
- a field with both `description` and `inlineHelpText` gets the
translation on `description`, and `inlineHelpText` is untouched;
- a diverged `description` is kept in zh-CN and en, through the type
dispatch, while the undiverged sibling is translated;
- a field the base does not declare counts as diverged;
- with no packaged base (`undefined`, `null`, or omitted) the catalog
applies;
- an absent `description` is filled by the catalog;
- array-shaped fields are judged against an array-shaped base;
- the input is not mutated.
No existing pin asserted a served field `help`. I searched every test
outside the bundle suites, so none had to move.
**Ablation**, run on the committed head. Each leg used
`scripts/ablation-replace.mjs` in WRAP mode plus a trap. Predictions
were written down before the run. Both legs were restored, with the
restored blob equal to HEAD (`a8eade91`) and `git diff HEAD` empty:
| leg | mutation (anchor 1 → 0 on disk) | predicted | observed |
|---|---|---|---|
| 1 | restore BASE's two lines (write `next.help`, never `description`)
| 7 failed / 2 passed (control and no-mutation stay green) | `Tests 7
failed \| 2 passed` |
| 2 | flat overlay (the D9.2a comparison replaced by `true`) | 3 failed:
the diverged, undeclared-field and array cases | `Tests 3 failed \| 6
passed` |
- Leg 1 sample: `expected 'Whether two-factor authentication is …' to be
'该用户是否已启用双因素认证。…'`.
- Leg 2 sample: `expected '该用户是否已启用双因素认证。…' to be 'Edited by the
tenant.'`.
**Tests**
- `@objectstack/spec`, full local project: `Test Files 619 passed`,
`Tests 18480 passed | 1 todo`.
- `pnpm --filter @objectstack/spec typecheck`: exit 0. Its test layer
compiles under `tsconfig.test.json` with the identity-pinned debt held.
- `@objectstack/service-analytics`: `typecheck` exit 0. The three
dimension/label suites that call `translateObject`: `Tests 53 passed`.
- Targeted eslint over the two changed `.ts` files: 0 errors and 0
warnings. That run is not the repo-wide lint, which is CI's.
**Gates.** `node scripts/pm/dispatch-gates.mjs --repo
objectstack-ai/objectstack --ran` derived 85 families: 84 ran with exit
0 and 1 is NOT MEASURED.
- The NOT MEASURED one is `pnpm check:dual-build-cjs-loads`, which exits
3 with `PREREQUISITE NOT MET` because 78 packages have no `dist/`.
- Narrowed in its place: all 19 `require` entries of
`@objectstack/spec`'s `exports` load from the rebuilt `dist`, and
`system.translateObject` is a function.
- `pnpm check:lean-entry-closure` first answered exit 3 (`objectql/core`
unbuilt). After `turbo run build --filter=@objectstack/objectql...` it
answered exit 0, and that is the recorded code.
**Ships:** `npm pack --dry-run` of `@objectstack/spec` lists
`dist/system/index.js`, `.mjs` and `.d.ts`. Both runtime files carry
`packagedObjectField` and no `next.help = translatedHelp`.
**Base:** origin/main moved to `a3bd157730` (#21947, test titles under
`packages/spec/src/ui/` only). None of this PR's files is touched, so it
is not merged.
## Known readers in objectui
objectui at `.objectui-sha` `0abd4f9f`, read-only. No objectui file is
edited here.
- `packages/plugin-form/src/ObjectForm.tsx:1033` and
`packages/plugin-form/src/sectionFields.ts:311` (`field.help ||
field.description`), and
`packages/app-shell/src/utils/resolveActionParams.ts:714`
(`param.helpText ?? field.help ?? field.description`).
- All three fall back to `description`, so they render the same
translated text, and their `help` arm is now dead. Retiring those arms
is objectui's job.
- The ingestion warning is
`packages/core/src/utils/reference-keys.ts:362`, reached through the
`no-declared-twin` arm (`:415`) of `canonicalizeRetiredFieldKeys`. It
fires for any undeclared key on a served field def, so it goes quiet
once no `help` is served.
## Acceptance notes
None of these is addressed in this PR.
1. **Studio `saveFields` write-back.** NOT MEASURED; this is a read-only
inference.
- objectui `packages/app-shell/src/services/MetadataService.ts:898` to
`:939` carries per-field server keys from the translated read back into
the object PUT.
- `help` is not in objectui's `RETIRED_FIELD_KEYS`
(`packages/types/src/internal/retired-field-keys.ts`). So a field save
on a platform object with bundle `help` entries should have sent a key
`FieldSchema` refuses.
- This PR removes the source.
- Carrier: this PR. Reach would need one measured PUT.
2. **The extractor's `field.help ??` arm**
(`packages/cli/src/utils/i18n-extract.ts:1223`) reads a key
`FieldSchema` refuses, so it is dead on every spec-valid field. Carrier:
`domain:cli`; none in flight.
3. **Field `placeholder` is never overlaid.** `FieldTranslationSchema`
declares `placeholder`, and the extractor emits
`objects.OBJECT.fields.FIELD.placeholder` (`:1224`), but
`translateField` never overlays it. The nine shipped bundles carry 0
field-level placeholder entries (the 4 per locale are action params), so
it is dormant. Carrier: none.
4. **`inlineHelpText` has no translation path.** The extractor never
reads it, so an authored one is never offered for translation. The nine
bundle sources author 0 of them. Carrier: none.
5. **Docs line.** `content/docs/protocol/kernel/i18n-standard.mdx:166`
lists a field's `label` / `help` / `placeholder` as display labels, but
`FieldSchema` declares no `help`. Carrier: none.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01T9u38rswFp5Rw8DswRUReJ)_
---------
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 80f9f7e commit bab7685
3 files changed
Lines changed: 257 additions & 11 deletions
File tree
- .changeset
- packages/spec/src/system
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3548 | 3548 | | |
3549 | 3549 | | |
3550 | 3550 | | |
| 3551 | + | |
| 3552 | + | |
| 3553 | + | |
| 3554 | + | |
| 3555 | + | |
| 3556 | + | |
| 3557 | + | |
| 3558 | + | |
| 3559 | + | |
| 3560 | + | |
| 3561 | + | |
| 3562 | + | |
| 3563 | + | |
| 3564 | + | |
| 3565 | + | |
| 3566 | + | |
| 3567 | + | |
| 3568 | + | |
| 3569 | + | |
| 3570 | + | |
| 3571 | + | |
| 3572 | + | |
| 3573 | + | |
| 3574 | + | |
| 3575 | + | |
| 3576 | + | |
| 3577 | + | |
| 3578 | + | |
| 3579 | + | |
| 3580 | + | |
| 3581 | + | |
| 3582 | + | |
| 3583 | + | |
| 3584 | + | |
| 3585 | + | |
| 3586 | + | |
| 3587 | + | |
| 3588 | + | |
| 3589 | + | |
| 3590 | + | |
| 3591 | + | |
| 3592 | + | |
| 3593 | + | |
| 3594 | + | |
| 3595 | + | |
| 3596 | + | |
| 3597 | + | |
| 3598 | + | |
| 3599 | + | |
| 3600 | + | |
| 3601 | + | |
| 3602 | + | |
| 3603 | + | |
| 3604 | + | |
| 3605 | + | |
| 3606 | + | |
| 3607 | + | |
| 3608 | + | |
| 3609 | + | |
| 3610 | + | |
| 3611 | + | |
| 3612 | + | |
| 3613 | + | |
| 3614 | + | |
| 3615 | + | |
| 3616 | + | |
| 3617 | + | |
| 3618 | + | |
| 3619 | + | |
| 3620 | + | |
| 3621 | + | |
| 3622 | + | |
| 3623 | + | |
| 3624 | + | |
| 3625 | + | |
| 3626 | + | |
| 3627 | + | |
| 3628 | + | |
| 3629 | + | |
| 3630 | + | |
| 3631 | + | |
| 3632 | + | |
| 3633 | + | |
| 3634 | + | |
| 3635 | + | |
| 3636 | + | |
| 3637 | + | |
| 3638 | + | |
| 3639 | + | |
| 3640 | + | |
| 3641 | + | |
| 3642 | + | |
| 3643 | + | |
| 3644 | + | |
| 3645 | + | |
| 3646 | + | |
| 3647 | + | |
| 3648 | + | |
| 3649 | + | |
| 3650 | + | |
| 3651 | + | |
| 3652 | + | |
| 3653 | + | |
| 3654 | + | |
| 3655 | + | |
| 3656 | + | |
| 3657 | + | |
| 3658 | + | |
| 3659 | + | |
| 3660 | + | |
| 3661 | + | |
| 3662 | + | |
| 3663 | + | |
| 3664 | + | |
| 3665 | + | |
| 3666 | + | |
| 3667 | + | |
| 3668 | + | |
| 3669 | + | |
| 3670 | + | |
| 3671 | + | |
| 3672 | + | |
| 3673 | + | |
| 3674 | + | |
| 3675 | + | |
| 3676 | + | |
| 3677 | + | |
| 3678 | + | |
| 3679 | + | |
| 3680 | + | |
| 3681 | + | |
| 3682 | + | |
| 3683 | + | |
| 3684 | + | |
| 3685 | + | |
| 3686 | + | |
| 3687 | + | |
| 3688 | + | |
| 3689 | + | |
| 3690 | + | |
| 3691 | + | |
| 3692 | + | |
| 3693 | + | |
| 3694 | + | |
| 3695 | + | |
| 3696 | + | |
| 3697 | + | |
| 3698 | + | |
| 3699 | + | |
| 3700 | + | |
| 3701 | + | |
| 3702 | + | |
| 3703 | + | |
| 3704 | + | |
| 3705 | + | |
| 3706 | + | |
| 3707 | + | |
| 3708 | + | |
| 3709 | + | |
| 3710 | + | |
| 3711 | + | |
| 3712 | + | |
| 3713 | + | |
| 3714 | + | |
| 3715 | + | |
| 3716 | + | |
| 3717 | + | |
| 3718 | + | |
| 3719 | + | |
3551 | 3720 | | |
3552 | 3721 | | |
3553 | 3722 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1419 | 1419 | | |
1420 | 1420 | | |
1421 | 1421 | | |
| 1422 | + | |
| 1423 | + | |
| 1424 | + | |
| 1425 | + | |
| 1426 | + | |
| 1427 | + | |
| 1428 | + | |
| 1429 | + | |
| 1430 | + | |
| 1431 | + | |
| 1432 | + | |
| 1433 | + | |
| 1434 | + | |
| 1435 | + | |
| 1436 | + | |
| 1437 | + | |
| 1438 | + | |
| 1439 | + | |
| 1440 | + | |
| 1441 | + | |
| 1442 | + | |
| 1443 | + | |
| 1444 | + | |
| 1445 | + | |
| 1446 | + | |
| 1447 | + | |
| 1448 | + | |
| 1449 | + | |
| 1450 | + | |
| 1451 | + | |
1422 | 1452 | | |
1423 | 1453 | | |
1424 | 1454 | | |
| |||
2414 | 2444 | | |
2415 | 2445 | | |
2416 | 2446 | | |
| 2447 | + | |
| 2448 | + | |
| 2449 | + | |
| 2450 | + | |
| 2451 | + | |
| 2452 | + | |
2417 | 2453 | | |
2418 | 2454 | | |
2419 | 2455 | | |
2420 | | - | |
2421 | 2456 | | |
2422 | 2457 | | |
2423 | 2458 | | |
| |||
2906 | 2941 | | |
2907 | 2942 | | |
2908 | 2943 | | |
2909 | | - | |
| 2944 | + | |
| 2945 | + | |
2910 | 2946 | | |
2911 | 2947 | | |
2912 | 2948 | | |
| |||
2949 | 2985 | | |
2950 | 2986 | | |
2951 | 2987 | | |
2952 | | - | |
2953 | | - | |
2954 | | - | |
2955 | | - | |
2956 | | - | |
2957 | | - | |
2958 | | - | |
| 2988 | + | |
| 2989 | + | |
| 2990 | + | |
| 2991 | + | |
| 2992 | + | |
| 2993 | + | |
| 2994 | + | |
| 2995 | + | |
| 2996 | + | |
| 2997 | + | |
| 2998 | + | |
| 2999 | + | |
| 3000 | + | |
| 3001 | + | |
| 3002 | + | |
| 3003 | + | |
| 3004 | + | |
| 3005 | + | |
| 3006 | + | |
| 3007 | + | |
| 3008 | + | |
| 3009 | + | |
| 3010 | + | |
| 3011 | + | |
| 3012 | + | |
| 3013 | + | |
| 3014 | + | |
| 3015 | + | |
| 3016 | + | |
2959 | 3017 | | |
2960 | 3018 | | |
2961 | 3019 | | |
| |||
2982 | 3040 | | |
2983 | 3041 | | |
2984 | 3042 | | |
| 3043 | + | |
2985 | 3044 | | |
2986 | 3045 | | |
2987 | 3046 | | |
2988 | 3047 | | |
2989 | 3048 | | |
2990 | 3049 | | |
2991 | 3050 | | |
2992 | | - | |
2993 | | - | |
| 3051 | + | |
| 3052 | + | |
| 3053 | + | |
| 3054 | + | |
| 3055 | + | |
| 3056 | + | |
| 3057 | + | |
2994 | 3058 | | |
2995 | 3059 | | |
2996 | 3060 | | |
| |||
0 commit comments