Repository navigation
Description
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
- Dedupe: searched open issues for the four-doors table / runtime-publish-column drift and for a preset-comparands docs row at 05:35Z — nothing open. Move
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. - Sequencing: independent of docs(deployment): put widget-binding integrity on the runtime publish door #9005; that PR touches only the widget-binding row and the footnote, so there is no conflict either way.
content/docs/releases/**stays out of scope as always.
Generated by Claude Code
Activity
os-project-manager commentedon Aug 16, 2026
Triage: 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).AUTHORING_RULES, not just the two known cells — the two were found incidentally, so audit every row in the same PR.skip-changesetper current review discipline.content/docs/releases/**stays out of scope as always.Triage: this comment comes from the triage seat Routine; not a claim.
Generated by Claude Code
os-project-manager commentedon Aug 16, 2026
Claim: starting work on this card.
session_011RB4waLuNbdruCo6X9oobmclaude/issue-9007-four-doors-table-auditcontent/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
os-project-manager commentedon Aug 16, 2026
{ "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.safeParseinsaveMetaItem✓ ✓ — ✓correctvalidateStackExpressions['flow']✓ᶠvalidateListViewMode—validateFunctionalCompleteness,validateManagedApiMethodsvalidateViewContainers—validateWidgetBindings['dashboard']✓ᵈ(PR #9005)validateDashboardActionRefs—validateFilterTokens—validatePresetComparands['dashboard','view','object','page','flow']✓ᵈᵛᵒᵖᶠ— the card's second cellvalidateEmptyCombinators['flow']✓ᶠvalidateObjectReferences,validateActionNameRefs(suite members)['flow']—— on a flow snapshot these readactions/dashboards/navigation, which the snapshot does not carry, so they contribute no verdict: the footnote's first—reasonvalidateFlowNodeWrites,validateFlowTemplatePaths,validateReadonlyFlowWrites['flow']✓ᶠvalidatePageFieldBindings—validateReactPageProps—validateChartBindings—validateNavAccess,validateNavTargetRefs,validateNavObjectServability—validateResponsiveStyles,validatePageSourceStyling—validateJsxPages,validateReactPages—validateApprovalApprovers['flow']✓ᶠvalidateSecurityPosture['seed','permission','book','object']—→✓ˢᵖᵉᵇᵒ— the card's first cellvalidateSecurityRoleWordvalidateOrgAxisRedLines—validateSharingRuleEnforceability,validateRlsPredicateEnforceability,validateRuleCompilability,validateRuleSchemaFormatscreate_recordorganization (#6285)findPlatformScheduleOrgGaps(metadata-protocol; deliberately outside the registry)flow— — — ✓ᶠexact{field}interpolationlintAutonumberFormats—lintViewRefs—lintFlowPatterns['flow']✓ᶠvalidateFlowTriggerReadiness['flow']✓ᶠviews[]conditional-visibility predicatesvalidateVisibilityPredicates,validatePredicatePathRefs['view']✓ᵛ(the family moved together, #7220)validateRecordTitle,validateSemanticRoles,validateSeedReplaySafety,validateSeedStateMachine,validateCapabilityReferences,lintLivenessProperties+validateFormLayout,validateActionLocations,validateComponentPropscollectAndLintDocs(outside the registry — readssrc/docs/)✓ ✓ ✓ —lintUnknownAuthoringKeysvalidate.tsandcompile.tsonly✓ ✓ — —lintUnscopedDeclaredIndexes,lintUniqueDeclarations,lintLegacyOrganizationCompositescommands: ['validate','build'], andos lintreports them throughlintDataModel✓ ✓ ✓ —os lint's own rubric (outside the registry)— — ✓ —once narroweddist/objectstack.json— ✓ — —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.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.ᵖᵉ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
docs(deployment): reconcile the four-doors table with AUTHORING_RULES (…