Skip to content

fix(rest,client)!: reconcile the two REST↔client mismatches the audit ledgered (#3610, #3611) - #3621

Merged
os-zhuang merged 2 commits into
mainfrom
claude/screen-flow-submit-resume-v9dqjx
Jul 27, 2026
Merged

fix(rest,client)!: reconcile the two REST↔client mismatches the audit ledgered (#3610, #3611)#3621
os-zhuang merged 2 commits into
mainfrom
claude/screen-flow-submit-resume-v9dqjx

Conversation

@os-zhuang

Copy link
Copy Markdown
Contributor

Closes #3610, closes #3611 — the two mismatch rows the #3587 REST route ledger carried (PR #3609). Same reconcile-in-one-PR shape as #3592 did for the dispatcher's four.

#3610POST /api/v1/packages publish-vs-install collision (real bug)

Evidence assembled before changing anything:

  • service-package is the marketplace plugin in serve.ts's plugin table; its publish({manifest, metadata}) is marketplace-registry publishing — a different concept from install.
  • The dispatcher packages domain already does the full job on the bare path: install routes through protocol.installPackage (in-memory registry and durable sys_packages), DELETE routes through protocol.deletePackage (full uninstall, Package uninstall does not clean up data-plane permission rows by package_id (ADR-0086 D3 wiring gap) #2747).
  • REST registers first in the production stack (serve.ts order + first-match-wins routers), so when the package service resolves, client.packages.install's POST landed on the publish handler → 400 Missing required fields: manifest, metadata.
  • Repo-wide + objectui-wide + qa/examples sweeps found zero HTTP callers of the publish shape.

Fix: marketplace publish moves to POST /api/v1/packages/publish; the bare POST /packages now has exactly one owner (dispatcher install). The dispatcher's own POST /packages/:id/publish (ADR-0033 draft publish) is two segments — different shape, no clash, and package ids are dotted so a bare publish id is not plausible. The remaining REST GET /packages, GET /packages/:id, DELETE /packages/:id shadows are compatible and deliberately stay (list additionally merges published-but-not-installed packages from the database; scoped bases depend on them).

#3611 — UI view dialect split

meta.getView spoke the ?type= query dialect only the dispatcher /ui domain understands; the REST surface mounts only the path form /ui/view/:object/:type, so the query form 404'd wherever REST is the serving surface (e.g. project-scoped bases). The client now sends the path form both surfaces accept, with a URL-pinning test — no test locked this URL before, which is exactly how the split survived.

Ledger

rest-route-ledger.ts: the packages row becomes a server-only POST /packages/publish row (publisher tooling, not app-SDK surface); the ui row flips mismatchsdk (meta.getView). Zero mismatches remain in the REST ledger; the direct-mount conformance guard enforces the route move mechanically (the old bare-POST row would now fail both directions).

Verification

  • @objectstack/rest: 394/394 (conformance guard green on the moved route).
  • @objectstack/client: 130/130 (new getView URL-pinning test) + bare tsc -p clean.
  • Client-side ledger coverage now also proves meta.getView exists (flipped row).
  • Changeset: rest minor (fix!, route relocation with zero known callers, launch-window convention) + client patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LX9ut3MK3KykE11S9bJmv5


Generated by Claude Code

… ledgered (#3610, #3611)

#3610: the REST package registrar claimed the bare POST /packages for
marketplace publish ({manifest, metadata}) while the dispatcher packages
domain gives the same verb+path install semantics — and REST registers
first in the production stack (first-match-wins), so every
client.packages.install call landed on the publish handler and 400'd.
Marketplace publish moves to POST /api/v1/packages/publish (zero direct
callers found repo- and objectui-wide; the dispatcher's two-segment
POST /packages/:id/publish is a different shape, no clash). The remaining
REST GET/GET/DELETE shadows are compatible and stay: the dispatcher
already double-writes on install (protocol.installPackage) and fully
uninstalls on DELETE (protocol.deletePackage).

#3611: meta.getView spoke the ?type= query dialect only the dispatcher
/ui domain understands; REST mounts only the path form
/ui/view/:object/:type, so the query form 404'd wherever REST serves
(e.g. project-scoped bases). The client now sends the path form both
surfaces accept, with a URL-pinning test — no test locked this URL
before, which is exactly how the split survived.

REST route ledger: both mismatch rows resolved (packages publish row is
server-only publisher tooling; ui row flips to sdk). Zero mismatches
remain.

Closes #3610
Closes #3611

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LX9ut3MK3KykE11S9bJmv5
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
objectstack Ignored Ignored Jul 27, 2026 10:08am

Request Review

@github-actions github-actions Bot added documentation Improvements or additions to documentation tests tooling size/s labels Jul 27, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

This PR changes 2 package(s): @objectstack/client, @objectstack/rest.

18 hand-written doc(s) reference the affected code and may need an implementation-accuracy re-verification:

  • content/docs/ai/skills-reference.mdx (via packages/client)
  • content/docs/api/client-sdk.mdx (via @objectstack/client)
  • content/docs/api/data-flow.mdx (via @objectstack/client)
  • content/docs/api/environment-routing.mdx (via @objectstack/client)
  • content/docs/api/error-catalog.mdx (via @objectstack/client, @objectstack/rest)
  • content/docs/api/error-handling-server.mdx (via @objectstack/rest)
  • content/docs/api/index.mdx (via @objectstack/rest)
  • content/docs/getting-started/your-first-project.mdx (via @objectstack/client)
  • content/docs/kernel/runtime-services/data-service.mdx (via packages/client)
  • content/docs/kernel/runtime-services/index.mdx (via packages/client)
  • content/docs/permissions/authentication.mdx (via @objectstack/client)
  • content/docs/plugins/index.mdx (via @objectstack/rest)
  • content/docs/plugins/packages.mdx (via @objectstack/client, @objectstack/rest)
  • content/docs/protocol/kernel/i18n-standard.mdx (via packages/rest)
  • content/docs/protocol/kernel/realtime-protocol.mdx (via @objectstack/client)
  • content/docs/releases/implementation-status.mdx (via @objectstack/client, @objectstack/rest)
  • content/docs/releases/v12.mdx (via @objectstack/rest)
  • content/docs/releases/v16.mdx (via @objectstack/client)

Advisory only. To re-verify, run the docs-accuracy-audit workflow scoped to these files:
node scripts/docs-audit/affected-docs.mjs origin/main → pass the list as args.docs.

…h moved to /packages/publish

The doc described the pre-#3610 collision state: bare POST /packages as
marketplace publish. That path is install (409 duplicate guard, overwrite
opt-in); publish now lives at POST /packages/publish.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LX9ut3MK3KykE11S9bJmv5
@os-zhuang
os-zhuang marked this pull request as ready for review July 27, 2026 10:37
@os-zhuang
os-zhuang merged commit 16adb3c into main Jul 27, 2026
16 checks passed
@os-zhuang
os-zhuang deleted the claude/screen-flow-submit-resume-v9dqjx branch July 27, 2026 10:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tests tooling

Projects

None yet

2 participants