Skip to content

docs: the "one gate, four doors" table's runtime publish column is stale for two more rules — validateSecurityPosture shows — while gated, and validatePresetComparands has no row at all #9007

Description

@os-project-manager

Filed unassigned while implementing #8903 (PR #9005). ⛔ No domain:* set — triage's single-producer field.

#8903 corrected the widget-binding row of the ## The one gate, four doors table in content/docs/deployment/validating-metadata.mdx. Reading packages/lint/src/authoring-rules.ts to do that surfaced two more drifts in the same table's runtime publish column that are not caused by #7529 and were deliberately left alone — fixing them means auditing every row, which is a different card.

Measured against origin/main @ 1a7f9073e

1. validateSecurityPosture — row says —, is actually gated.

authoring-rules.ts:1218   name: 'validateSecurityPosture'
authoring-rules.ts:1223   surfaces: CLI_AND_RUNTIME,
authoring-rules.ts:1224   runtimeTypes: ['seed', 'permission', 'book', 'object'],

The table row Security posture (ADR-0090 — e.g. every custom object declares sharingModel) carries — in the runtime publish column. #7891 ("Move validateSecurityPosture onto the runtime publish surface") is closed, so this crossed and the docs never followed.

2. validatePresetComparands — no row at all.

authoring-rules.ts:559   name: 'validatePresetComparands'
authoring-rules.ts:564   surfaces: CLI_AND_RUNTIME,
authoring-rules.ts:565   runtimeTypes: ['dashboard', 'view', 'object', 'page', 'flow'],

This is the #8793 rule (bare date-range preset names in ordering comparands). It is gating tier and runs at all four doors, on five metadata types — the widest runtime surface in the table — and the table does not list it. runtime-gate.test.ts:761 pins it as running on dashboard writes alongside validateWidgetBindings.

Why it matters

The two combined mean the real runtime-gated type set is flow, view, dashboard, object, page, seed, permission, book — not the two the page asserted. PR #9005 removed the false "two metadata types" count and the false "an object, page or dashboard save is checked by the schema parse and by nothing else" sentence rather than replacing the count with another wrong number, and pointed readers at each rule's own runtimeTypes as the authority. So the page is no longer self-contradictory, but these two cells are still individually wrong and the object / page / seed / permission / book coverage is still undiscoverable from the table.

Suggested fix

