Commit e0733ce
committed
fix(plugin-sharing)!: the share-link routes emit the declared envelope, and the last ratchet retires (#3983)
The fifth and final drifting route module. Unlike the four in #3843 this one was
not found by reading — `scripts/check-route-envelope.mjs` surfaced it the moment
that scan went repo-wide, which is the argument for a repo-wide guard over
per-package copies. It also turned out to be the one where the drift had broken
shipped SDK methods, not merely mis-shaped a body.
Three of these routes are `disposition: 'sdk'` in `runtime/src/route-ledger.ts`,
and `unwrapResponse` decides a body is an envelope by finding a boolean
`success`. With no flag it returns the body verbatim, so against this surface
`shareLinks.create()` — documented "Returns the link row (incl. token)" — handed
back `{ link: … }` and `.token` was undefined, while `shareLinks.list()`, typed
`Promise<any[]>`, handed back `{ links: [] }` and any `.map()` on it threw.
`packages/client/src/admin-surfaces.test.ts` mocks all three as
`{ success: true, data: <payload> }`: the SDK was written and tested against the
DISPATCHER's shape and only ever worked there.
So the target shape was not a design decision. `runtime/src/domains/share-links.ts`
serves these same five paths — for cloud's per-environment kernels it is the
designed PRIMARY surface — and has always answered in the declared envelope with
`data` carrying the payload directly. This module now answers identically, which
is what makes `unwrapResponse` return the same value either way:
POST /share-links { link } -> data: link
GET /share-links { links } -> data: link[]
DELETE /share-links/:id { ok: true } -> data: { ok: true }
GET /:token/resolve { record, link, redact… } -> data: { … }
GET /:token/messages { data: rows } -> data: rows
errors { error: { code, msg } } -> + success: false
`{ ok: true }` survives on revoke, but as the payload rather than as the body: at
the top level it was a second word for `success` (#3689 retired that from
storage); under `data` it is what the dispatcher already returned. The error half
was already nested `{ code, message }` — #3675's changeset cited this module as
the good example — so only the flag is new there, and all eleven codes were
already SCREAMING_SNAKE and registered, so ADR-0112 needs nothing.
Consumers swept: the framework has ZERO. In objectui, ShareDialog was already
dual-shape tolerant on all three routes it calls, and carried that tolerance
precisely BECAUSE both shapes existed in the fleet. SharedRecordPage needed one
fix of the kind a shape-swap would have missed — it renamed the wire's
`redactFields` to `redactedFields` only on the bare branch, so on the enveloped
dispatcher path the "fields are hidden by the owner" notice never rendered.
Converting this surface would have spread that to every share page; fixed in
objectui#2980, which merges first.
The module had no test file at all (only `share-link-service.test.ts`), so it
gains a driven conformance suite: 26 cases over all five routes and thirteen
error branches, every body parsed against the real spec schemas, plus the
`unwrapResponse` decision restated so the two broken SDK methods are pinned as
working. Reverting the two emitters fails 22 of the 26.
Guard: 7 conformant / 0 ratcheted / 1 exempt, from 6 / 1 / 1. `privateOk` is also
narrowed to what its doc always claimed — a literal `ok` at the TOP of a body,
where it competes with `success`; the same literal inside `data` is payload, which
is what a conformant revoke returns. Four self-test assertions pin both readings.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CYbS3kS8xzsHNXFTzp4e2z1 parent c35cfdb commit e0733ce
4 files changed
Lines changed: 710 additions & 43 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
0 commit comments