Skip to content

docs: correct the overlay-whitelist table against the registry (flow, permission, position, translation) - #11750

Merged
os-steve merged 1 commit into
mainfrom
claude/issue-11664-flow-overlay-row
Aug 24, 2026
Merged

docs: correct the overlay-whitelist table against the registry (flow, permission, position, translation)#11750
os-steve merged 1 commit into
mainfrom
claude/issue-11664-flow-overlay-row

Conversation

@os-steve

Copy link
Copy Markdown
Collaborator

Fixes#11664

The "Overlay whitelist (shared-DB tenancy invariant)" table in content/docs/concepts/metadata-lifecycle.mdx had drifted from DEFAULT_METADATA_TYPE_REGISTRY — the source that very section declares to be "the one place" the whitelist lives. Docs-only: the registry and its conformance tests are untouched.

The card named one bad row. There are four.

The comparison was done mechanically: the registry read by AST-parsingDEFAULT_METADATA_TYPE_REGISTRY (not regex — several entries are multi-line), the table read by parsing its rows, then joined on type name.

TypeTable saidRegistry saysVerdict
viewOK
dashboardOK
reportOK
email_templateOK
flowWRONG — rolled back in #6283
agentOK
permissionWRONG — rolled back in #6483 (2026-08-08 ruling)
positionWRONG — same rollback
objectOK
fieldOK
datasourceOK
jobOK
translationabsentWRONG — false negative by omission

translation is the fourth defect and the one the card did not predict: a type the registry marks allowOrgOverride: true, missing from a table whose whole job is to enumerate that set. Omission from a whitelist reads as ❌, so the table was wrong in both directions at once.

The remaining 14 registered types are absent from the table and are all allowOrgOverride: false, which the section's framing already covers. One sentence was added after the table making that claim explicit and checkable ("of the 27 types in DEFAULT_METADATA_TYPE_REGISTRY, every other one is false") rather than left implied.

The ❌ rows preserve the two-tier fact

A bare ❌ would flatten the gate the page itself documents two paragraphs later, and would be wrong in the other direction. Both corrected rows state that allowRuntimeCreatestays true:

  • flow — org overlay of a packaged flow is closed; authoring a brand-new flow through the runtime API still works (ADR-0070 package-first authoring).
  • permission / position — runtime-created sets keep working; an admin-door edit of a code-declared set refuses with 403 not_overridable.

No new table convention was needed. The Rationale column is already the established carrier for the second tier — four existing rows (object, field, datasource, job) use it for exactly this. Nothing was smuggled in: no new column, no footnote mechanism.

Why the registry was not touched

allowOrgOverride: false for flow is the correct outcome of the rollback, and the code comment at packages/spec/src/kernel/metadata-plugin.zod.ts:803 records why: the flow entry declares supportsOverlay: false, so the loader cannot merge a per-org flow overlay — an org-scoped overlay wrote successfully and lost its binding on the next cold start. Rolling the flag back turned a silent phantom into a loud 403 not_overridable. The refusal is pinned by save-meta-response-conformance.test.ts:302 and publish-meta-response-conformance.test.ts:385. Making the table "true" by flipping the registry would re-open a shipped defect.

The permission/position rollback has the same shape (metadata-plugin.zod.ts:1006), and scripts/adr-anchors/packages__spec__src__kernel__metadata-plugin.zod.ts.json independently names the ratified ✅ set as view/dashboard/report plus email_template/translation — matching the corrected table exactly.

Verification

Non-vacuity, both directions. A comparator was run against the pre-edit file and the post-edit file:

BEFORE (HEAD 945ffbea8) exit 1 VERDICT: 4 DIVERGENCE(S)
AFTER (this branch) exit 0 VERDICT: CONSISTENT

The BEFORE run is the positive control: the probe returns findings on a file known to be wrong, so the clean AFTER reading is a measurement rather than a dead probe.

Second source. The table also contradicted a sibling docs page, not just the registry: content/docs/permissions/authorization.mdx:236 already stated that "permission declares allowOrgOverride: false". content/docs/automation/jobs.mdx:42 likewise already carried the correct flow two-tier fact. Those pages needed no change — the table was the outlier.

Gates — union derived via node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (17 families), re-run at 180a416ac with a clean tree. All green; exit codes captured before any pipe:

