docs(rest): state the direction the read predicate rules on at the /published door - #16586
Merged
Merged
Conversation
…ublished door The `GET /meta/:type/:name/published` handler's comment argued that passing the RAW tenant "is right for a READ" because `getMetaItemLayered`'s overlay lookup is org-scoped-first then env-wide, so "nothing that resolves today stops resolving". That fail-open direction is precisely the reasoning `organizationIdForMetaRead` was written to refute: an org named on a type the registry does not declare per-org overridable resurrects the phantom rows #6190 stopped minting. Since #14907 the callee gates: `getMetaItemLayered` resolves `organizationIdForMetaRead` itself, AFTER its canonical fold. So the raw tenant is correct here for a different reason than the one stated, and this door must NOT pre-gate — `req.params.type` is unfolded, and gating on it is the #10340 defect. Because the old prose read as a deliberate, reasoned decision to gate, two successive enumerations in the same series recorded this door as already gating when it does not. The `#8805` half above is untouched and still true. Comment-only and line-count-neutral: 8 comment lines out, 8 in, no executable change, so the absolute-line anchors in `content/docs/permissions/system-context.mdx` cannot move. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YFY46JydE1gMxQG1TqBcMZ
Contributor
📓 Docs Drift Check
What this run could not see
Coarse fallback — 13 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-sales
marked this pull request as ready for review
September 7, 2026 11:36
os-sales
enabled auto-merge
September 7, 2026 11:37
3 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #16032
The finding
The
GET /meta/:type/:name/publishedhandler inpackages/rest/src/rest-server.tscarried a paragraph arguing that handinggetMetaItemLayeredthe RAW tenant "is right for a READ", because that method's overlay layer is org-scoped-first and THEN env-wide, so the door was "fail-open in the safe direction" and "nothing that resolves today stops resolving".Fail-open in that direction is precisely what
organizationIdForMetaReadwas written to refute. Its own docblock inpackages/metadata-core/src/meta-write-org-scope.tsnames the shorter fix as wrong, and the callee's#14907block re-states it against this very door: naming the org on a type the registry does not declare per-org overridable resurrects, on the read side, the phantom rows#6190stopped minting.Since
#14907the callee gates.getMetaItemLayeredresolvesorganizationIdForMetaRead(request.type, request.organizationId)itself, deliberately placed AFTER its canonical fold. So the raw tenant here is correct — but for a different reason than the one the comment gave, and the reason the comment gave is the one the predicate rules against.Why this was a card and not a tidy-up
The
#14907card and its triage comment both recorded that this door already gates. Measured, it does not — and the comment is why. It reads as a deliberate, reasoned decision, so an enumeration that greps for the predicate name and then reads the surrounding prose comes away satisfied. Two seats in the same series inherited the same wrong reading from it. A self-consistent wrong comment costs far more than an obviously stale one, because it manufactures wrong census results.Behaviour is correct today and there is no security consequence, which is why the card is p2.
The change
Comment-only, and line-count-neutral: 8 comment lines out, 8 comment lines in, no executable statement touched.
#8805half above it is untouched and still true: this door really can produce a tier-A org-scoped publish and really must serve it back.organizationIdForMetaReadcall is added here. Computing the predicate onreq.params.type(raw) would be the#10340defect, becausedeclaresOrgOverrideanswersfalsefor the URL-only spellings; the fold is what makes it safe, and the callee already does it.Verification
Comment-only, proved mechanically. Every added and removed line in the diff matches a whole-line
//comment: 16 changed lines, 0 non-comment changed lines.Line-count-neutral, so no absolute-line anchor moves.
content/docs/permissions/system-context.mdxanchors this file at:1858,:1887,:1890,:5520,:6977,:7225,:7656,:7849— all above the edited block, and the file's total line count is unchanged at 13443.node scripts/check-system-context-census.mjsexits 0. That green is verified against a non-zero control rather than trusted: inserting one line at:100(well above the anchored region), rebuilding nothing, reddens the gate to exit 1 with 12 structural errors naming exactly those rest-server.ts anchors — 6site-without-a-rowand 6anchor-is-not-a-read-site. The mutation was proved on disk by marker count and by blob hash, and the restore proved byte-identical to theHEADblob before the second leg ran.Nothing is published, so
skip-changesetis applied rather than a changeset written.@objectstack/restpublishes[dist, README.md, CHANGELOG.md]. Probing all six built artifacts (index.js,index.cjs, both.maps,index.d.ts,index.d.cts) finds zero occurrences of the edited comment's text, and both sourcemaps havesourcesContentABSENT. The probe is verified by a non-zero control: an unrelated//prose comment frompackages/rest/src/error-response.ts:903is found inindex.jsandindex.cjs, so line comments inside function bodies do reachdist— this one simply does not.Stronger still, the built output is byte-identical across the diff. Building
@objectstack/restat the branch base and at HEAD produces the same sha256 for all six artifacts.turbo ls --affectednames 19 packages, but 18 of them are reachable only through this package's emitted surface, which did not move.Gates.
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsderived 42 commands; reconciliation with--ranreports 42 derived, 42 run, 0 UNRUN. 41 exit 0. One is NOT MEASURED, never a pass:pnpm check:dual-build-cjs-loadsexits 3PREREQUISITE NOT METbecause it reads built output and 43 packages have nodist/.The 39 artifact rosters were run separately: 35 exit 0, 4 NOT MEASURED —
pnpm check:published-readme-exports(exit 3,PREREQUISITE NOT MET),check:react-declaration-parity(exit 1,MANIFEST is not set, an on-demand gate needing an objectui manifest dump), andcheck-single-claim-paths.mjspluscheck-partof-closing-keyword.mjs(exit 2,NOT WIRED, both need PR context supplied by their own workflows).Tests.
pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2— 188 test files, 3198 tests, all passed.pnpm --filter @objectstack/rest typecheckexits 0, includingcheck:test-typecheckovertsconfig.test.json. Repo-widepnpm lintwas run in full and exits 0, so no narrowing is claimed.No test was added: the diff has no executable delta to cover, and the byte-identical
distis the measurement that says so.验收备注
#15621(thegetMetaItemsdocblock, PR docs(metadata-protocol): thegetMetaItemsgate enumerates sixrest-server.tscall sites, not five, and names the transitive diagnostics door #16117 open) and#15620(the/referencesorg-scope block) are the same shape — a caller-side comment reasoning about read scope, written before the callee-side gate existed. Only this card's door is touched. Those two are not addressed here and remain open.distwhen attached to a preserved statement (the control above is one). The conclusion is unchanged and now rests on a measurement rather than on that rule. This is an observation about a dispatch note, not a repo defect, so no card.tsupemits"zodIssuesToFields" is imported from external module "@objectstack/spec/api" but never used in "src/rest-server.ts"on every build of this package. Pre-existing on the branch base, unrelated to this diff, and a lint-shaped observation rather than a reproducible defect, so it is not a card under Prime Directive 10.🤖 Generated with Claude Code
https://claude.ai/code/session_01YFY46JydE1gMxQG1TqBcMZ
Generated by Claude Code