Repository navigation
test(rest): the objectQLProvider consumer census, made mechanical — and its third consumer, driven - #18556
Merged
os-support-ai merged 1 commit intoSep 17, 2026
Conversation
… drive its third consumer The engine slot's consumer set has been counted as two, twice, by two seats: #14251's phase-1 census table, and the docblock of the #15405 repair. There are three -- `POST /batch` reads `this.objectQLProvider` directly, and it was already on the tree both readings were taken against. Neither enumeration could fail, because both were prose. This adds the enumeration as a test: the call sites are read out of `rest-server.ts` source, the count is pinned at three, and the scanner carries a positive and a negative control so a future zero means "gone" rather than "stopped matching". The third consumer is then driven for the first time -- absent, unwired, rejecting and synchronously-throwing engines, plus a served 200 and a declared 400 so the instrument can say something other than a fault. Measured: a rejection reaches 500 INTERNAL_ERROR where the `undefined` path reaches 501 NOT_IMPLEMENTED, so this consumer does NOT re-collapse. The 500 is recorded, not ruled -- the slot's two other consumers answer 503 for the same fact, and whether this door joins them is a per-consumer wire ruling. Claude-Session: https://claude.ai/code/session_01DvvamiacK328idtBYJBxV3 Co-authored-by: Claude <noreply@anthropic.com>
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): |
This was referenced Sep 17, 2026
os-support-ai
marked this pull request as ready for review
September 17, 2026 01:50
os-support-ai
deleted the
claude/issue-18546-engine-slot-consumer-census
branch
September 17, 2026 02:14
This was referenced Sep 17, 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.
Part of #18546 — deliverable 1 is delivered and pinned here; deliverable 2's disposition is the seat's, for the reason in the second section.
#18546 remains openon purpose.Deliverable 1 — the consumer census, and it disagrees with the record
The engine slot has THREE consumers, not two. Both prior enumerations counted two, in the same direction, and the third was already on the tree each of them was taken against.
79a046f8c5542086636accepts it)computeExecCtx,GET /meta/object/:name/state/:fieldobjectQLProviderhas two consumers inrest-server.ts"The third is
POST /batch(the cross-object transactional batch door), which reads the field directly. It was present at the census sha:git show a56baa2bdf:packages/rest/src/rest-server.ts | grep -n 'this.objectQLProvider'prints2362,2363,7452,7453and12251. It is not hidden either — the provider's own docblock inrest-api-plugin.tsnames it in as many words, "thetransactionprobe behind the batch routes". Neither enumeration could fail, because both were prose.The pathspec bound of this enumeration, not only the count
Bound: every read of
RestServer's private fieldobjectQLProvider, inpackages/rest/src/rest-server.ts. That is the whole reachable set, and two facts make it so — both now asserted in the new pin rather than argued here: the shipped closure is handed to exactly onenew RestServer(...)construction site inpackages/rest/src/rest-api-plugin.ts, and the field is read only asthis.objectQLProvider(no bracket access, noas anyread) in any non-test source.Control that can fail, carried per the dispatch's instruction. The scanner is run against a symbol known to be present — it must find sites, and it does — and against one known to be absent, which must read zero. So a future zero means "gone" rather than "the regex stopped matching". That is the failure mode that produced the two-consumer sentence in the first place: a consumer that cannot be parsed and a consumer that does not exist look identical, and the correct actions are opposite.
What this search cannot see, stated rather than rounded away:
objectqlservice through a different producer. Two exist and neither is this slot: the deliberately-absorbing KERNEL branch at the samecomputeExecCtxseam (kernel.getServiceAsync('objectql')viaseamOrUndefined, the RESIDUEwiredEngineOrLouddocuments and [finding] every OTHER shipped provider in rest-api-plugin.ts still absorbs the three-state ctx.getService throw — the #13904 shape, waiting one seam over #14251 leaves in place), and roughly ninety directctx.getService('objectql')sites in other packages, each its own seam.origin/mainat79a046f8c.privateis compile-time only. No such spelling exists in this repo's non-test sources, which is what the pin asserts; it cannot speak for code that is not here.The verdict on the decidable test — driven, not inferred
The tightened test from comment
5542086636: a slot is ripe only when NO consumer converts a rejection into exactly the value itsundefinedpath produces.undefined(absence)computeExecCtx, viawiredEngineOrLoudAuthzStoreUnavailableErrorundefinedGET /meta/object/:name/state/:field, viawiredEngineOrLoudsince #17077NOT_FOUNDPOST /batch, directawaitinto the handler's owncatchINTERNAL_ERRORNOT_IMPLEMENTED⇒ No consumer re-collapses. The slot is ripe. The card's STOP branch is therefore not triggered: there is no re-collapsing consumer to file.
handleRouteError, not through the seam helper its two siblings use — and it answers 500 where they answer 503 for the identical fact. ⛔ That is recorded, not ruled, and ⛔ nothing here moves it: a public door changing its answer is the per-consumer wire ruling #14251 reserves. It is handed back as a finding.Deliverable 2 — ⛔ the premise is falsified: there is no provider half left to repair
The card says deliverable 2 is "the provider-half repair in
rest-api-plugin.ts, in the shape #13904 landed forobjectQLProvider". Read atorigin/main79a046f8c,objectQLProvideralready is that shape — #13904 landed it on this very closure: the async leg absorbs onlyisServiceNotRegisteredErrorand re-raises everything else, the sync leg is the documentedKernelBaseleg the census explicitly fences off from any phase-2 roster, and its pinrest-api-plugin-objectql-provider-three-state.test.tsis on the tree.The engine slot is the census's worked example, not one of the twelve unrepaired slots (those are
auth,security,email,sharing,reports,approvals,sharingRules,analytics,i18n,settings,metadata,default-project). Its consumer half landed first (#13476), its provider half second (#13904), and its second consumer third (#15405 via PR #17077). Both halves are landed. So the only half of deliverable 2 with a target left is "plus the pin" — which is this PR.The two stop-gates — reported, not decided
1.
Clause-②: noMeasured from this diff (
79a046f8c...HEAD), 2 files changed, both*.test.ts, 384 insertions / 3 deletions:git diff … | grep -cE '^\+\s*export '= 0; the new file exports nothingERROR_CODE_LEDGER/StandardErrorCoderefuseUnknownQueryParamsset or.strict()surface is touched; no non-test file is touched at allcheck-clause2-carriers --pairexit code is recorded in theos-dev-reportcomment on #18546, run against this PR number once it existed.⇒ Not a clause-② PR, so it does not park outside the merge queue the way #18428 / #18429 do.
2. Runtime permission/security behaviour change: NO
The diff touches no runtime file — two test files, nothing else — so there is no before/after to have. The dispatch asked for the wire consequence to be DRIVEN rather than inferred, so it was driven anyway, on a real
RestServerover a realObjectKernel, and the answer is that a registered-but-FAILING engine is already told apart from an absent one at all three doors (the table above). What changed it was #13904 plus #17077, both landed; this PR moves none of it.For completeness, the third door's four facts as measured on
POST /api/v1/batchthis run — no provider wired 501, provider resolvingundefined501, provider rejecting 500, provider throwing synchronously 500 — beside a served 200 and a declared 400, so no fault status above comes from an instrument that can only report faults.Verification
HEADafter it (blob hash equal toHEAD:packages/rest/src/rest-server.tsandgit diff HEADempty on both restore legs; the mutation script carries atrap … EXIT INT TERM):exit 1, naming "THREE consumers, not two"); restored → green..catch(() => undefined)spelling → the behaviour pin goes red (exit 1, naming the decidable-test assertion); restored → green.11 passed (11).pnpm --filter @objectstack/rest test— 193 files, 3229 passed, 1 skipped.pnpm --filter @objectstack/rest typecheck— clean.pnpm --filter @objectstack/rest check:test-typecheck—0 file(s) / 0 error(s) / 0 pinned signature(s).pnpm --filter '@objectstack/rest^...' build— green (dependency closure, so nothing above read a staledist).origin/main— ⛔ not reused from the dispatch, whose checkout the tool reported stale:node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack→ 53 commands, all 53 run, reconciled with--ran: "53 derived famil(ies) accounted for — 51 run, 2 NOT-MEASURED".pnpm lintrepo-wide (the lane blind spotdispatch-gatesdoes not name) — exit 0, whole tree, no narrowing claimed.PREREQUISITE NOT MET(exit 3, a gate refusing its own prerequisite — ⛔ not a finding and ⛔ not a pass):check:dual-build-cjs-loadsandcheck:type-check-debt, each needing every package'sdist/. CI builds first and runs both.exit 1is pre-existing and not this diff's:check:cross-package-test-inputsreds onpackages/cli/test/init-created-files-summary.e2e.test.tswalkingpackages/spec/dist/. Controlled: a detached worktree at79a046f8cwith this diff absent exits 0 with nopackages/spec/dist/on disk and exits 1 with the identical finding once that directory exists. ⇒ the verdict follows local build state, not the change set. Filed back as a finding.skip-changesetmeasured rather than assumed:packages/restshipsfiles: ["dist", "README.md", "CHANGELOG.md"]; afterpnpm --filter @objectstack/rest build, every symbol unique to this diff reads 0 hits across all three, while the positive controlwiredEngineOrLoudis found indist/index.cjs,dist/index.jsandCHANGELOG.md. ⇒ nothing published moves.Acceptance notes
Observed while measuring, ⛔ not filed and ⛔ not fixed here:
enumerateAbsorbSites()inexecctx-authz-input-seam-reachability.test.tsis the same instrument as this PR's §1 scanner but scoped to the body ofcomputeExecCtxalone. The two could share one helper; they do not, and this PR does not merge them — a whole-file enumerator is a wider verification surface than this card's. Successor: whichever card next widens that seam census.5706358804and declined to correct another card's body; this PR is not that card either. Successor: the card's next implementer, who reads the body top-down.Generated by Claude Code