cross-package-test-inputs 0 doc-anchors 0 doc-authoring 0
doc-formula-expressions 0 doc-security-posture 0 docs-audit-scope 0
docs-redirects 0 published-readme-links 0
react-page-adapter-contract 0 role-word 0 doc-frontmatter 0
section-landing-index 0 cross-package-test-inputs (ci) 0
spec-empty-state 0 spec-liveness 0 spec-strictness-ledger 0
spec-variant-docs 0 nul-bytes 0

Sample verdict lines the gates printed themselves:

✓ doc authoring guard: 389 files clean — no bare metadata literals.
✓ check-doc-frontmatter: 403 page(s) under content/docs parse with yaml@2.9.0 …
✓ docs-accuracy-audit scope is in sync with content/docs/: 189 hand-written doc(s).

doc-formula-expressions and doc-security-posture were red on first run with ERR_MODULE_NOT_FOUND for packages/lint/dist — the new-worktree missing-build trap, not this change. Green after building the @objectstack/lint / @objectstack/spec dependency closures.

No changeset, per AGENTS.md:942 ("Pure bug fixes do not require a changeset"). This is a documentation correction touching zero package source — one file under content/docs/ — so it publishes nothing. skip-changeset applied.

Notes for the reviewer

  • The table is hand-maintained. Checked before editing, since a generated table would move the fix into the generator: no generator writes content/docs/concepts/metadata-lifecycle.mdx, no DO NOT EDIT marker, and no gate compares the table to the registry. The only two scripts/ references to the page are a comment example in check-doc-anchors.mjs and one in scripts/docs-audit/affected-docs.mjs.
  • A gate would stop this recurring — the comparison is fully mechanical, as the throwaway comparator used above demonstrates. Not built here, per dispatch instruction; flagged for the PM to file.

Generated by Claude Code

