Skip to content

Commit aa2e740

Browse files
committed
Merge remote-tracking branch 'origin/main' into claude/issue-16233-agents-return-propagating-seams
2 parents cffced2 + c334ba0 commit aa2e740

31 files changed

Lines changed: 3267 additions & 120 deletions
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
---
2+
'@objectstack/platform-objects': minor
3+
'@objectstack/spec': minor
4+
---
5+
6+
Studio's property-panel repeater tables name their columns in the author's own language: every repeater enumerates its row properties in the owning `*.form.ts`, and all four platform catalogs carry a translated name for each one
7+
8+
Clause-②: no
9+
10+
A `type: 'repeater'` renders as a table whose column heads come from the form's declared row children when it declares any, and from the served JSON Schema `items.properties[k].title` when it does not. `os i18n extract` only emits a `metadataForms.<type>.fields['<path>.<prop>']` key for a **declared** child, so a repeater that enumerated none had no localisation channel at all — #17232 (PR #17500) authored English titles on thirteen item schemas, #17505 and #17506 on four more, and every one of those column heads reached a Chinese, Japanese or Spanish author in English.
11+
12+
Both halves land together, because either alone is a half-state: 112 row properties across fifteen repeaters are now enumerated, each with a `label` equal to the item schema's own `.meta({ title })`, and the `en` / `zh-CN` / `ja-JP` / `es-ES` catalogs gain a leaf for each. Nothing in the accept set moves — the same author input parses identically before and after, and no row child declares a `type`, so the row widgets stay schema-derived.
13+
14+
Terms reuse the word each catalog already uses for the concept (`Label` → 显示名称 / 表示名 / Etiqueta, `Filter` → 筛选 / フィルター / Filtro, `Timeout (ms)` → 超时(毫秒)/ タイムアウト(ms)/ Tiempo de espera (ms)), and `field.options.*` mirrors its `object.fields.options.*` twin verbatim.
15+
16+
`page.variables.source` is the one existing string that moves. Its children were enumerated without labels, so the extractor emitted the humanized path `"Source"` as the English source and the bundle overlay then wrote that over the schema's authored `"Written By"`. The form now declares the label, the `en` leaf becomes `Written By`, and its three translations are re-authored with it (写入组件 / 書き込み元 / Escrito por).
17+
18+
`view.columns` / `view.sort` / `view.tabs` are untitled and enumerate no children — they are #17507's, and are untouched here. `object.fields.options` stays the curated four-key subset its reconciliation-ledger entry declares.
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
---
2+
"@objectstack/lint": patch
3+
---
4+
5+
`translation-target-unknown` no longer reports the locale keys a package ships for an object a SIBLING package of the same artifact declares — the OBJECT rung's universe read `stack.objects` alone, while this rule's own docblock already declared the wider `artifactProvidedObjectNames` reach (#19064).
6+
7+
`os build` runs the rule table per PACKAGE as well as over the union (`compile.ts` step 3b-ii): each package body is judged as its own stack with the artifact's `packages[]` beside it as resolution context (`packageBodyAsStack`, #16611). On that leg `stack.objects` holds ONE package's objects, so a bundle key naming a sibling's object resolved against nothing. Measured on the probe stack (`examples/app-multi-package`'s shape — `core` owns `crm_account`, `orders` reads it and here also translates it), the key produced one `error` at `translations[0]["zh-CN"].objects.crm_account`:
8+
9+
> Translations are keyed to "crm_account", which no object in this stack defines. The resolver looks up keys derived from the metadata, so this whole subtree is dead weight — every label it carries renders untranslated.
10+
>
11+
> *Rename the key to the object it was written for, drop it, or ignore this if the object is contributed by another installed package. Defined objects: crm_order.*
12+
13+
That is the remedy that deletes a translation the runtime resolves, at `error`, so the run FAILED on it — and it is byte-identical, but for the name, to the finding a genuine typo produces. ADR-0130 makes the release artifact the co-ownership boundary, so the miss is the RUN's blind spot and not the author's mistake.
14+
15+
**The precedent is followed, not re-decided.** `validateObjectReferences` closed this exact shape on this exact carrier for object NAMES (#16611 — `artifactProvidedObjectNames` folded into its `resolvable` set). What differs here is the RETURN, and two pins hold it: this rule's universe is keyed by FACTS, not names, so the sibling's fields, options, views, sections and rules are folded WITH the name through the same collector the declaration loop uses. A name-only fold would resolve the object key and then judge the owner's own field keys against an empty fact set — the same false positive one level up — and a wholesale subtree skip (rung 2b's answer, for a target whose declaration is genuinely invisible) would leave the per-package leg unable to see a typo the union leg reports.
16+
17+
**The control, which is what makes this a narrowing and not a hole.** Widening a universe trades a false positive for a blind spot unless every genuine orphan still reports, so both directions are pinned side by side: the same package judged ALONE still errors (the context is what does the work); a name no entry of the artifact declares is still an `error` with its rule id, and the remedy now enumerates what the artifact provides; a field the sibling does not declare is still an `error` under the now-resolved object; one bundle carrying both a sibling key and a typo reports exactly the typo; an entry with no readable body (a segment reference) makes nothing addressable; and the single-`defineStack` shape is untouched, because `objects` is a stack collection with no `stack.manifest` form to read.
18+
19+
No schema moved, no export moved, and no accept set moved: this is a lint rule's false-positive set narrowing. `Clause-②: no`
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
---
2+
'@objectstack/cli': patch
3+
---
4+
5+
`collect-docs.ts` records what the `docs/duplicate-name` refusal rests on now that ADR-0048 §3.4 retired its older justification (#19248)
6+
7+
`docs/duplicate-name` refuses two owners declaring one doc name. The claim it
8+
was once explained by — *"one registration overwrites the other"* — was retired
9+
by ADR-0048, and a refusal whose stated justification no longer exists is worth
10+
examining rather than inheriting second-hand. #19248 examined it.
11+
12+
**The verdict is that no wording change was warranted**, and the ADR text is
13+
quoted into the rule's own docblock so the next reader does not have to
14+
re-derive it. §3.4 retires a RUNTIME throw and nothing else — *"The
15+
cross-package **throw is retired**; two distinct packages coexist on the same
16+
bare name by construction."* — while keeping, in the same clause, the class
17+
this lint belongs to: *"Authoring-time hygiene — an author shipping two
18+
`page/home` in one package — stays covered by the `naming/namespace-prefix`
19+
lint in `os lint`."* Both sentences are quoted verbatim, checked against
20+
`docs/adr/0048-cross-package-metadata-collision.md` on this branch's base
21+
(`13d52947d8`) rather than recalled.
22+
23+
The message already said `for authoring hygiene` and already declined the
24+
retired claim by name, so what shipped was correct and stays byte-identical.
25+
What the docblock gains is the ADR's own words, the card number the standing
26+
**severity** disagreement is filed under, and the boundary between the two
27+
questions: §3.4 hands authoring hygiene to a warning-only lint while this one
28+
is `severity: 'error'`, which is a live question about the level and not about
29+
the reason.
30+
31+
⛔ No behaviour changes. No rule, message, severity or accept set moves; the
32+
only edited bytes are inside one docblock comment.
33+
34+
**This ships, which is why it carries a changeset rather than
35+
`skip-changeset`.** `@objectstack/cli`'s published `files[]` is
36+
`["dist","README.md","CHANGELOG.md"]` and the package builds with plain `tsc`
37+
(`tsc -p tsconfig.build.json`, no `removeComments`), so the comment is emitted
38+
into the tarball — measured on the rebuilt artifact: the new clause is present
39+
in `dist/utils/collect-docs.js` (1 occurrence), the replaced spelling is absent
40+
from all of `dist` (0), and `dist/**/*.d.ts` carries 0 of it because the block
41+
sits above a non-exported helper. The rule's own runtime message resolves to
42+
that same file as the positive control. So the published JS bytes move while
43+
the declaration surface does not.

‎.github/actions/setup-pnpm/action.yml‎

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,15 @@
4747
# this action materialised the pin, with an assertion in between -- is what
4848
# makes a job structurally unable to donate an unpinned manager to the cache.
4949
#
50-
# Deliberately NOT in here: `actions/setup-node`. `scripts/check-node-version.mjs`
51-
# scans `.github/workflows/*.yml` ONLY, and reports how many setup-node steps it
52-
# audited. Moving those steps into this composite would drop them from its census
53-
# and it would still print OK -- a gate silently auditing less than it says.
54-
# Callers keep their own `setup-node` step, with its literal `node-version` pin.
50+
# Deliberately NOT in here: `actions/setup-node`. The reason was a gate's blind
51+
# spot -- `scripts/check-node-version.mjs` scanned `.github/workflows/*.yml`
52+
# only, so a setup-node step moved into this composite would have dropped out of
53+
# its census while it still printed OK, a gate silently auditing less than it
54+
# says. That blind spot is CLOSED (#19229): the census now reads
55+
# `.github/actions/**` as well, and a step's Node pin is audited wherever it is
56+
# written. The separation is kept anyway, because the callers' own pins are
57+
# already in place and moving them buys nothing -- ⛔ it is no longer a
58+
# constraint, and a future composition is free to hold one.
5559

5660
name: Setup pnpm
5761
description: >-

‎.github/workflows/checklist-status.yml‎

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,10 +114,11 @@ jobs:
114114
- name: Checkout repository
115115
uses: actions/checkout@v7
116116

117-
# Kept as this job's own step rather than folded into the composite below:
118-
# `scripts/check-node-version.mjs` scans `.github/workflows/*.yml` only and
119-
# reports how many setup-node steps it audited, so a step moved out of
120-
# sight would silently shrink its census.
117+
# Kept as this job's own step rather than folded into the composite below.
118+
# ⛔ No longer because a gate cannot see it: `scripts/check-node-version.mjs`
119+
# reads `.github/actions/**` too since #19229, so its census follows a
120+
# setup-node step wherever it is written. Kept because the pin is already
121+
# here and moving it buys nothing.
121122
- name: Setup Node.js
122123
uses: actions/setup-node@v7
123124
with:

‎.github/workflows/platform-checklist-watchdog.yml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,10 @@ jobs:
193193
uses: actions/checkout@v7
194194

195195
# Kept as this job's own step rather than folded into the composite
196-
# below: `scripts/check-node-version.mjs` scans `.github/workflows/*.yml`
197-
# only and reports how many setup-node steps it audited, so a step moved
198-
# out of sight would silently shrink its census.
196+
# below. ⛔ No longer because a gate cannot see it:
197+
# `scripts/check-node-version.mjs` reads `.github/actions/**` too since
198+
# #19229, so its census follows a setup-node step wherever it is written.
199+
# Kept because the pin is already here and moving it buys nothing.
199200
- name: Setup Node.js
200201
uses: actions/setup-node@v7
201202
with:

‎.github/workflows/test-nightly-tiers.yml‎

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -161,9 +161,10 @@ jobs:
161161
uses: actions/checkout@v7
162162

163163
# Kept as this job's own step rather than folded into the composite
164-
# below: `scripts/check-node-version.mjs` scans `.github/workflows/*.yml`
165-
# only and reports how many setup-node steps it audited, so a step moved
166-
# out of sight would silently shrink its census.
164+
# below. ⛔ No longer because a gate cannot see it:
165+
# `scripts/check-node-version.mjs` reads `.github/actions/**` too since
166+
# #19229, so its census follows a setup-node step wherever it is written.
167+
# Kept because the pin is already here and moving it buys nothing.
167168
- name: Setup Node.js
168169
uses: actions/setup-node@v7
169170
with:

‎packages/cli/src/utils/collect-docs.ts‎

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -934,8 +934,23 @@ function bodyDocsOf(packages: unknown, index: number): DocItem[] {
934934
* cross-package throw is retired"). What survives there is exactly what this
935935
* is: an authoring-time hygiene lint. ⚠️ That `os build` refuses the shape at
936936
* all is a standing disagreement with ADR-0048 §3.4 which PREDATES this card
937-
* and is filed rather than changed here — ⛔ relaxing a refusal that shipped is
938-
* not a rider on a widening.
937+
* and is filed as #19248 rather than changed here — ⛔ relaxing a refusal that
938+
* shipped is not a rider on a widening.
939+
*
940+
* #19248 read §3.4 back and settled the justification rather than moving it.
941+
* The clause retires a RUNTIME throw and nothing else — *"The cross-package
942+
* **throw is retired**; two distinct packages coexist on the same bare name by
943+
* construction."* — while keeping the class this lint belongs to: *"Authoring-time
944+
* hygiene — an author shipping two `page/home` in one package — stays covered by
945+
* the `naming/namespace-prefix` lint in `os lint`."* So the reason stated above is
946+
* the one that survived §3.4, and ⛔ no wording change was warranted. What #19248
947+
* left open is the SEVERITY, not the reason: §3.4 hands authoring hygiene to a
948+
* warning-only lint while this one is `severity: 'error'`.
949+
*
950+
* ⚠️ "this module's older framing" above is not gone — it is still live in this
951+
* file's HEADER docblock, which states the retired claim as the current reason for
952+
* the naming lints. Out of #19248's file surface (it also justifies
953+
* `docs/namespace-prefix`), so it is reported, not edited here.
939954
*/
940955
function lintDocNamesAcrossOwners(
941956
sets: ReadonlyArray<{ label: string; docs: readonly DocItem[] }>,

0 commit comments

Comments
 (0)