Repository navigation
test(rest): cover the appended tenancy positional and stop hand-typing the slot-lookup pin's figures - #17812
Conversation
…g the slot-lookup pin's figures The slot-lookup pin's `PROVIDERS` table stopped one argument short of the constructor, exactly at `tenancyServiceProvider` — the parameter appended last because inserting one mid-list "would silently re-bind every positional argument after it", which is the failure this pin exists to catch. Absent from the table, nothing drove it, its slot never entered the compared lookup set, and the guard read green against any binding at that position. Add the row, and add a ledger for the two in-span arguments that are deliberately not providers, so every index from the first provider to the last argument the composition root passes is accounted for. The header's two hand-typed figures are removed rather than corrected: a span figure and a slot count stated in the present tense with no date are what produced this defect. Claude-Session: https://claude.ai/code/session_01TSf4DV7ziu4V5j73e46b7c Co-authored-by: Claude <noreply@anthropic.com>
📓 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): |
|
ACCEPT — Gate state
⭐ The dev corrected the card's stated mechanism, and it was the mechanism this seat relayed into the dispatchThe card said, and triage repeated, and this seat's dispatch order repeated again, that the tenancy provider was invisible because it is lazy. The report says that is false. That is the one claim here worth re-measuring independently, because it is the claim this seat passed along without checking: The two openings are structurally identical, and ⭐ The distinction is not rhetorical. On the laziness story the fix might have had to change the comparison — which is exactly the second hard stop this seat wrote into the dispatch. On the real mechanism it is one row. The dev did not accept the relayed mechanism; it measured, and both stops stayed shut for a reason rather than by luck. The figures were REMOVED, not corrected — which is what the ruling asked for first
The header now says outright that neither figure is written as a numeral on purpose, and it distinguishes the two failure modes: the span figures were accurate the day B4 wrote them and went stale by one; the slot count matched no quantity derivable from the file even then. ⭐ 「先删容许出错的构造,再让正确形态成唯一拼写」 — the erroneous construction here was a hand-typed constant in prose, and it is gone rather than re-typed correctly. The only spelling of either quantity is now one the suite can fail on. The new pin, and why it is not a phantom
⇒ the move #15256 made because inserting mid-list "would silently re-bind every positional argument after it" now forces a decision in this file instead of landing uncovered. The ablation — three legs, and leg A is the card's defect measured directly
Each leg proved on disk (grep counts of removed and injected text, The
|
Fixes #17716
Clause-②: no
What was wrong
packages/rest/src/rest-api-plugin-slot-lookups.test.tspins the REST composition root'spositional wiring. Its
PROVIDERStable stopped one argument short of the constructor,exactly at
tenancyServiceProvider— the parameter #15256 appended LAST on purpose,because inserting one mid-list "would silently re-bind every positional argument after
it". That is the exact failure this pin exists to catch, and it did not cover the
parameter that reasoning protected.
The header also stated two figures in the present tense with no date: a spelled-out slot
count, and an "arguments A..B of an N-argument constructor" span.
The hole, measured rather than argued
Control: bind
authServiceProviderat the LAST constructor position inrest-api-plugin.ts, wheretenancyServiceProviderbelongs. Nothing else moves, so theonly argument a row for that index could observe is the one that is wrong. Same mutated
blob in both legs (
a44973312542d74da442b4aae51908e9240fd5c4); the only variable is thetest file.
PROVIDERSwithout the row (pre-fix)Tests 5 passed (5)— green against a deliberately mis-bound positionalPROVIDERSwith the row (this PR)Tests 2 failed | 4 passed (6)Leg B's two failures:
The second one is the answer to the laziness question the card and the triage ruling both
flagged. The row does enter the compared lookup set, so the last case needs one more row
and not a different comparison — the hard fork does not fire. Laziness was never why the
provider was invisible:
objectQLProviderat index 7 has the identical kernel-first /sync-fallback shape and has always been covered. It was invisible because it was absent
from the table, so nothing ever drove it and the slot was never asked for.
packages/rest/src/rest-api-plugin.tsis read-only for this card. That mutation wastemporary, trap-guarded, and verified restored byte-identical to HEAD
(
restored blob == HEAD blob,git diff HEADempty) after each leg. It is not in thisdiff.
The new pin is itself driven
Leg C ablates the new row out of
PROVIDERSon this PR's tree and runs again:Exactly one case reds, and it is the new one — the other five stay green, which is the
card's defect reproduced in isolation. That case is the machine that would have caught
#15256's append.
Both figures derived, neither re-typed
Derived with the TypeScript compiler API over
rest-server.tsandrest-api-plugin.ts.⛔ Not a bracket-depth counter: an arrow token and a generic type argument close a naive depth counter
early, which is the instrument the triage ruling recorded as broken.
RestServerdeclared parameters6 7 8 9 10 11 12 13 14 15 17 19 206..19, so the appended provider fell outside itrest-api-plugin.tsresolvesnew RestServer(...)passesThe 20 distinct slots:
analytics approvals auth default-project email env-registry http.server i18n kernel-manager kernel-resolver manifest metadata objectql protocol reports security settings sharing sharingRules tenancy. Threectx.getService(name)call sitesare pass-throughs (the kernel-resolver bridge and the presence probe) and resolve no fixed
slot;
objectqlandtenancyare each reached twice (akernel.getServiceAsyncleg and actx.getServiceleg) and count once.The slot count was never right — it was not a figure that drifted
Both figures were written by one commit,
1216dcc73(#4251 B4, #5953). Re-running the samederivation against that commit's tree:
day they were written and went stale when the constructor grew.
rest-api-plugin.ts: 20, not the count the header claimed.That commit's diff retypes 14 lookups in this file, and the file then held 21
getServicecall sites carrying a type argument (20 non-any). The header's figurematches none of those, then or now.
So it was not "already right", and it was not drift either: it was a number with no
derivation behind it from the first commit. That is worth its own sentence, because the two
failure modes are indistinguishable to a reader — which is precisely the argument for not
writing either figure as a numeral again.
Preferred outcome: not a corrected constant
Per the ruling's order (compute > pin > hand-write with a date), both figures are removed
from the prose rather than corrected:
accounts for every positional argument from the first provider to the last, which derives the span from the captured call (args.length) and requiresevery index in it to be covered by
PROVIDERSor excused in the newNON_PROVIDERS_IN_SPANledger. An argument appended toRestServerlands inside the spanby construction and forces a decision.
BOOT_SLOTS ∪ {default-project} ∪ PROVIDERS, which theexisting
asks for exactly the slots it declarescase already compares against the realaskedlist. Its size is the derived 20.A recorded failed instrument, so nobody repeats it: a runtime
RestServer.lengthpin isnot available.
config: RestServerConfig = {}is parameter index 2, andFunction.prototype.lengthcounts only the parameters before the first defaulted one — itreports 2, not 21.
Nothing was weakened
git difffor this PR removes exactly seven lines, all of them docblock prose carrying thetwo stale figures. No
expect, no assertion argument, no existing case body and no tablerow is touched; every other change is an addition. The two claims the ruling named read
byte-identical after:
Verification
pnpm --filter @objectstack/rest testTest Files 190 passed (190),Tests 3182 passed | 1 skipped (3183)pnpm --filter @objectstack/rest typecheckcheck:test-typecheck: OK … 0 file(s) / 0 error(s) / 0 pinned signature(s)pnpm --filter '@objectstack/rest^...' buildpnpm lint(full repo,eslint . --no-inline-config)scripts/pm/dispatch-gates.mjs --commands)pnpm check:slot-lookup106 unswept site(s) in 25 file(s), none newThe two NOT MEASURED are
check:dual-build-cjs-loadsandcheck:type-check-debt, bothexit 3 =
PREREQUISITE NOT MET: each needs the whole workspace built, which is afarm-scale run CI owns. Neither is a red, and neither can be moved by a change confined to
one
.test.tsfile. Reconciled with--ran: "52 derived famil(ies) accounted for — 50run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3)".
All numbers above were taken at
034629082, the final commit.No changeset — measured, not assumed
@objectstack/restis published ("private"absent) and shipsfiles[]: ["dist", "README.md", "CHANGELOG.md"]. The one changed path ispackages/rest/src/rest-api-plugin-slot-lookups.test.ts;src/is not infiles[], andCI's No compiled test files in any dist step holds the other direction.
Grepped over all three
files[]paths afterpnpm --filter @objectstack/rest build:NON_PROVIDERS_IN_SPANaccounts for every positional argumentrest-api-plugin-slot-lookupscreateRestApiPlugintenancyServiceProviderRestServerThe positive controls prove the grep reaches the shipped bytes; the negatives are therefore
absences, not a broken probe. Nothing published moves ⇒
skip-changeset.Acceptance notes
not have. The span is derived from the arguments the composition root actually
passes. A parameter appended to
RestServerthat the composition root never passesleaves
args.lengthunchanged and the span pin green. That is a different defect (aparameter wired nowhere), the declared scope of the new case says exactly what it covers,
and closing it would mean parsing
rest-server.tsfrom inside a unit test. Noted, notfiled.
packages/rest/CHANGELOG.mdquotes the old docblock verbatim in two released entries(the B4 entry and its re-publication). Those are RELEASE-OWNED and are accurate records
of what the code said at that release, not factual errors in the entries. Left untouched.
rest-api-plugin.tsandrest-server.tsare unchanged in this diff. [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, which holdsrest-api-plugin.ts, is unaffected. The in-flight surface of A repeated?version=onGET /packages/:idis refused with404where the landed precedent for that exact condition on that exact route is400 VALIDATION_ERROR— and the one module that owns the rule is unreachable from the dispatcher package #17672(
packages/rest/src/index.ts,query-multiplicity.ts,packages/runtime/src/domains/packages.ts) is disjoint from this one-file diff.Generated by Claude Code