test(client,runtime): close 337 refused authz-resolver reads — the false-green class on this lane's nine sites - #18082
Merged
Conversation
…sing fixtures WIP — the seven `@objectstack/client` sites from #18070 now register the `sys_*` objects `resolveUserAuthzGrants` reads, locally and with only the columns that reading path touches. Claude-Session: https://claude.ai/code/session_01TbSMtGzMrtPwh925wDEZd5 Co-authored-by: Claude <noreply@anthropic.com>
WIP — the two `packages/runtime` integration fixtures now provision the five authz tables locally, and the `silentChannels` pins that asserted the refusals are replaced by an assertion that the same reads succeed. Claude-Session: https://claude.ai/code/session_01TbSMtGzMrtPwh925wDEZd5 Co-authored-by: Claude <noreply@anthropic.com>
…thz-resolver-false-green
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-warren
marked this pull request as ready for review
September 14, 2026 00:22
os-warren
enabled auto-merge
September 14, 2026 00:23
This was referenced Sep 14, 2026
This was referenced Sep 14, 2026
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 #18070
The false-green class, closed on the nine sites this lane owns: seven
@objectstack/clientfixtures where the refusals were visible in the log,and two
@objectstack/runtimeintegration fixtures where the symptom waspinned rather than closed. Test-only: no product code is touched, and no
dependency edge onto
plugin-auth/plugin-securityis added.What was wrong
core/src/security/resolve-authz-context.tsreaches fivesys_*tables throughtryFind, which classifies a missing table as "not provisioned" and answers[]. A fixture that boots a realObjectQLover a realSqlDriverbutregisters a narrower object set therefore gets a green it did not earn: the
assertion passes because the read returned empty, not because the state was
empty. A suite in that condition cannot turn red when grant resolution breaks.
The card's counts, RE-MEASURED (not transcribed)
Every number in the card was re-derived on
fb29f62ce, classified by the(table, filter, limit)triple of the eight reads the resolver issues — sosys_position ... where name in (...) limit 200counts andwhere name = ? limit 1on the same table does not.client/src/client.metadata-prefix.test.tsclient/src/client.hono.test.tsclient/src/client.data-prefix.test.tsclient/src/client.batch-transaction.test.tsclient/src/auth-get-session-envelope.test.tsclient/src/client.environment-scoping.test.tsclient/src/auth-login-register-envelope.test.tsWhole-package control, same tree, same command shape:
@objectstack/clientemitted 264 refused reads of which 227 were resolver-class; after, 37
of which 0 are. The 37 that remain are
sys_metadata25,sys_setting7,sys_metadata_history3,sys_organization2 — theprobeInstallOrganizationsand boot-metadata classes, a different card. The seven summing to the
whole-package 227 is what proves there is no eighth site.
The instrument under-reads, and here is the proof
The two
@objectstack/runtimesites route their refusals throughcaptureExpectedReadRefusals(#10629 / #11081), which withholds the driverline. Measured on
fb29f62ce:grep -c "refused a read on"over a full run ofeither file reads a clean 0, while the capture's own counter reads
After:
{"sys_setting":2}and{"sys_setting":3}— 110 resolver-classrefusals closed, and
sys_setting, which is not resolver-class, deliberatelyleft exactly as it was.
Total across this PR: 337 refused authz-resolver reads closed (227 visible +
110 withheld).
The count falls because the read SUCCEEDS
Nothing is silenced, filtered or re-levelled. Proven positively by a one-off
probe that seeded one row per table and printed what the read returns —
injected, run, then restored under a
trapand verified byte-exact withgit hash-objectagainst each path's HEAD blob:A by-product worth naming: seeding those rows made the new runtime assertion go
RED (
expected [ { id: 'probe-user', …(6) } ] to deeply equal []). That is theassertion reading real state rather than a stub.
⭐ The
runtimehalf: a passing assertion had to move, deliberatelyThis is the review's sticking point, and it should be.
Both runtime fixtures declared
ABSENT_AUTHZ_TABLESand assertednoise.silentChannels(ALWAYS_READ_AUTHZ_TABLES)— an assertion that each of thefive reads was still being refused. That pins the symptom. Closing the read
necessarily falsifies it, and leaving it in place would leave a pin asserting a
number that no longer describes reality.
It is replaced, not deleted. What it asserted about behaviour — "these five
reads really happen on this path" — is now asserted in the direction the fix
runs, by
expectResolverAuthzReadsSucceed(): each read SUCCEEDS and answers[]because the state is empty rather than because the table is missing. Samecall sites, same
-t-safety (per authed test in the hono file; inafterAllfor the conformance file, with the shutdown moved into a
finallyso the oldinvariant — a failure here can never leave the kernel running — survives the
reordering the live-engine read forces).
ABSENT_AUTHZ_TABLESshrinks to['sys_setting'], which is the shared capturemodule's own prescribed repair: "a table that started resolving means the
fixture now provisions it". ⭐ Shrinking that list is also what keeps the
capture from becoming a mute:
captureDriverforwards an unrecognisedrefusal straight to
console.warn, so a regression that stops provisioning oneof the five is now LOUD as well as red — where, while the five were declared,
the same regression would have been withheld and merely counted.
Ablation — the new pin can fail
Registration deleted, on-disk landing proven by anchor counts before/after
(
rt2=1 cl1=1→rt2=0 cl1=0, oneABLATEDmarker each), restored under atrapand verified byte-exact against HEAD:notification-schema-conformance.integration.test.tsTestspass. The failure is the newafterAllassertion, i.e. the pin catches exactly the regression it exists for. The five driver refusal lines are also visible in the output, confirming the loudness claim above.client.environment-scoping.test.tsScope and fences
resolve-authz-context.tslives inpackages/core/src/security/(domain:engine) and is not touched. Nothing needed it.packages/specis not touched. The only new dependency on it is aimport type { ServiceObject }— a type already re-exported from@objectstack/spec/data, which both packages already depend on.idis not declared anywhere — the registry supplies the primary key).sys_position_permission_setandsys_permission_setare deliberately absent: the resolver reaches them only after asys_positionrow resolves, and measurement confirms neither appears in any of these files' refusals before or after.skip-changeset, measured rather than assumed. Both packages publishfiles: ["dist","README.md","CHANGELOG.md"];grep -rlfor the new symbols (AUTHZ_RESOLVER_OBJECTS,expectResolverAuthzReadsSucceed) over every one of those paths returns zero hits, against a positive control (ObjectStackClient,createRestApiPlugin) that hitsdist/. No published artefact moves.Acceptance notes
Out of scope, observed while measuring, filed as nothing:
@objectstack/clientstill emits 37 refused reads (sys_metadata25,sys_setting7,sys_metadata_history3,sys_organization2) and the tworuntimefixtures still withholdsys_setting(2 and 3). None is resolver-class by the(table, filter, limit)classifier — they are theprobeInstallOrganizations/ boot-metadata-load / localization-settings classes, which [finding] 227 refused authz-resolver reads in @objectstack/client and 2 pinned-not-closed sites in @objectstack/runtime — the false-green class, measured outside domain:services #18070's body and PR test(triggers,plugins,services): the authz false-green sweep — five in-lane fixtures now provision the resolver's tables #18067's own notes already separate out. Noted, not filed: the carrier is whoever picks up that class, which lands in these same files.expected-read-refusal-noise.tsprescribes the repair for "a table that started resolving" (drop it from the declared list) but offers nothing to assert the success that replaces the refusal, so each consumer hand-rolls it — this PR writesexpectResolverAuthzReadsSucceed()twice. A design observation about a test helper, not a defect in it, and not a reproducible failure: noted, not filed, carrier none.Verification
See the report comment on #18070 for the full gate table and exit codes.
Authored by Claude Code in session
session_01TbSMtGzMrtPwh925wDEZd5— kept as prosebecause this body was EDITED after creation, and the edit channel appends its own
footer block: a session-URL footer sent on an edit ends up with the platform's bare
one beneath it, two footers where the form allows one.
Generated by Claude Code