Uh oh!
There was an error while loading. Please reload this page.
test(rest): the meta read-scope stub honours the where and the limit on both sys_metadata_history seams - #13839
Merged
os-steve merged 4 commits intoAug 31, 2026
Conversation
…harness Measurement checkpoint: over the CURRENT unfiltered stub the positive case is green (vacuously) and the two cross-tenant controls are red, which is what proves those controls are not writable against a stub that ignores the where. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UngCYXF98BVpYA9hfz6NYk
…th history seams Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UngCYXF98BVpYA9hfz6NYk
…ta-read-org-scope-stub-honours-where
… repaired stub Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01UngCYXF98BVpYA9hfz6NYk
Contributor
📓 Docs Drift CheckNothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs. What this run could not see
Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): |
os-steve
marked this pull request as ready for review
August 31, 2026 15:06
Uh oh!
There was an error while loading. Please reload this page.
os-steve
deleted the
claude/issue-13764-meta-read-org-scope-stub-honours-where
branch
August 31, 2026 15:29
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 freeto 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#13764
The stub engine in
packages/rest/src/rest-server-meta-read-org-scope.test.tsdiscardedopts.whereon bothsys_metadata_historyseams —findOneanswerednullunconditionally and
findhanded back every history row unfiltered — and was alsolimit-blind, one of the 168 doubles
check:objectql-double-limitgrandfathers. Bothseams are repaired on one edit, plus the matcher's silent-combinator hole.
There was no live defect and no vacuous claim in the file as it stood: it drove only
PUT /meta/:type/:name,GET /meta/:type/:nameandGET /meta/:type, and everyassertion it made its stub genuinely kept. What is repaired is a trap — the file whose
name reads like the obvious home for a
/historyorg-scoping assertion was the one filewhere that assertion could not be tested.
The deliverable is the discrimination control, not the green gate
SysMetadataRepository.history()anddiffMetaItemfilterorganization_idby strictequality and post-filter nothing, so over an unfiltered stub the org predicate is a no-op.
The control mutates the
/historydoor to not forward the organization — the exactline
...(historyOrganizationId ? ...)insideGET /meta/:type/:name/history— and readsone assertion,
serves the org-scoped change log of an item the active org authored, inall four cells.
PASSPASS— the vacuity, measured directlyPASSFAIL—expected +0 to be 2Verbatim, cell 2 (old stub, org dropped):
and cell 4 (new stub, org dropped):
Green in both states before, red in exactly one state after. That is the discriminating
power the card is about.
⛔
rest-server.tsis held hard-serial by #13280 and nothing lands in it here. It wasmutated transiently for the measurement only, with the blob hash equal to its
HEADblobbefore and after, the removed and injected text counted in both directions, and an empty
git diff HEADon the restore leg.The second axis of the control
The two cross-tenant cases were not writable at all against the old stub — they were
red over it with the org forwarded and with it dropped, because an unfiltered read hands
org B org A's rows whatever the door does. They are green over the new stub in both
states. That makes
does not serve org A history to org Bthe assertion that holds thestub partitioned: the positive case stays green if anyone un-partitions the stub again,
and only the cross-tenant one reddens.
Was
findOne's unconditionalnullload-bearing? Measured: noPredicted before running, from the production call sites — the only callers of
findOneon that table are
getByHash,restoreVersionandresolveMetaItemOrgScope, none ofwhich a PUT reaches; the write path reads history through
find, innextEventSeqandnextItemVersion. The sibling harness landed in #13756 implements this exact seam anddrives the same PUT path green, which is the positive control for the prediction.
Confirmed: with the seam honouring the
where, all 15 pre-existing assertions staygreen and the file runs 18/18. So the implement form was safe and the refusal form was not
needed on this seam.
Which form on each axis, and why
whereonfind— implemented, not refused. Refusal was not available: anorg-scoping assertion has to be able to read the partition, and a seam that throws on
every predicate is red in both states rather than discriminating.
whereonfindOne— implemented, matching the sibling, once thenullwasmeasured not load-bearing.
limit— applied after the filter and by presence,typeof opts?.limit === 'number',on both table branches, which is
check:objectql-double-limit's shape rule. Every callthis fixture makes passes no bound, so every existing assertion keeps its meaning.
is the one place refusal is right: a double that answers
$andby looking for a columnliterally called
$andreturns a well-formed wrong answer, which is the same silentclass one level down.
The door's own
?limit=contract and the/diffand non-overridable controls are pinnedby
rest-server-meta-history-diff-org-scope.test.tsand are deliberately not copiedhere — the gate's own probes exercise the shape rules of the double itself, and
duplicating the sibling's door pins would be redundant coverage rather than new
information.
Baseline ratchet
scripts/objectql-double-limit.baseline.jsonloses itsrest-server-meta-read-org-scopeentry. Not a new baseline row — a ratchet down, which the gate requires in the same
PR; it reconciles in both directions and errored with
baselined file is clean or gone -- ratchet DOWNuntil the entry was deleted.Verification
Union derived with
scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackaftermerging
origin/mainand after the last edit, harvested with--commands. Everythingbelow ran at
aab1254550, tree clean.by exact
comm -23of the sorted union against the sorted ran-list — no prefix or fuzzymatching, and no arithmetic on a hand-kept counter.
comm -13is empty too.One non-zero exit, and it is NOT MEASURED rather than a finding, in the gate's own
words:
The two gates this change is really answerable to, quoting their own verdict lines:
Also run, all exit 0:
pnpm --filter @objectstack/rest test— 164 files, 2764 tests, all passedpnpm --filter @objectstack/rest typecheck—check:test-typecheck: OK. The editedfile was confirmed present in that program by
tsc --listFiles(1 hit, with the siblingharness as the positive control), so the green really covers it. The 2 remaining
tscerrors are the pre-existing pinned
src/rest.test.tsdebt held by The 2 remaining ledgered TS2345 in packages/rest are hand-builtIHttpResponseliterals — they were masked by the request literals, not absent #13454; zero comefrom this diff.
pnpm lint— the whole repo,eslint . --no-inline-config, exit 0 in 85s. Nonarrowing claimed and none needed.
pnpm check:nul-bytes—OK (scanned 7598 text file(s) … no raw ASCII control bytes),plus a direct control-byte scan over both edited files.
Changeset
Proposed: the
skip-changesetlabel, and this is a reading rather than a preference.packages/rest's manifest declaresfiles: ["dist", "README.md", "CHANGELOG.md"], andnpm pack --dry-runreports an 8-file tarball that does not contain the edited testfile, with
dist/index.jspresent as the control that the reading is real. The other fileis a CI-internal gate ledger. So the change publishes nothing from any package.
The seat rule says to prefer release noise over a silent gate bypass when the two readings
conflict — here they do not, and the bypass surface was measured rather than assumed:
Check Changesetruns exactly three substantive steps, and this diff adds no changeset atall (so there is no empty-frontmatter file to reject) and declares no breaking change (so
no ADR-0087 disposition is owed). The one thing that stretches the closed list is that the
baseline ledger sits in
scripts/rather thanscripts/pm/; it is the gate's mandatorysame-PR companion to the test edit and cannot be split out.
Generated by Claude Code
Generated by Claude Code