Skip to content

Commit c0525b2

Browse files
docs(deployment): reconcile the four-doors table with AUTHORING_RULES (#9007) (#9033)
Audit every row of the "one gate, four doors" table in content/docs/deployment/validating-metadata.mdx against AUTHORING_RULES in packages/lint/src/authoring-rules.ts, which the table's footnote already names as the authority. Two runtime-publish cells were false: validateSecurityPosture is gated on seed, permission, book and object writes and the row showed an em dash, and validatePresetComparands -- the widest runtime surface in the registry -- had no row at all. The audit found four more drifts: the security-posture row silently covered validateSecurityRoleWord, whose runtime answer is the opposite; the ADR-0120 declared-unique rules were shown as lint-only while their registry entries name validate and build; the footnote's list of reasons for an em dash was incomplete and cited permission sets as a collection the snapshot lacks, which has not been true since #8309; and eight registry entries had no row. Markers stay the existing convention -- one superscript per declared type, in the order the rule declares them. permission takes a two-letter superscript because page already holds the single letter; that collision is the only marker invented here and the footnote says so. No hard count is introduced anywhere: each cell points at the rule's own runtimeTypes. No rule's surfaces or runtimeTypes changed -- this documents what is. Claude-Session: https://claude.ai/code/session_011RB4waLuNbdruCo6X9oobm Co-authored-by: Claude <noreply@anthropic.com>
1 parent 27a567d commit c0525b2

1 file changed

Lines changed: 50 additions & 19 deletions

File tree

content/docs/deployment/validating-metadata.mdx

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -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

425450
The visibility family crossed **together**, and that is the point rather than an
426451
implementation 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
458483
machine's environment is a false signal for them — so `os build` must not judge
459484
it 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):
463488
the Zod parse and the undeclared-key diff need the pre-parse tier and the schema,
464489
which 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

469500
That invariant is enforced, not merely documented. Each rule declares its command
470501
coverage as data, and a CLI test fails if a rule that can emit `error` runs on

0 commit comments

Comments
 (0)