Repository navigation
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
Activity
- addeddocumentationImprovements or additions to documentationImprovements or additions to documentation
on Aug 16, 2026 os-project-manager commented
on Aug 16, 2026 CollaboratorAuthorMore actionsTriage: lands in
content/docs/deployment/validating-metadata.mdx(the "one gate, four doors" table) againstpackages/lint/src/authoring-rules.tsas 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-changesetper 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
- Scope per the card: one pass over the whole table against
os-project-manager commented
on Aug 16, 2026 CollaboratorAuthorMore actionsClaim: starting work on this card.
- Session ID:
session_011RB4waLuNbdruCo6X9oobm - Branch:
claude/issue-9007-four-doors-table-audit - Scope:
content/docs/deployment/validating-metadata.mdxonly — a full row-by-row audit of the "one gate, four doors" table againstAUTHORING_RULESinpackages/lint/src/authoring-rules.ts, not just the two cells named in the card. Nosurfaces/runtimeTypesdeclaration 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
- Session ID:
os-project-manager commented
on Aug 16, 2026 CollaboratorAuthorMore actions{ "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_RULESinpackages/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 safeParseinsaveMetaItemparses at the write path ✅ ✓ ✓ — ✓correct2 CEL / predicate validation (ADR-0032) validateStackExpressions['flow']✅ ✓ᶠ3 List-view navigation modes (ADR-0053) validateListViewModeCLI only ✅ —4 Zod-valid but functionally inert declarations validateFunctionalCompleteness,validateManagedApiMethodsCLI only ➕ added — both gating entries had no row 5 View container shape validateViewContainersCLI only ✅ —6 Widget-binding integrity (ADR-0021) validateWidgetBindings['dashboard']✅ ✓ᵈ(PR #9005)7 Dashboard action/route references (ADR-0049) validateDashboardActionRefsCLI only ✅ —8 Filter placeholder resolvability (#3574) validateFilterTokensCLI only ✅ —9 Ordering comparands naming a date-range preset (#8793) validatePresetComparands['dashboard','view','object','page','flow']➕ added, ✓ᵈᵛᵒᵖᶠ— the card's second cell10 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 readactions/dashboards/navigation, which the snapshot does not carry, so they contribute no verdict: the footnote's first—reason12 Flow reference integrity (#3583) validateFlowNodeWrites,validateFlowTemplatePaths,validateReadonlyFlowWritessuite entry ['flow']✅ ✓ᶠ13 Page-component field bindings (#3583) validatePageFieldBindingsas row 11 ✅ —14 React page block field bindings (#4340) validateReactPagePropsas row 11 ✅ —15 Chart bindings outside dashboards (#3583) validateChartBindingsas row 11 ✅ —16 Navigation vs. granted access (ADR-0090 D6) validateNavAccess,validateNavTargetRefs,validateNavObjectServabilityas row 11 ✅ —17 SDUI scoped styling (ADR-0065) validateResponsiveStyles,validatePageSourceStylingCLI only ✅ —18 JSX / React page source parses validateJsxPages,validateReactPagesCLI 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 cell21 Security vocabulary freeze (ADR-0090 D3) validateSecurityRoleWordCLI 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) validateOrgAxisRedLinesCLI only ✅ —23 Declared enforcement that cannot run validateSharingRuleEnforceability,validateRlsPredicateEnforceability,validateRuleCompilability,validateRuleSchemaFormatsCLI only ➕ added — four gating entries had no row 24 Platform-schedule create_recordorganization (#6285)findPlatformScheduleOrgGaps(metadata-protocol; deliberately outside the registry)early-returns for any type that is not flow✅ — — — ✓ᶠexact25 Autonumber {field}interpolationlintAutonumberFormatsCLI only ✅ —26 View references (#2554) lintViewRefsCLI only ✅ —27 Flow authoring anti-patterns (#1874) lintFlowPatterns['flow']✅ ✓ᶠ28 Flow trigger readiness (#5762) validateFlowTriggerReadiness['flow']✅ ✓ᶠ29 views[]conditional-visibility predicatesvalidateVisibilityPredicates,validatePredicatePathRefsboth ['view']✅ ✓ᵛ(the family moved together, #7220)30 Advisory row validateRecordTitle,validateSemanticRoles,validateSeedReplaySafety,validateSeedStateMachine,validateCapabilityReferences,lintLivenessProperties+validateFormLayout,validateActionLocations,validateComponentPropsall CLI only ⚠️ columns correct, enumeration incomplete → three entries added to the row31 Package docs (ADR-0046) collectAndLintDocs(outside the registry — readssrc/docs/)imported by all three command files ✅ ✓ ✓ ✓ —32 Undeclared authoring keys (#3786 / #4167) lintUnknownAuthoringKeyscalled from validate.tsandcompile.tsonly✅ ✓ ✓ — —33 Declared-unique scope (ADR-0120 D5) lintUnscopedDeclaredIndexes,lintUniqueDeclarations,lintLegacyOrganizationCompositescommands: ['validate','build'], andos lintreports them throughlintDataModel❌ 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 narrowed35 Emits dist/objectstack.jsonbuild artifact build only ✅ — ✓ — —Footnote / prose, audited in the same pass
- ❌
—was explained by two reasons; the registry carries more. Added: snapshot-safe rules simply not rolled out to a type yet (validateSharingRuleEnforceability,validateRlsPredicateEnforceability, and the object-writes-last rollout), andvalidateCapabilityReferences, which would graduate from advisory to gating at that door. - ❌ The stack-wide-collection reason cited permission sets as not carried.
RuntimeStackContexthas carriedpermissionsandbookssince [2 of #7891]permission/bookwiring:TYPE_TO_STACK_KEYentries + the cross-collection snapshot the three comparison rules need #8309 anddatasetssince The metadata door accepts a dashboard widget dataset binding that names nothing — 200 on both save and publish, referential integrity enforced only at runtime #7529; the surviving examples are pages, dashboards, navigation, positions, apps. ⚠️ "Two rows are deliberately not universal" restated without the count, consistent with PR docs(deployment): put widget-binding integrity on the runtime publish door #9005's removal of the footnote count.- ✅ Marker convention kept and extended: one superscript per declared type, in declaration order. One marker invented —
ᵖᵉforpermission, becausepagealready holdsᵖ— and the footnote says why. No hard count anywhere. - ✅
## The one gate, four doorsheading untouched (deep-linked fromcontent/docs/deployment/cli.mdx);check:doc-anchorsgreen.
Coverage check: every one of the 41
AUTHORING_RULESentries now maps to a row, counting the 20-member reference-integrity suite as the six rows that describe its members.
Generated by Claude Code
- ❌
- added a commit that references this issue
on Aug 17, 2026
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 doorstable incontent/docs/deployment/validating-metadata.mdx. Readingpackages/lint/src/authoring-rules.tsto do that surfaced two more drifts in the same table'sruntime publishcolumn 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@1a7f9073e1.
validateSecurityPosture— row says—, is actually gated.The table row
Security posture (ADR-0090 — e.g. every custom object declares sharingModel)carries—in theruntime publishcolumn. #7891 ("MovevalidateSecurityPostureonto the runtime publish surface") is closed, so this crossed and the docs never followed.2.
validatePresetComparands— no row at all.This is the #8793 rule (bare date-range preset names in ordering comparands). It is
gatingtier 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:761pins it as running ondashboardwrites alongsidevalidateWidgetBindings.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 ownruntimeTypesas the authority. So the page is no longer self-contradictory, but these two cells are still individually wrong and theobject/page/seed/permission/bookcoverage is still undiscoverable from the table.Suggested fix
One pass over the table against
AUTHORING_RULES: add avalidatePresetComparandsrow, correct thevalidateSecurityPosturecell, and add whatever marker letters the type set needs (✓ᵈfordashboardalready 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
validateSecurityPostureonto the runtime publish surface — a measured strictness rollout (#7576's remainder, #4001 pattern) #7891 and The metadata door accepts a dashboard widget dataset binding that names nothing — 200 on both save and publish, referential integrity enforced only at runtime #7529 are the closed code cards behind the two drifts.content/docs/releases/**stays out of scope as always.Generated by Claude Code