Repository navigation
Commit 59775a0
fix(spec): a published fieldPatches label is served by every object read, not only /layers (#29624)
<!-- claude-projects-attribution: {"github_login":"os-warren"} -->
_Requested by **Warren** · [project
thread](https://claude.ai/code/project/chan_01U5RdnAAmkSQmZbqh6FtqZ8?thread=cmsg_01U5RdnAAmkSQmZbqh6FtqZ8Mwj3s3TJDLo1t9qXkT1euk)_
Fixes #29564
Clause-②: no
Metadata-protocol: none
## 维护者速读
- 改了什么:`translateObject` 的字段 `label` 与选项 `label` 两个槽位改走既有的
`valueOverridesPackagedBase` 比较,与 `description` / `inlineHelpText` /
`inlineTitle` 及对象三标量同一条规则。
- 为什么改:对象扩展发布的 `fieldPatches` 改了字段标签后,只有 `/layers` 能看到,无包名读、`?package=`
基础包读和列表读都被目录(catalog)里的出厂标签盖回去了。
- 风险与回滚:租户覆盖层对字段标签或选项标签的改名,从此也会压过目录翻译(与对象改名 #8284 同理);回滚即还原
`i18n-resolver.ts` 的两处判断。
- 先看:`packages/spec/src/system/i18n-resolver.ts` 的
`translateField`(两处新判断与选项基线的取法),再看
`packages/rest/src/meta-object-field-patch-i18n.test.ts`。
- 两分钟验证:`pnpm --filter @objectstack/rest exec vitest run
src/meta-object-field-patch-i18n.test.ts`(先建 spec),预期 7/7 通过,补丁标签
`Headline` / `Queued` 在 zh-CN 与 en 两个语言下都原样返回。
- 需要你做的:无,席位落地。
## What changes
- `packages/spec/src/system/i18n-resolver.ts`, `translateObject` →
`translateField`:
- The field `label` (catalog, then the built-in system-field label) is
applied only while `valueOverridesPackagedBase(packagedField, 'label',
def.label)` is false, i.e. only while the served label still equals the
same field's label in `packagedBase`.
- Each option label is applied only while it still equals the label of
the packaged field's option with the same `value` (found with the
existing `packagedPart` finder, matched by `String(value)` as the
dashboard filter options are).
- A picklist-bound served field (`picklist` set) is judged against no
field-level baseline: its options are the list's, resolved onto the
served field on every read (`resolvePicklistFieldsOnto`) and never
present on the packaged declaration, so the catalog (field-level, then
`picklists.LIST`) applies to them exactly as before. The registry fold
never applies an option patch to a picklist-bound field either.
- The docblock paragraph that said a field label stays a flat `catalog
?? document` now states the rule above.
- One comparison, no second application: nothing re-applies the patch
after translation; the two slots ask the same predicate their siblings
ask.
## Why
ADR-0146 D10 admits a base field's `label` and option `label` through an
object extension's `fieldPatches`, and the registry folds the patch onto
every read. The served `/meta` exit
(`packages/rest/src/meta-item-read-gate.ts`, `translateMetaDocument` /
`translateMetaList`) localizes the folded body with
`translateMetadataDocument('object', …)`, which wrote the catalog's
field label and option labels unconditionally. The showcase catalog
carries an `en` entry for every `showcase_task` field, so the shipped
text replaced the patch on the bare, `?package=` and list reads
(reproduced on `main` `50e35a28`, report 6588058932). The objectql pin
reads registry bodies directly and never runs this localization, which
is why it stayed green.
## Tests
- `packages/spec/src/system/i18n-resolver.test.ts`: new block
"translateObject — a field label and its option labels yield to a
diverged value" (9 cases: the patched label and option through the type
dispatch in `en` and `zh-CN`; per-field and per-option judgment;
untouched document; no base; absent or empty served label; a field or
option the base does not declare; a picklist-bound field keeps the
list's labels; an injected system field's built-in label; no input
mutation). The old case "leaves FIELD labels alone — the rule is scoped
to the three scalars" pinned exactly the branch this changes, so it is
replaced by "judges a FIELD label by the same rule".
- `packages/rest/src/meta-object-field-patch-i18n.test.ts` (new, 7
cases): a REAL `SchemaRegistry` with an owner and a `fieldPatches`
extender; the protocol double's `getPackagedObjectBase` reads the
registry. It drives `translateMetaDocument` and `translateMetaList` and
asserts the patched field label, patched description and patched option
label in `zh-CN` and `en`, the untouched siblings still translated, and
the no-extension control.
## Acceptance notes
- Side effect, by the #8284 rule: a tenant overlay's rename of a field
label or option label is now served over the catalog too, the way an
object rename already is.
- A field the packaged base does not declare (an extension's own field)
counts as diverged on every slot, as its `description` /
`inlineHelpText` slots already did. So a catalog entry for such a
field's label is no longer served. In this repository no producer writes
one: the i18n extractor walks `objects` only, and no generated bundle
carries an extension field. Named here because a third-party bundle
could.
- Not changed, noted only: `formula-option-labels.ts` (objectql) and the
analytics dimension labels call `translateObject` without a
`packagedBase`, so they keep applying the catalog unconditionally (no
base means the rule infers nothing). Not measured to diverge on a public
read.
## Verification
Head `6d0f0e01`, base `origin/main` `81cd9eb0`.
<details><summary>Ablation (both slots), each leg rebuilt and proved in
dist</summary>
Each leg: `node scripts/ablation-replace.mjs` (anchor 1 → 0, blob
changed), `pnpm --filter @objectstack/spec build`, `node
scripts/ablation-dist-preflight.mjs @objectstack/spec MARKER` (marker
present in 2 built files), then both pins; the tool restored the source
(blob equals HEAD, `git diff HEAD` empty).
- Label slot (the guard made always-true): spec pin 3 failed / 389
passed; REST pin 4 failed / 3 passed.
- Option slot (the early return disabled): spec pin 2 failed / 390
passed; REST pin 4 failed / 3 passed.
- Restore: spec rebuilt, preflight `--absent` for both markers (absent
from all 588 built files, tree clean); spec pin 392/392, REST pin 7/7.
</details>
<details><summary>Package suites</summary>
- `pnpm --filter @objectstack/spec test`: 801 files, 23707 passed, 1
todo. `pnpm --filter @objectstack/spec typecheck`: green (test layer
OK).
- `pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2`: 384
files, 7402 passed, 352 skipped. `pnpm --filter @objectstack/rest
typecheck`: green.
</details>
<details><summary>Derived gates</summary>
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` at `6d0f0e01`: 79 families. Reconciled with
`--ran`: 79 accounted, 78 run with exit 0, 1 NOT MEASURED: `pnpm
check:dual-build-cjs-loads` exit 3 (prerequisite: the whole workspace's
`dist/` is not built in this container; left to CI).
`check-plugin-teardown-shape.mjs --self-test` first exited 3 on the
shallow clone; after fetching its pinned fixture commit it exits 0 (48
cases). Local-only: `check:skill-frame-freshness` 0; `check:dev-prereqs`
refuses (35 workspace packages unbuilt, only the rest closure was
built).
</details>
## Human Minimum
- [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic.
- [x] 2. Every name I added uses the casing for its kind.
- [ ] 3. No formatter ran; `pnpm lint` passes. (No formatter ran; `pnpm
lint` was not run locally, it is CI's run.)
- [x] 4. One issue, one branch off an up-to-date `main`, one pull
request.
- [x] 5. A change that publishes carries a changeset, and both
declaration lines are filled in here and in the changeset.
- [x] 6. `packages/spec` touched: its generated artifacts are
regenerated and committed. (none were stale: the derived spec checks are
green)
- [x] 7. No hand edits to `content/docs/references/`,
`packages/*/CHANGELOG.md` or `content/docs/releases/`.
- [x] 8. Title, body and comments are in English.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01JQwxbX91BzYkHsRob9kBV8)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 4008e62 commit 59775a0
4 files changed
Lines changed: 376 additions & 16 deletions
File tree
- .changeset
- packages
- rest/src
- 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 | + | |
| 14 | + | |
| 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 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
| 125 | + | |
| 126 | + | |
| 127 | + | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
| 131 | + | |
| 132 | + | |
| 133 | + | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
| 137 | + | |
| 138 | + | |
| 139 | + | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
3878 | 3878 | | |
3879 | 3879 | | |
3880 | 3880 | | |
3881 | | - | |
3882 | | - | |
3883 | | - | |
3884 | | - | |
3885 | | - | |
| 3881 | + | |
| 3882 | + | |
| 3883 | + | |
| 3884 | + | |
| 3885 | + | |
| 3886 | + | |
| 3887 | + | |
3886 | 3888 | | |
3887 | 3889 | | |
3888 | 3890 | | |
| |||
3894 | 3896 | | |
3895 | 3897 | | |
3896 | 3898 | | |
3897 | | - | |
| 3899 | + | |
3898 | 3900 | | |
3899 | | - | |
| 3901 | + | |
3900 | 3902 | | |
3901 | 3903 | | |
3902 | 3904 | | |
| |||
3921 | 3923 | | |
3922 | 3924 | | |
3923 | 3925 | | |
| 3926 | + | |
| 3927 | + | |
| 3928 | + | |
| 3929 | + | |
| 3930 | + | |
| 3931 | + | |
| 3932 | + | |
| 3933 | + | |
| 3934 | + | |
| 3935 | + | |
| 3936 | + | |
| 3937 | + | |
| 3938 | + | |
| 3939 | + | |
| 3940 | + | |
| 3941 | + | |
| 3942 | + | |
| 3943 | + | |
| 3944 | + | |
| 3945 | + | |
| 3946 | + | |
| 3947 | + | |
| 3948 | + | |
| 3949 | + | |
| 3950 | + | |
| 3951 | + | |
| 3952 | + | |
| 3953 | + | |
| 3954 | + | |
| 3955 | + | |
| 3956 | + | |
| 3957 | + | |
| 3958 | + | |
| 3959 | + | |
| 3960 | + | |
| 3961 | + | |
| 3962 | + | |
| 3963 | + | |
| 3964 | + | |
| 3965 | + | |
| 3966 | + | |
| 3967 | + | |
| 3968 | + | |
| 3969 | + | |
| 3970 | + | |
| 3971 | + | |
| 3972 | + | |
| 3973 | + | |
| 3974 | + | |
| 3975 | + | |
| 3976 | + | |
| 3977 | + | |
| 3978 | + | |
| 3979 | + | |
| 3980 | + | |
| 3981 | + | |
| 3982 | + | |
| 3983 | + | |
| 3984 | + | |
| 3985 | + | |
| 3986 | + | |
| 3987 | + | |
| 3988 | + | |
| 3989 | + | |
| 3990 | + | |
| 3991 | + | |
| 3992 | + | |
| 3993 | + | |
| 3994 | + | |
| 3995 | + | |
| 3996 | + | |
| 3997 | + | |
| 3998 | + | |
| 3999 | + | |
| 4000 | + | |
| 4001 | + | |
| 4002 | + | |
| 4003 | + | |
| 4004 | + | |
| 4005 | + | |
| 4006 | + | |
| 4007 | + | |
| 4008 | + | |
| 4009 | + | |
| 4010 | + | |
| 4011 | + | |
| 4012 | + | |
| 4013 | + | |
| 4014 | + | |
| 4015 | + | |
| 4016 | + | |
| 4017 | + | |
| 4018 | + | |
| 4019 | + | |
| 4020 | + | |
| 4021 | + | |
| 4022 | + | |
| 4023 | + | |
| 4024 | + | |
| 4025 | + | |
| 4026 | + | |
| 4027 | + | |
| 4028 | + | |
| 4029 | + | |
| 4030 | + | |
| 4031 | + | |
| 4032 | + | |
| 4033 | + | |
| 4034 | + | |
| 4035 | + | |
| 4036 | + | |
| 4037 | + | |
| 4038 | + | |
| 4039 | + | |
| 4040 | + | |
| 4041 | + | |
| 4042 | + | |
| 4043 | + | |
| 4044 | + | |
| 4045 | + | |
| 4046 | + | |
| 4047 | + | |
| 4048 | + | |
| 4049 | + | |
| 4050 | + | |
| 4051 | + | |
| 4052 | + | |
| 4053 | + | |
| 4054 | + | |
| 4055 | + | |
| 4056 | + | |
| 4057 | + | |
| 4058 | + | |
| 4059 | + | |
| 4060 | + | |
| 4061 | + | |
| 4062 | + | |
| 4063 | + | |
| 4064 | + | |
| 4065 | + | |
| 4066 | + | |
| 4067 | + | |
| 4068 | + | |
| 4069 | + | |
| 4070 | + | |
| 4071 | + | |
| 4072 | + | |
| 4073 | + | |
| 4074 | + | |
| 4075 | + | |
| 4076 | + | |
| 4077 | + | |
| 4078 | + | |
| 4079 | + | |
| 4080 | + | |
| 4081 | + | |
| 4082 | + | |
| 4083 | + | |
3924 | 4084 | | |
3925 | 4085 | | |
3926 | 4086 | | |
| |||
0 commit comments