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 615fac3
Browse filesBrowse the repository at this point in the historyBrowse files
authored
fix(lint,metadata-protocol): a Studio publish refuses an object whose highlightFields (or any field-name list) names a missing field — the same rule family as code (#15254) (#15493)
* fix(lint,metadata-protocol): refuse an object whose field-name lists name a missing field
Studio's app builder mints no `view` items, so `list-view-field-unknown` had
nothing to inspect on the only artifacts the click path authors, and
`highlightFields` is an object-level list no gating rule covered:
`runtimeAuthoringRulesFor('object')` dispatched seven rules and no
reference-integrity rule among them, while the object-level existence check
that did exist (`semantic-role-field-unknown`) is warning-tier and CLI-only.
Adds `object-field-ref-unknown` (error) over the object-level field-name LISTS
nothing owns — `highlightFields` and `publicSharing.redactFields` — registers
it in the reference-integrity suite with `runtimeTypes` including `object`,
and crosses the suite entry onto the object write door so its one
object-judging member runs there. The existence half moves out of
`validateSemanticRoles`, which keeps the provenance question at that position.
Adds an `objects` plane to the ADR-0038 L3 build probes so `probes.checked`
reports how many objects were inspected — the absent key was the tell.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
* test(lint): re-pin the moved highlightFields clauses; scope the member to object writes
The #5378 injected-column counter-examples and the #8116 withheld-anchor case
move to the rule that now owns the position, at `error` rather than `warning`.
`validateSemanticRoles` keeps its own stageField copies and the provenance
question, and gains the controls that keep its new silence non-vacuous.
The suite member declares `runtimeTypes: ['object']` only: on a flow or view
snapshot the objects are context, present in baseline and candidate alike, so
every finding it could raise there cancels in the gate's differential.
Adds the changeset (minor/minor, with the Migration section).
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
* fix(lint): the new suite member keeps the #4463 P1 flow floor
Every member of the reference-integrity suite judges flow snapshots, pinned
as a roster-wide invariant rather than a per-member preference. The member
declares 'flow' to hold that floor; on a flow snapshot the objects are context
in both passes, so it adds a pass and no verdict. 'view' stays argued out —
a view write cannot change an object's own field-name lists.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
* test(metadata-protocol): drop the duplicated PKG constant from the copied harness
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
* test(metadata-protocol): the harness find double honours the caller's limit
check:objectql-double-limit refuses a NEW limit-blind double ('the baseline
never grows'): the copied harness answered more rows than the real engine
would, so every assertion downstream of it measured a shape production never
produces. Applies the bound after the filter, by presence.
Records the new file's engine doubles in the pinned ledger, as
check:engine-double-contract prescribes for new pinned coverage.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zGPuVVX3deAx9LdjK8jCk
---------
Co-authored-by: Claude <trymqms@gmail.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
A publish now refuses an object whose `highlightFields` names a field that does not exist on it — the same gate that refuses a code-authored stack.
7
+
8
+
`list-view-field-unknown` inspects `view.columns`, and Studio's app builder mints no `view` items at all, so the reference-integrity family had nothing to inspect on the only artifacts the click path authors. What it authors is the **object**, and an object-level field-name list was covered by nothing that could refuse: measured on `origin/main`, `runtimeAuthoringRulesFor('object')` dispatched seven rules with no reference-integrity rule among them, while the object-level existence check that did exist (`semantic-role-field-unknown`) is `warning`, advisory-tier and CLI-only. So `os validate` exited 0 on a dangling reference and the runtime publish door — the only door a Studio, REST `/meta` or MCP author has — said nothing at all.
9
+
10
+
The reproduction is the natural click order, not a contrived one: click-create a field (Studio mints it as `field_10`), add it to `highlightFields`, then give it a label — the API name auto-derives to `health_score` and `highlightFields` keeps `field_10`. Anyone who names a field after placing it produces this.
11
+
12
+
-**New rule `object-field-ref-unknown` (`error`)**, in `@objectstack/lint`, over the object-level field-name **lists** that no rule owned: `highlightFields` (ADR-0085) and `publicSharing.redactFields`. It resolves through the same `object-graph` seam as the rest of the family, so the three shared skips hold — an object outside the stack, an object with no readable field map (ADR-0015 `external`), and a registry-injected system column resolved **per object** (`highlightFields: ['owner_id']` is a live pointer on an owned object and a real miss under `ownership: 'none'`).
13
+
-**It runs on the runtime publish door.** The reference-integrity suite entry's `runtimeTypes` gains `object`, and the suite's per-member declaration keeps the crossing narrow: this is the only member that judges an object snapshot; every other member keeps `['flow', 'view']` or the frozen `['flow']` default.
14
+
-**`validateSemanticRoles` keeps the provenance question** at the same position (`semantic-role-field-unprovisioned`, still `warning`) and no longer restates existence — one finding per path, at one tier.
15
+
-**`probes.checked` gained an `objects` counter.** Its absence was the tell: a receipt reading `{seeds: 0, views: 0, widgets: 0}` was accurate while the objects the package published were probed by nothing.
16
+
17
+
## Migration
18
+
19
+
**A publish that used to succeed can now be refused (HTTP 422, `INVALID_METADATA`).** The receipt names the rule id `object-field-ref-unknown` and the offending path, name-keyed on the wire — for example `objects.proj_task.highlightFields[1]` — plus the string that was written and the fields the object actually has.
20
+
21
+
To fix a dangling reference, do one of:
22
+
23
+
- rewrite the entry to the field's current API name (after a Studio label edit the derived name is the one to use — `field_10` becomes `health_score`); or
24
+
- drop the entry from the list.
25
+
26
+
`os validate` / `os build` / `os lint` report the same finding at `error`, so a stack can be repaired before it reaches a publish. If an object legitimately points at a platform-injected system column, no change is needed — the rule resolves those per object and stays silent where the platform really provisions them.
0 commit comments