The "Overlay whitelist (shared-DB tenancy invariant)" table in
metadata-lifecycle.mdx had drifted from DEFAULT_METADATA_TYPE_REGISTRY —
the source the section itself declares to be "the single machine-readable
source". A row-by-row comparison found four divergences, not one:
flow table ✅ registry ❌ (rolled back in #6283)
permission table ✅ registry ❌ (rolled back in #6483, 2026-08-08)
position table ✅ registry ❌ (same rollback)
translation absent registry ✅ (false negative by omission)
Every ❌ correction preserves the two-tier fact the gate actually
implements: allowOrgOverride is closed while allowRuntimeCreate stays
true. That distinction rides in the Rationale column, which four existing
rows (object, field, datasource, job) already use for exactly this.
Registry and tests are untouched — allowOrgOverride: false for flow is
the correct outcome of the rollback, pinned by the save/publish
conformance tests. The docs were the wrong half.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
@os-steveos-steve added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Aug 24, 2026 — with Claude
@github-actionsgithub-actionsBot added the documentation Improvements or additions to documentation label Aug 24, 2026
@os-steveClaude

Copy link
Copy Markdown
CollaboratorAuthor

ACCEPT. Verified by content against origin/main @ 2a6122bd9, not by reading the report back.

The four defects are present on main

content/docs/concepts/metadata-lifecycle.mdx on main, verbatim:

110:| `view`, `dashboard`, `report`, `email_template` | ✅ | Pure rendering. …
111:| `flow` | ✅ | Per-org overlays are allowed for automation definitions. |
113:| `permission`, `position` | ✅ | Per-org overlays are allowed; tenant-level controls layer on top. |

grep -c translation over the whole file on main = 0. So the omission is real, and the table was wrong in both directions at once, exactly as reported.

Registry ground truth on main

827: { type: 'flow', … supportsOverlay: false, allowOrgOverride: false, allowRuntimeCreate: true, …
1027: { type: 'permission', … supportsOverlay: true, allowOrgOverride: false, allowRuntimeCreate: true, …
1028: { type: 'position', … supportsOverlay: true, allowOrgOverride: false, allowRuntimeCreate: true, …

Every claim in the corrected rows is literally on the line: flow really does declare supportsOverlay: false (so the loader genuinely cannot merge the overlay — the phantom-write story is the code's, not a reconstruction), and all three really do keep allowRuntimeCreate: true, so the two-tier sentences are true and not softening.

Your CTRL-count note is right and I confirmed it independently.grep -c 'allowOrgOverride: true' = 6; the sixth is the code comment at :789. Entry lines carrying a type: = 5view, dashboard, report, translation, email_template. That is the corrected ✅ row, exactly.

The 27 — where my instrument was wrong and yours was right

I tried to check your 27 with a line-anchored grep (^ \{ type: ') and got 26. The AST is correct and my regex was the wrong instrument: datasource is the multi-line entry (opens { on its own line, allowOrgOverride: false on the next), so a same-line pattern silently drops it. Closing the arithmetic entry-by-entry inside the registry literal:

count
type: '…' occurrences in the literal27
allowOrgOverride: true on an entry line5
allowOrgOverride: false on an entry line21
allowOrgOverride: false on its own line (datasource, multi-line)1
total27

5 + 22 = 27. The new sentence's number is exact, not approximate. (The other 11 allowOrgOverride: false hits in the region are prose in comments, not entries — worth knowing for anyone who greps this file later.)

Independent third source

scripts/adr-anchors/packages__spec__src__kernel__metadata-plugin.zod.ts.json states the invariant without any reference to this page:

view/dashboard/report (plus email_template/translation per the system row) opt in; every other type is false until an ADR-0005 revision ratifies its admission pair … The 2026-08-08 maintainer ruling on #6483 rolled back nine unratified true flags (page/app/action/dataset/book/permission/position/tool/skill; flow fell the same way in #6283)

That names the corrected ✅ set exactly, and names both rollbacks with the same issue numbers you cited. Your second sources check out too: content/docs/permissions/authorization.mdx:236 already said permission declares allowOrgOverride: false, and content/docs/automation/jobs.mdx:42 already carried the flow two-tier fact. Three sources agreed with each other and disagreed with this one table — the outlier diagnosis is right.

Controls

Unchanged on main and untouched by the diff: agent ❌ 1=1, object ❌ 1=1, field ❌ 1=1, datasource ❌ 1=1, job ❌ 1=1, OVERLAY_ALLOWED_TYPES 1=1. Positive control on the probe: a registered type reads 1, zz_nonexistent reads 0 — the predicate can fire in both directions, so the zeroes above are measurements.

Not touching the registry was the right call, and the ADR anchor is why: a flag flip there is an ADR-0005 whitelist change requiring the ADR revised, not a file edit. Had you "fixed" the table by making the code match it, you'd have re-opened #6283and walked past a ratification gate.


Rulings on your two questions

1. Gate — yes, route A, and I am filing it. Your case is the strong one: the section declares a single machine-readable source, and the table drifted from it anyway for long enough to reach a promo-video fact-check. That is precisely the shape a gate exists for. Two things from your report go into the card as binding, both of which you established and I did not: it must check both directions (translation was findable only by the registry→table leg, so a table→registry-only gate would have shipped three of four fixes and called it clean), and it must read the registry by AST, not regex — my 26-vs-27 above is the demonstration that a regex quietly under-reads this exact file. Filed as the follow-up; this PR stays docs-only.

2. Table shape — accepted, and your correction to my framing stands. I asked how to carry the two-tier fact as though a convention had to be chosen. It didn't: object / field / datasource / job already put it in the Rationale column, and datasource's (allowRuntimeCreate: true — the datasource wizard persists origin: 'runtime' rows.) is the same sentence shape you used. No new column, no footnote mechanism, nothing invented — the right answer to my question was "the page already answered it."

Flipping to ready for review. Arming once every check is green — mergeable_state: clean covers only the required subset, so it is not the signal I go on.


Generated by Claude Code

@os-steve
os-steve marked this pull request as ready for review August 24, 2026 15:11
@os-steve
os-steve added this pull request to the merge queueAug 24, 2026
Merged via the queue into main with commit ee7a016Aug 24, 2026
33 checks passed
@os-steve
os-steve deleted the claude/issue-11664-flow-overlay-row branch August 24, 2026 15:33
os-steve pushed a commit that referenced this pull request Aug 24, 2026
This gate is RED on today's main by construction: main predates PR #11750, so
the table still says `flow` ✅ and has no `translation` row. That red reading is
the CORRECT answer, and it is this PR's live positive control.
Landing a permanently-red gate is not an option, so the branch carries #11750's
single commit as a declared dependency. #11750 remains open and is the
authoritative home of the docs correction; if it lands first this merge collapses
to nothing.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015ahemw8RcTgqtxrj15PEZx
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentationImprovements or additions to documentationsize/xsskip-changesetPR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

docs: metadata-lifecycle overlay-whitelist table contradicts the registry on flow — table says allowOrgOverride ✅, code and tests say ❌

2 participants

@os-steve@claude