Repository navigation
Commit 3e62a22
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1XNUzphnasmraGeKrcFVQSpZ)_
Fixes #28830
Clause-②: yes (widening)
Metadata-protocol: none
## 维护者速读
-
**改了什么**:邮件模板的分层视图(`/meta/email_template/<名称>/layers`)按基础包名或不带包名读取时,客户在
`BASE.custom` 里新增的语言(基础包没有的,比如 showcase 只发 `en-US`,客户加
`fr-FR`)现在返回配对包那一层(`code` 为空、`overlay` 与 `effective`
是客户的模板),和按名读取、列表、发信一致;依赖包新增的语言在基础包地址下仍是 404,按依赖包名读取才有。
- **为什么改**:PR #28828 之后,配对包新增的语言在按名读取、列表和发信里都由基础包地址提供,只有分层视图还是
404,作者在后台看不到自己改了什么(#28830,PR #28828 合同复核提的「分层读取」标记)。
- **风险与回滚**:低。只改读取侧的一处分支,复用 #28828
已有的同一判定(`pairOfAddedMember`),只在名单类型(`ITEM_KEY_DISCRIMINATORS`,目前只有
`email_template`)且某语言基础包不发时才生效;其它类型字节不变,写入闸门不变。回滚即撤销本 PR。
- **先看**:`packages/metadata-protocol/src/protocol.ts` 的 `[#28830]`
一处(`getMetaItemLayered`)和新的私有方法
`findPairAddedMemberRow`(按名读取与分层读取共用的一次读取)。
- **两分钟验证**:`pnpm --filter @objectstack/dogfood exec vitest run
test/email-template-dependent-unshipped-locale-read.dogfood.test.ts`,预期
12/12 通过(main 上 2 红)。
- **需要你做的**:无,席位落地。
## What changes
Since PR #28828 (option A of #28779, ruling A on #28390), a base's
address serves an email template member its `.custom` pair adds at a
locale the base does not ship: the by-name reads naming the base or no
package, the env-wide and base-scoped lists, `getMetaItemsForExecution`
and `sendTemplate`. The layered read did not: `GET
/meta/email_template/<name>/layers?package=<base>&member=fr-FR` answered
`404` (no code layer, since the base ships no `fr-FR`, and no overlay,
since the served-row candidates of the base's address hold no row at
that member). ADR-0146 D8 lists the reads that must agree; this brings
the layered read in line.
| layered read on the base's address (`?package=BASE` or no package) |
before | after |
|:--|:--|:--|
| base's own member (`en-US`) | `code`: base, `overlay`: null |
unchanged |
| pair's declared override (`en-US`) | `code`: base, `overlay`: override
| unchanged |
| pair's own added member (`fr-FR`) | `404` | **`code: null`,
`overlay`/`effective`: the pair's row** |
| a dependent's added member (`fr-FR`) | `404` | `404` (unchanged;
answers under `?package=DEPENDENT`) |
| pair and dependent both at `fr-FR` | `404` | **the pair's** |
| any non-bundle type | as before | unchanged (the branch needs a bundle
member) |
**`packages/metadata-protocol/src/protocol.ts`.**
- `getMetaItemLayered`: when the served-row resolution finds no row and
the read addresses a bundle member on a package's address, the pair's
own row at that member is the overlay, read by `findPairAddedMemberRow`.
`code` stays as resolved (null: the base ships no such member), so
`effective` is the pair's row.
- `findPairAddedMemberRow` (new, private): the one read of the pair's
row at an added member. It asks PR #28828's `pairOfAddedMember` (the
base ships the name and not the member, else `undefined`) and then
`findServedOverlayRow` naming the pair. `readMetaItem`'s #28802 branch
now calls it too, so the by-name read and the layered read share one
predicate and one read (behaviour of the by-name read unchanged: its
suite and both test files stay green).
- Another package's member never answers here: `pairOfAddedMember` names
only the base's `.custom` pair, so a dependent's row is not read on the
base's address.
## Tests
-
`packages/qa/dogfood/test/email-template-dependent-unshipped-locale-read.dogfood.test.ts`
(real showcase over HTTP, `showcase_task_done_email`): a `layers(member,
pkg?)` probe on the rig and 2 new cases, plus layered assertions folded
into 2 existing ones.
- Pair: the layered read naming the base, naming no package and naming
the pair answers `{code: null, overlay: pair's subject, effective:
pair's subject}` for `fr-FR`; the base's `en-US` layers unchanged.
- Dependent: `fr-FR` stays 404 on the base and package-less layered
reads and answers under `?package=DEPENDENT`; base `en-US` unchanged.
- Pair beside dependent at `fr-FR`: the base's layered read answers the
pair's.
- Control: the pair's declared `en-US` override answers `{code: shipped,
overlay: override, effective: override}`, and `fr-FR` on the base with
only that override stored is 404.
- RED on main `1920e480`: 2 failed / 10 passed (the pair case and the
pair-beside-dependent case). GREEN at `c53513be`: 12/12 (os-verify-lock
VERDICT command-exit 0).
- `packages/objectql/src/protocol-bundle-member-base-address.test.ts`
(real protocol, real engine, in-memory driver): a `layersOf` helper and
a `[#28830]` describe with 4 cases: the pair's added member on the base,
package-less and pair addresses; a dependent's member 404 on the base
and answered under the dependent; pair and dependent at one locale;
control (declared `en-US` override, and a non-bundle `view` answering
`{code: base columns, overlay: null}` as before). GREEN 10/10 at
`c53513be`.
- Ablation, one leg (the seam): `if (row) served = { row };` → `void
row;` through `scripts/ablation-replace.mjs` (anchor 1 → 0, restore blob
== HEAD verified), `metadata-protocol` rebuilt and the mutation proved
absent from `dist/` by `ablation-dist-preflight.mjs --absent`. Unit: 2
red (the pair's added member; pair beside dependent), 8 green. Dogfood:
2 red (the same two), 10 green. The dependent cases and every control
stay green. A restore build followed, the marker proved present again.
- Package suites at this head: see Verification.
## Acceptance notes
- **The `version` token (measured, not changed).** On main `1920e480`,
showcase, pair-added `fr-FR`: the by-name read naming the base answers
`version: null`; the package-less and pair-named reads answer the pair
row's token (`hmac-sha256:a8a29081…`); the base's own `en-US` read
naming the base answers `null` (no stored row at the base's address).
`version` is `readVersionToken` at the request's address, so naming the
base it reads the base's row at `fr-FR`, which does not exist. Not the
same seam (the token is the OCC pin of a save at that address, and a
save naming the base at a member only the pair adds is the write gate's
question), so it is not changed here; reported for the seat.
- **`Metadata-protocol: none`.** Nothing an author can write changed (no
key, value or metadata type added or refused) and no meaning changed:
what a pair-added locale means on the base's address was decided by
#28828; this read now reports it. Changeset `patch`.
- **Stamp.** The layered read reports layers, not a `_packageId` stamp
of its own; the `overlay` is the pair's stored document as stored.
- **`overlayRow`** (what `declinesStoredRow` judges a shipped flow name
on) is set from the pair's row too; it only matters for `flow`, which is
no bundle type.
- **Overlap re-read** before `pr_create`: open PRs touching
`packages/metadata-protocol/src/` are #28731 (`protocol.ts`, the by-id
OCC comparison near line 14450), #28764 (`metadata-redaction.ts`) and
#28838 (one test file). `git merge-tree` against this head: no conflict
with any; none touches `readMetaItem`, `getMetaItemLayered` or the
#28802 helpers. Seat 1's #28831 (the per-package layer's provenance) has
no open PR yet.
## Verification
Package suites at `c53513be`: `@objectstack/metadata-protocol` typecheck
+ test (297 files passed, 4 skipped; 22080 tests passed),
`@objectstack/objectql` typecheck + test (521 files, 10008 tests
passed), both under the lock, VERDICT command-exit 0.
Gate sweep at `c53513be`: `dispatch-gates --commands` derived 66
families (the same 66 as PR #28828); 66 run, all exit 0 (`dispatch-gates
--ran` reads "66 run, 0 NOT-MEASURED", a derived zero). One first ran
exit 3 on a prerequisite and was re-run green:
`check:dual-build-cjs-loads` (seven packages outside the dogfood closure
were unbuilt). The record is `pm-orders/server/28830-gates-ran.txt` in
the project files.
Full dogfood battery: not run. The arm is `(widening)` and the title
carries no `!`; the two touched test files ran as above.
Changeset `.changeset/28830-layered-read-pair-added-member.md`:
`@objectstack/metadata-protocol` patch, both declaration lines. CI
families are read from this PR's check-runs, not re-run here.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5m2Ryfx2Wubuz716mw)_
🤖 Generated with [Claude Code](https://claude.com/claude-code)
https://claude.ai/code/session_01FEkQ5m2Ryfx2Wubuz716mw
Co-authored-by: Claude <noreply@anthropic.com>
1 parent b95a856 commit 3e62a22
4 files changed
Lines changed: 140 additions & 8 deletions
File tree
- .changeset
- packages
- metadata-protocol/src
- objectql/src
- qa/dogfood/test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
11630 | 11630 | | |
11631 | 11631 | | |
11632 | 11632 | | |
11633 | | - | |
11634 | | - | |
11635 | | - | |
11636 | | - | |
11637 | | - | |
11638 | | - | |
| 11633 | + | |
11639 | 11634 | | |
11640 | 11635 | | |
11641 | 11636 | | |
| |||
12335 | 12330 | | |
12336 | 12331 | | |
12337 | 12332 | | |
12338 | | - | |
| 12333 | + | |
12339 | 12334 | | |
12340 | 12335 | | |
12341 | 12336 | | |
12342 | 12337 | | |
12343 | 12338 | | |
12344 | 12339 | | |
12345 | 12340 | | |
| 12341 | + | |
| 12342 | + | |
| 12343 | + | |
| 12344 | + | |
| 12345 | + | |
| 12346 | + | |
| 12347 | + | |
12346 | 12348 | | |
12347 | 12349 | | |
12348 | 12350 | | |
| |||
17525 | 17527 | | |
17526 | 17528 | | |
17527 | 17529 | | |
| 17530 | + | |
| 17531 | + | |
| 17532 | + | |
| 17533 | + | |
| 17534 | + | |
| 17535 | + | |
| 17536 | + | |
| 17537 | + | |
| 17538 | + | |
| 17539 | + | |
| 17540 | + | |
| 17541 | + | |
| 17542 | + | |
| 17543 | + | |
| 17544 | + | |
| 17545 | + | |
| 17546 | + | |
| 17547 | + | |
17528 | 17548 | | |
17529 | 17549 | | |
17530 | 17550 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
345 | 345 | | |
346 | 346 | | |
347 | 347 | | |
| 348 | + | |
| 349 | + | |
| 350 | + | |
| 351 | + | |
| 352 | + | |
| 353 | + | |
| 354 | + | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
| 358 | + | |
| 359 | + | |
| 360 | + | |
| 361 | + | |
| 362 | + | |
| 363 | + | |
| 364 | + | |
| 365 | + | |
| 366 | + | |
| 367 | + | |
| 368 | + | |
| 369 | + | |
| 370 | + | |
| 371 | + | |
| 372 | + | |
| 373 | + | |
| 374 | + | |
| 375 | + | |
| 376 | + | |
| 377 | + | |
| 378 | + | |
| 379 | + | |
| 380 | + | |
| 381 | + | |
| 382 | + | |
| 383 | + | |
| 384 | + | |
| 385 | + | |
| 386 | + | |
| 387 | + | |
| 388 | + | |
| 389 | + | |
| 390 | + | |
| 391 | + | |
| 392 | + | |
| 393 | + | |
| 394 | + | |
| 395 | + | |
| 396 | + | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
| 402 | + | |
| 403 | + | |
| 404 | + | |
| 405 | + | |
| 406 | + | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
| 412 | + | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
75 | 75 | | |
76 | 76 | | |
77 | 77 | | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
78 | 86 | | |
79 | 87 | | |
80 | 88 | | |
| |||
133 | 141 | | |
134 | 142 | | |
135 | 143 | | |
136 | | - | |
| 144 | + | |
137 | 145 | | |
138 | 146 | | |
139 | 147 | | |
| |||
179 | 187 | | |
180 | 188 | | |
181 | 189 | | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
182 | 200 | | |
183 | 201 | | |
184 | 202 | | |
| |||
195 | 213 | | |
196 | 214 | | |
197 | 215 | | |
| 216 | + | |
| 217 | + | |
| 218 | + | |
198 | 219 | | |
199 | 220 | | |
200 | 221 | | |
| |||
223 | 244 | | |
224 | 245 | | |
225 | 246 | | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
226 | 257 | | |
227 | 258 | | |
228 | 259 | | |
| |||
240 | 271 | | |
241 | 272 | | |
242 | 273 | | |
| 274 | + | |
| 275 | + | |
243 | 276 | | |
244 | 277 | | |
245 | 278 | | |
| |||
0 commit comments