Summary
Avoid repeated observe() / unobserve() churn when multiple framework hooks mount against the shared global context.
Why
Today useAskable() in React and Vue calls ctx.observe(document, ...) on mount for the shared singleton context. Since Observer.observe() unconditionally calls unobserve() when a root is already active, multiple hook mounts can trigger:
- full re-scan of
[data-askable] elements
- detach + reattach of listeners across the page
- unnecessary MutationObserver teardown / recreation
This is especially likely in apps that:
- call
useAskable() from several components
- mount the inspector alongside consumer hooks
- have multiple AI surfaces reading from the same context
The core benchmarks still pass, but this is avoidable runtime churn and likely the biggest practical performance footgun in the current adapter design.
Proposed direction
Introduce idempotent observation for shared contexts.
Options:
-
Internal reference-counted ensureObserved()
- first hook mount observes the document
- subsequent mounts only subscribe to focus state
- final unmount tears observation down
-
Provider/root component API
<AskableProvider> / <AskableRoot> owns observation once
- hooks become pure consumers of the existing context
Acceptance criteria
Notes
This issue complements, but is separate from, larger context-shaping work like #145 and #121.
Summary
Avoid repeated
observe()/unobserve()churn when multiple framework hooks mount against the shared global context.Why
Today
useAskable()in React and Vue callsctx.observe(document, ...)on mount for the shared singleton context. SinceObserver.observe()unconditionally callsunobserve()when a root is already active, multiple hook mounts can trigger:[data-askable]elementsThis is especially likely in apps that:
useAskable()from several componentsThe core benchmarks still pass, but this is avoidable runtime churn and likely the biggest practical performance footgun in the current adapter design.
Proposed direction
Introduce idempotent observation for shared contexts.
Options:
Internal reference-counted
ensureObserved()Provider/root component API
<AskableProvider>/<AskableRoot>owns observation onceAcceptance criteria
useAskable()mounts do not trigger full re-observation churnNotes
This issue complements, but is separate from, larger context-shaping work like #145 and #121.