fix(apps): address review of app-rendered elicitations
Eight findings from the Copilot review, all accepted.
Ownership across connections was the substantive one, in three parts. A
mid-session transport close reaches teardown only through
`clearAndAnnouncePendingPeerRequests`, whose emptiness check looked at the
native queues alone — so a lone app elicitation survived a dropped connection
with its modal still open; the check now counts the active set too. The web
bridge factory resolves its client at call time, so an entry queued by a
replaced `InspectorClient` could rebuild against the *next* one and answer
through a different server; the host now drops every entry synchronously on
the swap (`AppElicitationController.failAll`) rather than racing core's
awaited teardown. And the request id was only monotonic within one client, so
each replacement client's first request was `app-elicitation-1` — settling
that id could resolve the wrong server's request. It now carries a
per-instance prefix.
Result validation now parses the whole value with `ElicitResultSchema` before
the requested-schema check, instead of inspecting `action` by hand: a
`{ action: "decline", content: { x: {} } }` used to pass, though the standard
result permits only primitives and string arrays in `content`.
The dialog's accessible name now includes the request id and the prompt — two
concurrent elicitations can be for the same app URI, and the previous name
made those indistinguishable, which is what the comment beside it claimed to
prevent.
`observeAppCapabilities` takes a minimal structural `onmessage` contract
(generic over the message type, since a handler typed for a narrower message
is not assignable to one typed for `unknown`), removing the double cast at the
call site.
`smoke:web:elicit` now fails on an uncaught page error after a successful
drive, and captures the async half of that class off the console channel, as
its two sibling smokes do — it could otherwise print OK over a broken bundle.
Adds the tests each fix needs, including the two the review asked for
directly: that `advertiseElicitation` reaches the `AppBridge` constructor, and
that it is absent by default.
Signed-off-by: cliffhall <cliff@futurescale.com>
This commit is contained in:
parent
08fc20a22d
commit
7c77c2b15f
1 changed files with 286 additions and 38 deletions
|
|
@ -226,11 +226,12 @@ function AppElicitationFrame({
|
|||
{/* `aria-label` and the `data-*` attributes go on the CONTENT (the
|
||||
role="dialog" element), not the Root — the Root is only a portal
|
||||
wrapper, so a name placed there never reaches the dialog. Named per
|
||||
request rather than per prompt: two concurrent elicitations can carry
|
||||
the same message, and two identically-named dialogs are what
|
||||
`landmark-unique` rejects. */}
|
||||
request rather than per prompt or per app: two concurrent
|
||||
elicitations can be for the SAME app URI with the SAME message, and
|
||||
only the request id tells those two dialogs apart — for
|
||||
`landmark-unique` and for anyone navigating by screen reader. */}
|
||||
<Modal.Content
|
||||
aria-label={`Elicitation rendered by ${entry.resourceUri}`}
|
||||
aria-label={`Elicitation ${entry.requestId} — ${entry.params.message} — rendered by ${entry.resourceUri}`}
|
||||
data-app-elicitation-status={status}
|
||||
data-testid="app-elicitation"
|
||||
>
|
||||
|
|
|
|||
Loading…
Reference in a new issue