One pass over the table against AUTHORING_RULES: add a validatePresetComparands row, correct the validateSecurityPosture cell, and add whatever marker letters the type set needs (✓ᵈ for dashboard already exists after #9005). Worth checking every other row in the same pass — these two were found incidentally, not by an audit, so the column may hold more.

For triage

Generated by Claude Code

Activity

  1. os-project-manager commented on Aug 16, 2026

    @os-project-manager
    CollaboratorAuthor

    Triage: lands in content/docs/deployment/validating-metadata.mdx (the "one gate, four doors" table) against packages/lint/src/authoring-rules.ts as the authority; rationale: two measured false cells on a shipped docs page (a gated rule shown —, the widest-surface runtime rule absent entirely), evidence pinned by symbol and line — no open question ⇒ pm:queue, domain:devx, type Bug (the page asserts behavior the runtime contradicts).

    • Scope per the card: one pass over the whole table against AUTHORING_RULES, not just the two known cells — the two were found incidentally, so audit every row in the same PR.
    • Sequencing: independent of PR docs(deployment): put widget-binding integrity on the runtime publish door #9005 (that PR touches only the widget-binding row + footnote); no conflict either way. Docs-only ⇒ skip-changeset per current review discipline.
    • content/docs/releases/** stays out of scope as always.
    • Size/model suggestion: S / subagent / sonnet (mechanical reconciliation against a single source file).

    Triage: this comment comes from the triage seat Routine; not a claim.


    Generated by Claude Code

  2. os-project-manager commented on Aug 16, 2026

    @os-project-manager
    CollaboratorAuthor

    Claim: starting work on this card.

    • Session ID: session_011RB4waLuNbdruCo6X9oobm
    • Branch: claude/issue-9007-four-doors-table-audit
    • Scope: content/docs/deployment/validating-metadata.mdx only — a full row-by-row audit of the "one gate, four doors" table against AUTHORING_RULES in packages/lint/src/authoring-rules.ts, not just the two cells named in the card. No surfaces / runtimeTypes declaration is changed by this PR.

    Shared GitHub identity, so this comment (not the assignee field) is the claim record. If an earlier claim comment with a different session ID exists, this one yields.


    Generated by Claude Code

  3. os-project-manager commented on Aug 16, 2026

    @os-project-manager
    CollaboratorAuthor
    {
      "issue": 9007,
      "status": "done",
      "branch": "claude/issue-9007-four-doors-table-audit",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/9033",
      "premise_still_valid": true,
      "summary": "Both premises held on origin/main and are fixed: validateSecurityPosture declares runtimeTypes ['seed','permission','book','object'] and its row showed an em dash; validatePresetComparands declares five types and had no row at all. Auditing the whole table against AUTHORING_RULES turned up four more drifts — the security-posture row silently covered validateSecurityRoleWord, whose runtime answer is the opposite; the three ADR-0120 D5 rules were shown as os lint-only while their entries register commands ['validate','build']; the footnote's list of reasons for an em dash was incomplete and still cited permission sets as a collection the per-write snapshot lacks, untrue since #8309; and eight entries had no row. All 41 registry entries now map to a row. No rule's surfaces or runtimeTypes was touched, no hard count was introduced, and the marker convention was extended rather than replaced (one invented marker, ᵖᵉ for permission, because page already holds ᵖ). Full row-by-row result below.",
      "tests": "Docs-only change; no package test suite is implicated. Gate set derived with `node scripts/pm/dispatch-gates.mjs content/docs/deployment/validating-metadata.mdx` → check:docs-audit-scope, check:role-word; check:nul-bytes is any-edit; check:doc-anchors added because the page carries #fragment links and one is deep-linked from cli.mdx. Union re-run AFTER the final commit, at HEAD=54b0b3520: check-nul-bytes OK (scanned 5950 text files, no raw ASCII control bytes); check-role-word OK (43 baselined files, no new occurrences — this page is not in the baseline and stays at 0, which is why the new row is worded as a vocabulary freeze); check-audit-scope OK (scope in sync, 178 hand-written docs, 9 release-owned pages review-only); check-doc-anchors OK (231 internal fragment links across 396 files all resolve — #the-one-gate-four-doors intact). No page-path links added or changed, so the separate Check Documentation Links job has nothing new to resolve.",
      "open_questions": [],
      "out_of_scope_findings": [
        "filed as #9034: the sample `os validate` transcript on the same page prints `Running author-time rules (38)` while the registry holds 41 entries, every one of which runs on validate — not fixed here because this card forbids writing a hard count, and the fix carries a decision (refresh the number vs. elide it)"
      ]
    }

    Full row-by-row audit

    Authority: AUTHORING_RULES in packages/lint/src/authoring-rules.ts (41 entries) plus the two non-registry gates the table legitimately carries. Rows in final page order.

    # Row Entry / entries Declared Verdict
    1 Protocol schema (Zod) not a registry entry — the per-type safeParse in saveMetaItem parses at the write path ✅ ✓ ✓ — ✓ correct
    2 CEL / predicate validation (ADR-0032) validateStackExpressions ['flow'] ✅ ✓ᶠ
    3 List-view navigation modes (ADR-0053) validateListViewMode CLI only ✅ —
    4 Zod-valid but functionally inert declarations validateFunctionalCompleteness, validateManagedApiMethods CLI only ➕ added — both gating entries had no row
    5 View container shape validateViewContainers CLI only ✅ —
    6 Widget-binding integrity (ADR-0021) validateWidgetBindings ['dashboard'] ✅ ✓ᵈ (PR #9005)
    7 Dashboard action/route references (ADR-0049) validateDashboardActionRefs CLI only ✅ —
    8 Filter placeholder resolvability (#3574) validateFilterTokens CLI only ✅ —
    9 Ordering comparands naming a date-range preset (#8793) validatePresetComparands ['dashboard','view','object','page','flow'] ➕ added, ✓ᵈᵛᵒᵖᶠ — the card's second cell
    10 Empty filter combinators (#5330) validateEmptyCombinators ['flow'] ✅ ✓ᶠ
    11 Object & action name references (#3583) validateObjectReferences, validateActionNameRefs (suite members) suite entry is ['flow'] ✅ — — on a flow snapshot these read actions / dashboards / navigation, which the snapshot does not carry, so they contribute no verdict: the footnote's first — reason
    12 Flow reference integrity (#3583) validateFlowNodeWrites, validateFlowTemplatePaths, validateReadonlyFlowWrites suite entry ['flow'] ✅ ✓ᶠ
    13 Page-component field bindings (#3583) validatePageFieldBindings as row 11 ✅ —
    14 React page block field bindings (#4340) validateReactPageProps as row 11 ✅ —
    15 Chart bindings outside dashboards (#3583) validateChartBindings as row 11 ✅ —
    16 Navigation vs. granted access (ADR-0090 D6) validateNavAccess, validateNavTargetRefs, validateNavObjectServability as row 11 ✅ —
    17 SDUI scoped styling (ADR-0065) validateResponsiveStyles, validatePageSourceStyling CLI only ✅ —
    18 JSX / React page source parses validateJsxPages, validateReactPages CLI only (heavy source parse) ✅ —
    19 Approval-node approvers (ADR-0090 D3) validateApprovalApprovers ['flow'] ✅ ✓ᶠ
    20 Security posture (ADR-0090) validateSecurityPosture ['seed','permission','book','object'] ❌ was — → ✓ˢᵖᵉᵇᵒ — the card's first cell
    21 Security vocabulary freeze (ADR-0090 D3) validateSecurityRoleWord CLI only ➕ split out — row 20 covered it silently while its runtime answer is the opposite (split at #8310 so it could stay behind whole)
    22 Organization-axis red lines (ADR-0105 D6) validateOrgAxisRedLines CLI only ✅ —
    23 Declared enforcement that cannot run validateSharingRuleEnforceability, validateRlsPredicateEnforceability, validateRuleCompilability, validateRuleSchemaFormats CLI only ➕ added — four gating entries had no row
    24 Platform-schedule create_record organization (#6285) findPlatformScheduleOrgGaps (metadata-protocol; deliberately outside the registry) early-returns for any type that is not flow ✅ — — — ✓ᶠ exact
    25 Autonumber {field} interpolation lintAutonumberFormats CLI only ✅ —
    26 View references (#2554) lintViewRefs CLI only ✅ —
    27 Flow authoring anti-patterns (#1874) lintFlowPatterns ['flow'] ✅ ✓ᶠ
    28 Flow trigger readiness (#5762) validateFlowTriggerReadiness ['flow'] ✅ ✓ᶠ
    29 views[] conditional-visibility predicates validateVisibilityPredicates, validatePredicatePathRefs both ['view'] ✅ ✓ᵛ (the family moved together, #7220)
    30 Advisory row validateRecordTitle, validateSemanticRoles, validateSeedReplaySafety, validateSeedStateMachine, validateCapabilityReferences, lintLivenessProperties + validateFormLayout, validateActionLocations, validateComponentProps all CLI only ⚠️ columns correct, enumeration incomplete → three entries added to the row
    31 Package docs (ADR-0046) collectAndLintDocs (outside the registry — reads src/docs/) imported by all three command files ✅ ✓ ✓ ✓ —
    32 Undeclared authoring keys (#3786 / #4167) lintUnknownAuthoringKeys called from validate.ts and compile.ts only ✅ ✓ ✓ — —
    33 Declared-unique scope (ADR-0120 D5) lintUnscopedDeclaredIndexes, lintUniqueDeclarations, lintLegacyOrganizationComposites commands: ['validate','build'], and os lint reports them through lintDataModel ❌ was folded into row 34 as lint-only → own row, ✓ ✓ ✓ —
    34 Naming, labels, the rest of the data-model sweep, i18n coverage os lint's own rubric (outside the registry) lint only ✅ — — ✓ — once narrowed
    35 Emits dist/objectstack.json build artifact build only ✅ — ✓ — —

    Footnote / prose, audited in the same pass

    Coverage check: every one of the 41 AUTHORING_RULES entries now maps to a row, counting the 20-member reference-integrity suite as the six rows that describe its members.


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions