A business package imported the Remote assembly for `ctx.remote` and the
Connection plugin for the wire types it passes around. The assembly now
re-exports the carrier's Client-facing types, so a business package names one
package. The re-export is type-only: the carrier's runtime values keep their
own module edge, since inlining them here would duplicate the carrier inside
the assembly bundle.
Four surfaces that had no Remote assembly dependency declare one now.
Review follow-ups on the presentation intent.
The card claimed any single-question request declaring the intent, then sent one
of two labels — so a producer offering a third option, or a multi-select batch,
lost answers the generic flow would have shown. That contradicts the intent's
own contract, so `planReviewOf` now claims only a binary single choice and
leaves everything else to the flow that can express it.
`ask()` also rejects a plan-review intent on a question with no `detail`: the
intent declares detail IS the plan, and without one a honouring UI asks the
user to approve something invisible. The client keeps its own fallback — it sits
downstream of a wire boundary — but the misconfiguration now fails at the asker.
`planReviewOf` stops being a value export of the client contract face (client
export discipline: pure helpers stay internal; the tests already import it
relatively), and the ui-question README fallback list, both languages, now
states every condition the code enforces.
The Web composer now renders a request that declares the `plan-review` intent
as its own surface: the waiting-approval card language — amber "Plan review"
strip, the plan as the scrolling markdown body, the question as the card's
accessible name — over one decision row of Chat about it / Refuse / Approve.
Gone from that surface are the 1/1 pager, the numbered radio rows, the custom
answer row, and Skip/Submit, which made approving a plan read as sitting an
exam.
Approve and Refuse answer with the asker's own option labels and keep its
descriptions as tooltips; Chat about it cancels the request so the composer
returns and the user can simply say what they want. Copy is bilingual under the
existing `question` namespace.
The shape choice lives inside the single composer entry rather than a second
chain registration, so the two surfaces cannot race the same carrier, and
`planReviewOf` falls back to the generic flow for any request it cannot render
as a card — the client sits downstream of a wire boundary and every request
must stay answerable.