Repository navigation
test(dogfood): the anonymous door sweep — ADR-0138 criterion 2 as an in-repo conformance test - #23137
Draft
objectstack-fleet[bot] wants to merge 5 commits into
Draft
objectstack-fleet[bot] wants to merge 5 commits into
objectstack-fleet[bot] wants to merge 5 commits into
Conversation
Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRQ9Mp1yH7R1az6MaUM18H
…eader says what a red run means Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRQ9Mp1yH7R1az6MaUM18H
…onymous-sweep-test
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 Oct 13, 2026
…onymous-sweep-test
…unt family, with route detail behind a local-only switch Co-authored-by: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BRQ9Mp1yH7R1az6MaUM18H
This was referenced Oct 13, 2026
This branch has not been deployed
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 #22146
Clause-②: no (a test; no published accept set or public surface changes)
Summary
The test half of ruling
6134095444: ADR-0138 acceptance criterion 2 is evidenced by a test in the tree, not by a one-off sweep. This PR adds one dogfood suite and its classification table, nothing else:packages/qa/dogfood/test/anonymous-door-sweep.dogfood.test.tspackages/qa/dogfood/test/anonymous-door-sweep.classification.tsNo production code changes, and nothing under
docs/adr/**. The criterion-2 wording and criterion 4's two back-pointers are the next PR of the ruling, after this test is green onmain.The suite is red on this head. That is the result, not a defect in the test. The everything-else class does not answer 401 throughout: one surface family outside D2's list answers an anonymous caller without the 401 floor (class-level result below). As the dispatch orders, the assertion stays as D2 states it. It is not weakened and not marked expected-to-fail, and the PM decides the next step.
What the suite does
Boot. It boots the showcase the way a deployment serves it:
bootShowcase, plus two extras.MetadataPluginruns over a build-shaped artifact, becausecreateStandaloneStackcomposes it and declared endpoints only route through it.MCPServerPluginis added becauseservemounts MCP by default.Population. It reads the registered route table off the running server, from three sources:
getMountedRoutes();getRawApp().routes, which also holds the raw-app mounts;Nothing in the population is listed by hand. The derivation is guarded by a floor per source, by asserting the port table is a subset of the framework table, by one anchor per source, and by checking that every declared endpoint resolves through
matchEndpointto itself.One unauthenticated request per route. Middleware is the exception, because it serves no request of its own.
A closed table. Each answer is judged by the route's class: D2's six door classes, the surfaces outside the guest model by construction, middleware, and nothing else.
Every class on a real subject, admitted and refused. A sweep whose probes name nothing can only observe the refusal half of a door. The subjects are the showcase's own or are created in-test while signed in: the public form, the shareable brief, the public book, an uploaded file. The showcase has no subject for three of the legs, so they are declared inline beside it:
object_operationendpoint and an anonymousflowendpoint, over a flow with no data step;org-audience book;The showcase's own two declared endpoints are
authRequired: trueand of the same two types, so they serve as the negative controls of classes 4 and 5.The assertions are class-level. A failure names the route pattern and the status class it answered, never a body.
Classification, for the ADR amendment to name
Door classes (D2):
/metaread routes, which the sweep holds to 401 for every other subjectauthRequired: falseendpoints,object_operationauthRequired: falseendpoints,flowacl: 'public_read'file downloadOutside the guest model by construction. Each row carries its reason in the table.
isAuthGateAllowlisted, never a copy of its paths;RuntimeConfigPlugin's bootstrap reads;bootStackruns the development posture.isAuthGateAllowlisteddoes not name literally (the REST root and the dispatcher's well-known document);Middleware: the server-wide
*registrations.Class-level result on this head
authRequired: falseobject_operationauthRequired: falseflowacl: 'public_read'file downloadThe family, at function level only: the settings service's REST family (
registerSettingsRoutesin@objectstack/service-settings, mounted bySettingsServicePlugin). It opens no handler with an anonymous floor, so it answers an anonymous caller from its own authorization logic rather than with 401. On this boot it served no settings value. The status class is still not the one D2 states. The finding is in the report on the card, for the seat to file.Proof the suite can fail
Two ablations, each through
scripts/ablation-replace.mjs(anchor hit, then restore proven by blob hash againstHEADand an emptygit diff HEAD):eb86b66c06==HEAD.dist/. One dispatcher domain's anonymous floor (shouldDenyAnonymousin the/i18ndomain of@objectstack/runtime) was bypassed in source, and runtime was rebuilt.ablation-dist-preflightfound the marker in 2 built files, and the everything-else case named 4 → 7 routes.d111be27d4==HEAD, runtime rebuilt, the marker absent from all 6 built files, the tree clean, and the everything-else case back to the same 4.Both moved in the predicted direction: more diagnostics, not a different failure.
Tests
Run on head
bf3ba9957, which mergesorigin/maindfb3ba2b2:pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/anonymous-door-sweep.dogfood.test.ts test/authz-conformance.test.ts: 74 passed, 1 failed. The failing case is the everything-else one, on the settings family.authz-conformanceis green; it scans every*.dogfood.test.tsfor row attribution, and the new file claims no row.pnpm --filter @objectstack/dogfood typecheck(tsc --noEmit): exit 0.tsc --listFilesOnlylists both new files in the program.--no-inline-config --format json: 0 errors, 0 warnings over 2 files. The narrowing is safe becauseeslint.config.mjsenables no type-aware linting (noparserOptions.projectorprojectServicein the printed config), so no untouched file's result can change.node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderives 53 commands from the merge base. All 53 were run on this head and every one exits 0. The--ranreconcile prints53 derived famil(ies) accounted for — 53 run, 0 NOT-MEASURED (a DERIVED zero — all 53 recorded an exit code and none of them is 3). Two of them first exited 3 (PREREQUISITE NOT MET): one needed a pinned commit the shallow clone lacked, and one needed 8 packages that had nodist/. Each was re-run once its prerequisite was met, and both exit 0.Acceptance notes
isolateddogfood project by its file name;packages/qa/dogfood/vitest.config.tsis untouched, and PR test: the stage-8 test half — suites stop depending on the four catalog row objects (#15204 stage 8, S8-T) #22962 edits it. It runs with the dogfood battery, which is part ofmain's full battery. PR and queue runs carry the fast set, so this draft's own CI does not run it. Landing it while the settings family is open makes the dogfood battery red onmain.UNAUTHENTICATED, andAUTH_REQUIREDon the storage family's refusals. D2's text namesUNAUTHENTICATED, while criterion 2 judges the status class and what is served. The suite asserts the status and the error envelope and does not pin the code. Noted for the ADR wording PR.mainthat text lands in CI logs. It never carries a body.skip-changeset.Parked in draft (written by the seat,
domain:specseat 2)This PR stays draft until the settings family answers anonymous callers with 401. The dogfood battery is not in PR or queue CI, so this red shows in no check run here, and landing first would turn
main's dogfood battery red.anonymous-door-sweep.dogfood.test.ts›the everything-else class answers 401 throughout, with nothing served, printingeverything-else · /api/settings (port): 4 route(s) red(the local run on4bdd92c65). Every other case is green. A red line naming any other class or family is a new finding, not this one.registerSettingsRoutes) answers an anonymous caller from its own authorization logic instead of the 401 floor; ADR-0056 D2 and ADR-0138 D2 require 401 — the fourth door blocking ADR-0138 criterion 2 #23142 (the settings REST family's anonymous floor) merged. Then: mergemaininto this branch, re-run the suite throughos-verify-lockwith every case green, and only then ready and the queue.docs/adr/**(Tier H) follows once this suite is green onmain.Generated by Claude Code