Skip to content

Route audit tranche 2: the @objectstack/rest surface (search / forms / reports / sharing / …) — #3563 follow-up #3587

Description

@os-zhuang

Split from #3563. The dispatcher tranche is complete (gap ratchet 27→0, #3569 #3571 #3575 #3577 #3579), but the dispatcher is not the only server surface: @objectstack/rest mounts a second, larger route set the client also reaches — and it has never been audited with the same rigor.

Known zero-expression routes (from the PR-1 sweep, rest-server.ts line refs in the audit doc)

Route family Routes
GET /search?q&objects&limit&perObject 1
POST /email/send 1
forms/:slug (get / submit / lookup) 3
Record shares GET/POST/DELETE /data/:object/:id/shares[/:shareId] 3
POST /data/:object/:id/clone 1
POST /analytics/dataset/query 1
sharing/rules (incl. /evaluate) 5
reports (incl. /run, /schedule, /schedules) 8
external-datasource/* (external-datasource-routes.ts) family

Plus the reverse direction that tranche 1 deliberately left out of scope: client surfaces that target REST-only routes (views CRUD, permissions, workflow, approvals, realtime, notification devices/preferences, presigned storage, import jobs) — currently expressed but with no ledger row anywhere asserting their server side exists.

Proposed method — same as tranche 1, one new problem to solve

  1. Enumerate the REST mounts (rest-server.ts is large; the mounts are server.<verb>() calls — scriptable).
  2. Extend the ledger (or add a sibling rest-route-ledger.ts in packages/rest) with per-route dispositions.
  3. Guard on both sides, same split as feat(runtime): route ledger + conformance guard for the dispatcher↔client surface (#3563) #3569: enumeration-side conformance next to where routes are declared; client-method existence next to the SDK. The tranche-1 lesson applies verbatim: no runtime→client package edge (build cycle) — each package verifies its own half.
  4. New problem tranche 1 didn't have: REST route registration is method calls, not a registry with .list(). Either add an introspection seam to the REST server (preferred — mirrors DomainHandlerRegistry.list()), or pin the mount list the way LEGACY_CHAIN_PREFIXES pins the if-chain.

Acceptance

  • Every REST-mounted route has a reviewed disposition.
  • A ratchet equivalent to tranche 1's, wired into CI.
  • The reverse direction closed: every client method's target route provably exists on some server surface.

Refs: audit doc docs/audits/2026-07-dispatcher-client-route-coverage.md §8; ledger scope note at packages/runtime/src/route-ledger.ts header.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions