You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit f89dd33
Browse filesBrowse the repository at this point in the historyBrowse files
fix(cli, lint): gate a dangling lookup/master_detail reference, and resolve one across the artifact packages[] (#17066)
* feat(lint): enrol a field's reference target in object-reference-unknown's severity ladder
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016N6xmWt5hYm94ffVEwGH8x
* feat(cli, lint): resolve a field reference against the artifact's packages[] on os build's per-package leg
ADR-0130 makes the release artifact the co-ownership boundary, so `os build`'s
per-package authoring-rule leg judging a package with no sight of its siblings
is the run's defect, not the author's. `compile.ts` now hands each package's
stack the artifact's `packages[]` as resolution context, and
`validate-object-references` widens rung 1 to the names those entries provide.
It changes what a rule can RESOLVE, never what it JUDGES: the collections read
off the top level are still the one package's, and a name no entry provides
still lands on rung 2 and errors.
Claude-Session: https://claude.ai/code/session_015QE8qk46e5CHJxyQEUjbf8
Co-authored-by: Claude <noreply@anthropic.com>
* docs(changeset): state the artifact-packages rung and the cli half
Claude-Session: https://claude.ai/code/session_015QE8qk46e5CHJxyQEUjbf8
Co-authored-by: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
`object-reference-unknown` now judges a field's `reference` — the target of `Field.lookup()` / `Field.masterDetail()` / `Field.user()` — with the same four-rung ladder it applies to every other object-name site, and `os build`'s per-package run resolves those names across the artifact's `packages[]`
7
+
8
+
`FieldSchema.reference` is `z.string()`: the schema holds it present and non-empty on `lookup` / `master_detail`, and nothing anywhere asked whether the name resolved. So `os validate`, `os lint` and `os build` all exited 0 — no diagnostic of any severity — on `Field.lookup('zzz_object_that_does_not_exist')` (measured on 17.3.0), and the miss surfaced only at runtime: the record picker asking the REST layer for an object that is not registered (404 `OBJECT_NOT_FOUND`), `$expand` failing on the field, the form rendering a control that can never resolve a value.
9
+
10
+
The site joins `validateObjectReferences` and rides its existing ladder, so the three commands judge it identically:
11
+
12
+
1. resolves in the stack's own objects, or in the objects an entry of this artifact's `packages[]` provides → ok;
13
+
2. resolves in `PLATFORM_PROVIDED_OBJECT_NAMES` (`sys_user`, the target `Field.user()` writes) → ok;
14
+
3. unresolved and not platform-prefixed → **`error`** — `os validate` / `os build` / `os lint` exit 1;
15
+
4. unresolved, platform-prefixed, registered by nothing (`sys_approval_process`) → the existing `object-reference-unregistered-platform` advisory.
16
+
17
+
Judged: `lookup`, `master_detail`, `user`. Not judged, on purpose: `tree` (the object schema already refuses any target but the own name), a `reference` on a non-relationship type (inert), and `objectExtensions[].fields` (an extension targets an object another package owns, routinely one this artifact does not carry).
18
+
19
+
## Migration
20
+
21
+
**A build that used to pass can now fail.** Rung 3 is a new `error`-level refusal on a published accept set. Point the field at one of the stack's own objects, at an object another package of the same artifact ships, or at a platform object by its full name (`sys_user`, not `user`); the finding names the objects that resolve and suggests the nearest one.
22
+
23
+
**A reference into a sibling package of the same release artifact resolves — it needs no annotation.** ADR-0130 makes the release artifact the co-ownership boundary, so `os build`'s per-package leg now hands each package's stack the artifact's `packages[]` as resolution context (`compile.ts`). A module's `crm_order.account` → its App package's `crm_account` is an ordinary rung-1 resolution on all three commands. This changes what a rule can resolve, never what it judges: the collections judged per package are still that package's own, and a name no entry of `packages[]` provides still errors on the per-package run exactly as it does on the union one.
24
+
25
+
**A reference into another RELEASE ARTIFACT still has no rung** — an app naming an object a separate product ships (HotCLM's `clm_contract.crm_contract` → HotCRM). It is unresolved and unprefixed, so rung 3 refuses it. The declared escape for that case resolves against declared manifest dependencies and is its own change; ⛔ it is deliberately not an authored per-field marker, which would be a one-line switch that silences the gate.
0 commit comments