@@ -382,10 +382,12 @@ one. `sys_metadata` overlay rows are not in any config file, so there is no
382382| Protocol schema (Zod) | ✓ | ✓ | — | ✓ |
383383| CEL / predicate validation (ADR-0032) | ✓ | ✓ | ✓ | ✓ᶠ |
384384| List-view navigation modes (ADR-0053) | ✓ | ✓ | ✓ | — |
385+ | Zod-valid but functionally inert declarations — a ` summary ` with no operations (ADR-0078), a managed object advertising an API method its affordances refuse (#7521 ) | ✓ | ✓ | ✓ | — |
385386| View container shape | ✓ | ✓ | ✓ | — |
386387| Widget-binding integrity (ADR-0021) | ✓ | ✓ | ✓ | ✓ᵈ |
387388| Dashboard action/route references (ADR-0049) | ✓ | ✓ | ✓ | — |
388389| Filter placeholder resolvability (#3574 ) | ✓ | ✓ | ✓ | — |
390+ | Ordering comparands naming a date-range preset — ` last_30_days ` in a ` >= ` position (#8793 ) | ✓ | ✓ | ✓ | ✓ᵈᵛᵒᵖᶠ |
389391| Empty filter combinators — ` $and: [] ` , ` $or: [] ` , ` $not: {} ` (#5330 ) | ✓ | ✓ | ✓ | ✓ᶠ |
390392| Object & action name references (#3583 ) | ✓ | ✓ | ✓ | — |
391393| Flow reference integrity — node writes, template paths, read-only writes (#3583 ) | ✓ | ✓ | ✓ | ✓ᶠ |
@@ -396,31 +398,54 @@ one. `sys_metadata` overlay rows are not in any config file, so there is no
396398| SDUI scoped styling (ADR-0065) | ✓ | ✓ | ✓ | — |
397399| JSX / React page source parses (ADR-0080/0081) | ✓ | ✓ | ✓ | — |
398400| Approval-node approvers (ADR-0090 D3) | ✓ | ✓ | ✓ | ✓ᶠ |
399- | Security posture (ADR-0090 — e.g. every custom object declares ` sharingModel ` ) | ✓ | ✓ | ✓ | — |
401+ | Security posture (ADR-0090 — e.g. every custom object declares ` sharingModel ` ) | ✓ | ✓ | ✓ | ✓ˢᵖᵉᵇᵒ |
402+ | Security vocabulary freeze (ADR-0090 D3 — the reserved word, replaced by ` permission_set ` / ` position ` / ` business_unit ` ) | ✓ | ✓ | ✓ | — |
400403| Organization-axis red lines (ADR-0105 D6) | ✓ | ✓ | ✓ | — |
404+ | Declared enforcement that cannot run — sharing-rule conditions (#4698 ), row-level-security predicates (#4983 ), a validation rule's regex / JSON Schema (#4762 ) and its ` format ` names (#5178 ) | ✓ | ✓ | ✓ | — |
401405| Platform-schedule ` create_record ` organization (#6285 ) | — | — | — | ✓ᶠ |
402406| Autonumber ` {field} ` interpolation | ✓ | ✓ | ✓ | — |
403407| View references — form targets, view-key collisions (#2554 ) | ✓ | ✓ | ✓ | — |
404408| Flow authoring anti-patterns (#1874 ) | ✓ | ✓ | ✓ | ✓ᶠ |
405409| Flow trigger readiness — a flow that looks armed and never launches (#5762 ) | ✓ | ✓ | ✓ | ✓ᶠ |
406410| ` views[] ` conditional-visibility predicates — CEL syntax, parse budget, bare identifiers, binding-root layer, schema path refs (ADR-0089 D3b, #7010 ) | ✓ | ✓ | ✓ | ✓ᵛ |
407- | Advisory: record titles, semantic field pointers (ADR-0085), seed replay/state safety, capability references, liveness | ✓ | ✓ | ✓ | — |
411+ | Advisory: record titles, semantic field pointers (ADR-0085), form-section layout, action placement, SDUI component props, seed replay/state safety, capability references, liveness | ✓ | ✓ | ✓ | — |
408412| Package docs — flatness, prefixes, links (ADR-0046) | ✓ | ✓ | ✓ | — |
409413| Undeclared authoring keys — every metadata collection (#3786 ) and the stack's own top-level keys (#4167 ) | ✓ | ✓ | — | — |
410- | Naming, labels, data-model conventions, i18n coverage | — | — | ✓ | — |
414+ | Declared-unique scope — a bare ` unique: true ` index, a field-level and index-level double declaration, legacy organization composites (ADR-0120 D5) | ✓ | ✓ | ✓ | — |
415+ | Naming, labels, the rest of the data-model best-practice sweep, i18n coverage | — | — | ✓ | — |
411416| Emits ` dist/objectstack.json ` | — | ✓ | — | — |
412417
413- ** ` ✓ᶠ ` means the rule runs at that door for ` flow ` writes; ` ✓ᵛ ` for ` view `
414- writes; ` ✓ᵈ ` for ` dashboard ` writes.** Each marker names the metadata types that
415- rule's own ` runtimeTypes ` declares, and that entry in ` AUTHORING_RULES ` is the
416- authority — the set has grown a type at a time (#4463 shipped P1 as ` flow ` and
417- four rule families, #7220 moved the whole ` views[] ` visibility-predicate family
418- across in one edit, #7529 put widget-binding integrity on ` dashboard ` ), so read
419- the rule rather than assuming a save of some other type reaches storage
420- unjudged. The ` — ` cells above are ` — ` for two different reasons: some
421- rules read a stack-wide collection a one-item write does not carry (pages,
422- dashboards, navigation, permission sets), and some parse authored source through
423- ` typescript ` , which the kernel boot path must never load.
418+ ** Every superscript in the ` runtime publish ` column is one metadata type whose
419+ writes that rule inspects: ` ✓ᶠ ` ` flow ` , ` ✓ᵛ ` ` view ` , ` ✓ᵈ ` ` dashboard ` , ` ✓ᵒ `
420+ ` object ` , ` ✓ᵖ ` ` page ` , ` ✓ˢ ` ` seed ` , ` ✓ᵇ ` ` book ` , ` ✓ᵖᵉ ` ` permission ` ** — the last
421+ one carries two letters because ` page ` already holds ` ᵖ ` . A cell lists one
422+ superscript per declared type, in the order the rule declares them, and that
423+ rule's own ` runtimeTypes ` in ` AUTHORING_RULES ` is the authority — the set has
424+ grown a type at a time (#4463 shipped P1 as ` flow ` and four rule families, #7220
425+ moved the whole ` views[] ` visibility-predicate family across in one edit, #7529
426+ put widget-binding integrity on ` dashboard ` , #8307 → #8310 walked the ADR-0090
427+ security-posture block across ` seed ` , then ` permission ` and ` book ` , then
428+ ` object ` ), so read the rule rather than assuming a save of some other type
429+ reaches storage unjudged.
430+
431+ That last move is also why the vocabulary freeze is a row of its own. It was
432+ split out of the security-posture rule on the day the rest of that block
433+ crossed, because it judges collections the per-write snapshot does not carry:
434+ one rule id has to sit on ONE side of the wall, so it stayed behind whole rather
435+ than crossing for some of the collections it judges and not others.
436+
437+ The ` — ` cells above are ` — ` for more than one reason, and only the first two are
438+ about the rule being unable to run there: some rules read a stack-wide
439+ collection a one-item write does not carry (pages, dashboards, navigation,
440+ positions, apps — the snapshot has carried ` permissions ` and ` books ` since #8309
441+ and ` datasets ` since #7529 , so those three are no longer in this class); some parse
442+ authored source through ` typescript ` , which the kernel boot path must never
443+ load; some are snapshot-safe and simply have not been rolled out to a type yet
444+ (a sharing rule or an RLS predicate crosses on a ` runtimeTypes ` edit, not on new
445+ wiring); and the capability-reference rule would * graduate* from advisory to
446+ gating at that door, since the live registry decides what the CLI has to hedge —
447+ a severity change on a published rule id, which is its own PR rather than a
448+ wiring change.
424449
425450The visibility family crossed ** together** , and that is the point rather than an
426451implementation detail. An earlier attempt wired one of its rules alone, which
@@ -458,13 +483,19 @@ write lands in, and whether this deployment walls organizations), and a build
458483machine's environment is a false signal for them — so ` os build ` must not judge
459484it at all.
460485
461- Two rows are deliberately not universal across the three commands, and both are
462- one-directional (neither lets a stack through a gate another command enforces):
486+ Some rows are deliberately not universal across the three commands, and each is
487+ one-directional (none lets a stack through a gate another command enforces):
463488the Zod parse and the undeclared-key diff need the pre-parse tier and the schema,
464489which only the two commands that parse actually have; and ` os lint ` 's own
465- rubric — snake_case names, missing labels, data-model conventions — is a lint
466- verdict, not a publish gate. ` os build ` has never rejected a camelCase object
467- name.
490+ rubric — snake_case names, missing labels, the best-practice data-model sweep —
491+ is a lint verdict, not a publish gate. ` os build ` has never rejected a camelCase
492+ object name.
493+
494+ The declared-unique row is the one that looks like that rubric and is not. Its
495+ ADR-0120 D5 rules register for ` os validate ` and ` os build ` only, because
496+ ` os lint ` reaches them through its own data-model sweep and a second
497+ registration would print every finding twice — coverage recorded, not coverage
498+ missing, which is what each of those entries says for itself.
468499
469500That invariant is enforced, not merely documented. Each rule declares its command
470501coverage as data, and a CLI test fails if a rule that can emit ` error ` runs on
0 commit comments