Repository navigation
fix(runtime): GET /packages/:id/customizations answers over HTTP, mounted beside the other package reads - #28635
Conversation
…r plugin The read shipped with its route-ledger row and its domain handler but no mountPackagesRoute() call, so the live router answered nothing for it and the Dogfood route-ledger live-mount parity gate went red on main. Co-Authored-By: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 2 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
What this run could not see
Coarse fallback — 28 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin 4699360a38d6fc8f36b57409ec49139bbfa692b2 && git checkout 4699360a38d6fc8f36b57409ec49139bbfa692b2
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin d77dc07a5e5a4b5478763fb3a2126913c92f8c01 67e1f910957f24385391b420070e7c26e4b7ac61 && git checkout -B drift-repro d77dc07a5e5a4b5478763fb3a2126913c92f8c01 && git merge --no-ff 67e1f910957f24385391b420070e7c26e4b7ac61
node scripts/docs-audit/affected-docs.mjs --json d77dc07a5e5a4b5478763fb3a2126913c92f8c01
|
|
domain:server#1 · os-project-manager · session_01R1q2xdtYgU6FKrZ7LgjPCC 席位核对 · ACCEPT ·
|
| item | reading |
|---|---|
| Shape | Draft, base main, Fixes #28622. Three files: dispatcher-plugin.ts (+3), one new probe test, one @objectstack/runtime patch changeset. Clause-②: no, Metadata-protocol: none. |
| Diff check (seat) | The added line is mountPackagesRoute('get', '/:id/customizations', (req) => \/${req.params.id}/customizations`), placed beside /:id/exportand before the single-segment/:id, the exact shape of its siblings and the order's sketch. registerPackageRoutesruns for both bases, so the scoped prefix gets it too.route-ledger.ts, UNEXERCISED_BY_THIS_BOOTand the dogfood gate are untouched. The probe startscreateDispatcherPlugin()on a recordingIHttpServer, takes the registered GET /api/v1/packages/:id/customizationshandler, and asserts 200 and adatathat parses throughGetPackageCustomizationsResponseSchema`. |
| Evidence | CI green on head 67e1f910 (35 success, 13 skipped, 0 failed; the CI and Lint & Type Check workflow runs both success). Governed check: NOT governed, 121 changed lines. The report gives the dogfood gate route-ledger-live-mount-parity red at origin/main 0e78922e (1 failed / 7 passed, the card's sentence) and green at head (8/8); the probe red with the mount ablated ("must be mounted") and green restored; runtime suite 503/503 files; 57 of 58 derived gates exit 0 and 1 NOT MEASURED (check:dual-build-cjs-loads, a prerequisite-only exit 3). |
| Landing | 「按照 pm-dispatch 规则复核过的都授权」 (Leehom, 2026-10-25T11:35Z): ready and auto-merge through the relay, once every check on this head is green or an expected skip. p0 main-red fix, landed ahead of the lane's other PRs. |
Generated by Claude Code
Requested by Leehom · project thread
Fixes #28622
Clause-②: no
Metadata-protocol: none
维护者速读
GET /api/v1/packages/:id/customizations补上 HTTP 挂载,一行,挨着同类的/:id/export。519089e1起每次推送都红在 Dogfood 回归门禁上,挡住所有车道的合并后读数。packages/runtime/src/dispatcher-plugin.ts(新增的那一行挂载);packages/runtime/src/dispatcher-plugin.package-customizations-mount.test.ts(经挂载路由打到接口的探针)。pnpm --filter @objectstack/dogfood exec vitest run test/route-ledger-live-mount-parity.dogfood.test.ts,预期 8/8 通过(main 上是 1 失败)。What changes
packages/runtime/src/dispatcher-plugin.ts: onemountPackagesRoute('get', '/:id/customizations', (req) => '/' + id + '/customizations')call, beside its two-segment siblingGET /:id/export. It is the exact shape every sibling uses (same registrar, samedispatcher.dispatch(...)pipeline: kernel resolution, identity, auth gate), so it matches the card's sketch with no difference. BecauseregisterPackageRoutesis called for both bases, the route is mounted at/api/v1/packages/:id/customizationsand, with project scoping on, at/api/v1/environments/:environmentId/packages/:id/customizations./:idis single-segment, so registration order shadows nothing.packages/runtime/src/dispatcher-plugin.package-customizations-mount.test.ts(new): startscreateDispatcherPlugin()against a recordingIHttpServer(the harness ofanalytics-empty-cube-refusal.test.ts), takes the handler registered forGET /api/v1/packages/:id/customizations, and calls it the way the transport does. It asserts 200, the success envelope, the domain handler'sdata(one served override from the protocol stand-in, empty extensions and switched-off lists, counts 1/0/0), and that thedataparses throughGetPackageCustomizationsResponseSchema. Identity is stubbed to astudio.accesscaller, asdomain-handler-registry.test.tsdoes for the other/packagesroutes. The read's own behaviour stays pinned indomains/packages-customizations.test.ts..changeset/28622-package-customizations-mount.md:@objectstack/runtimepatch.files[]shipsdist, anddist/index.jscarries the new route after a build.Untouched, as ruled:
route-ledger.ts(the row stays),UNEXERCISED_BY_THIS_BOOT, and the dogfood gate. No generated file moved.Why
PR #28595 (#28411) added the ledger row (
route-ledger.ts:544) and the domain branch (domains/packages.ts:2532) but no mount. The dispatcher mounts every/packagessub-route explicitly, so the read 404'd for every caller on a host without@objectstack/hono's catch-all. Its unit test calls the domain handler directly, so it stayed green. TheDogfood Regression Gate (n/3)shards run only onpush, so the first reading was post-merge onmain.Tests
Red on origin/main 0e78922, green at head 67e1f91 (the dogfood gate)
pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/route-ledger-live-mount-parity.dogfood.test.ts, after building the@objectstack/dogfood^...closure.At
origin/main0e78922e, the card's sentence exactly, and nothing else:At head
67e1f910, afterpnpm --filter @objectstack/runtime build(dist/index.jsholds/:id/customizations):The HTTP-level probe: red with the mount ablated, green with it
The probe imports
./dispatcher-plugin.jsfromsrc/(a relative import, nodist/hop), so the ablation needs no rebuild.Green at head:
Test Files 1 passed (1) · Tests 1 passed (1) · VERDICT command-exit 0.Ablation via
node scripts/ablation-replace.mjs --file packages/runtime/src/dispatcher-plugin.ts --anchor ANCHOR --delete -- bash abl-inner.sh:Runtime package
pnpm --filter @objectstack/runtime test:Test Files 503 passed (503) · Tests 8159 passed | 19 skipped (8178) · VERDICT command-exit 0.pnpm --filter @objectstack/runtime typecheck(tsc --noEmit && pnpm check:test-typecheck, so the new test file is type-checked too): exit 0.eslint packages/runtime --no-inline-config: exit 0.Acceptance notes
test:repowas not run locally (it belongs to CI'sTest Core); the diff touches no file of that project.!in the title and no(narrowing)arm. The one gate the card names was run red and green.Verification
Derived gates at 67e1f91 (58 families)
node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackderived 58 families from the 3 changed paths. Each was run with its exit code captured before any pipe, and reconciled with--ran:node scripts/check-plugin-teardown-shape.mjs --self-test: exit 3 on the first run (shallow clone, positive-control commit missing), exit 0 aftergit fetch --depth=1 origin 621a4876….pnpm check:dual-build-cjs-loads, exit 3PREREQUISITE NOT MET(it needs every package'sdist/, which only the dogfood closure was built for). CI runs it.Human Minimum
packages/specholds no runtime logic. (No spec change.)pnpm lintpasses (scoped topackages/runtime).main, one pull request.packages/spectouched: n/a.content/docs/references/,packages/*/CHANGELOG.mdorcontent/docs/releases/.🤖 Generated with Claude Code
https://claude.ai/code/session_01FEkQ5kwT5zvfww7MNoyovM
Generated by Claude Code