mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
feat(coding-agent): preserve handles across facet reloads
This commit is contained in:
parent
75223072b8
commit
6f0ea81e8b
12 changed files with 496 additions and 63 deletions
|
|
@ -519,7 +519,7 @@ Required behavior:
|
|||
3. **Hydration** installs a complete snapshot atomically before updates flow. Subscribing before hydration is valid, and updates emitted concurrently with the snapshot are buffered, so the listener observes snapshot then updates with no gap.
|
||||
4. Once hydrated, `.value` is synchronously readable and `subscribe()` immediately reports the current value, then future updates. The first snapshot callback uses a fresh **hydration context** parented to the subscription; an immediate callback for an already-present value uses a fresh local delivery context because the write that produced it may be long settled.
|
||||
5. State values are borrowed immutable JSON. The state runtime does not defensively clone reads, writes, snapshots, or listener deliveries. Callers transfer ownership to `set()` and must not mutate or retain values returned by `.value` or passed to listeners; copy explicitly when ownership is required. Process and transport serialization may naturally produce a detached value, but callers must not depend on object identity or detachment.
|
||||
6. Disconnect may retain the last value as stale display data alongside connection or attachment state. Reconnecting to the same provider replaces it with a fresh snapshot. Switching to a different provider or host generation clears readiness and `.value` becomes `undefined` until that provider hydrates; service-bound presentation resources are disposed as part of the switch.
|
||||
6. Disconnect may retain the last value as stale display data alongside connection or attachment state. Reconnecting to the same provider replaces it with a fresh snapshot. Reloading a singleton provider installs its complete replacement snapshot in the existing member facade. Switching routes to a different provider clears readiness and `.value` becomes `undefined` until that provider hydrates; route-bound presentation resources are disposed as part of the switch.
|
||||
7. `set(value, context)` carries source trace metadata; each live delivery invokes listeners with a reconstructed delivery `Context`. Background updates use an intentional background or lifecycle context, never a retained caller context.
|
||||
|
||||
Anything a consumer must recover after reconnect is exposed as replicated state or pulled through a remote method. Replicated state is latest-value replication, not by itself durable session storage; the providing facet must reconstruct its authoritative value after a worker restart.
|
||||
|
|
@ -983,9 +983,9 @@ The memo has the existing invocation lifetime. Staging the tool result as `outco
|
|||
|
||||
Every facet-owned resource — singleton registrations, still-open service instances, contributions, state subscriptions, watchers, timers, in-flight RPCs, subprocesses, overlays — is owned by the facet environment and disposed when that environment closes, in reverse dependency order. Host capabilities enforce this automatically for hooks and event subscriptions; `onDeactivate` handles the rest. Contribution registries rebuild from the remaining ordered contributions instead of asking a plugin to reverse shared mutations.
|
||||
|
||||
Source reload does not replace one environment or service in place. One user-triggered `/reload` selects a new complete manifest generation for server, Session, and presentation hosts. Each host closes its old facet set through ordinary shutdown, reconstructs runtime state from durable authority, and rebinds services from fresh snapshots. Hosts may temporarily run different generations; contracts must remain forward compatible during convergence.
|
||||
Source reload replaces the affected facet environments while retaining unaffected consumers. The host stages each replacement against the existing dependency graph, disconnects its old provisions, deactivates the old facet, activates the replacement, and rebinds its provisions before unloading the old module generation. A singleton facade returned earlier by `use()` keeps its identity: local calls resolve the current implementation, and RPC consumers receive a complete replacement snapshot on the existing subscription. Reloads that change service requirements, provisions, modes, or manifest membership require graph reassembly before they can switch.
|
||||
|
||||
Reload has no safety or rollback guarantee beyond normal shutdown and restart. Committed durable state survives, removed plugin data is retained, interrupted calls are not automatically replayed, and non-restartable process effects may fail. See [`plugin-reloading.md`](plugin-reloading.md) for the complete design.
|
||||
Reload has no safety or rollback guarantee beyond ordinary facet shutdown and activation. Committed durable state survives, removed plugin data is retained, interrupted calls are not automatically replayed, and non-restartable process effects may fail. Hosts may temporarily run different source generations, so contracts remain forward compatible during convergence. See [`plugin-reloading.md`](plugin-reloading.md) for the complete design.
|
||||
|
||||
## Connection loss, errors, and security
|
||||
|
||||
|
|
@ -1039,7 +1039,7 @@ The handoff should include a reusable two-transport test matrix (loopback plus a
|
|||
- **Registries:** ordered provider contributions rebuild deterministically; tool wrappers compose once and rebuild correctly after removal.
|
||||
- **Presentation:** typed selections return values rather than labels; modal leases do not interleave multi-step dialogs; closing a queued instance removes it before display; closing an active instance aborts and dismisses only that dialog; non-cancellation observer failures reach host failure policy.
|
||||
- **Routing:** attach authorizes at the server and rejects cross-workspace targets; attach/switch closes previous routed requests and instance tasks, then hydrates the selected session; a routed singleton or instance call reconstructs `Context` at the session worker, with cancellation and trace carriers traversing the server; stale instance generations are rejected; per-client keying prevents request-ID collisions; the server routes services whose contracts it does not load; session-worker failure leaves server services healthy and updates directory status; presentation disconnect cleanup reaches the session; summaries contain no `ownerId` or `cwd`.
|
||||
- **Reload:** one `/reload` selects one desired manifest generation for every facet kind; old Session ownership closes before replacement; logical selection survives a route gap and receives a fresh attachment ID; old calls and frames are fenced; state rehydrates from authoritative snapshots; events are not replayed; interrupted mutations are not retried; removed plugin data is retained; temporary generation skew remains compatible; and failed replacement stays degraded without rollback.
|
||||
- **Reload:** changed facet implementations replace their matching active facets while stable service facades rebind to new local implementations or RPC singleton snapshots; structural graph changes reassemble the affected host; old Session ownership closes before worker replacement; logical selection survives a route gap and receives a fresh attachment ID; old calls and frames are fenced; events are not replayed; interrupted mutations are not retried; removed plugin data is retained; temporary generation skew remains compatible; and failed replacement stays degraded without rollback.
|
||||
- **Boundaries:** scoped agent and fleet capabilities cannot reach host ownership or whole-registry mutation; raw Harness/Session/SessionRepo capabilities unreachable from any client connection; job `wait` cancellation distinct from `job.cancel()`; stale/closed reference rejection; concurrent question invocations add distinct services visible in simultaneous TUI and web clients, survive having no connected presentation while the worker is live, disappear on worker loss, reappear under new generations when safe replay finds no answer memo, accept only one durable answer each, reject the tool wait rather than hang when the memo write fails, return committed answers without adding another instance on replay, clean up with durable tool-result staging, and close in every presentation; invocation cancellation writes no durable cancellation state.
|
||||
|
||||
## Collaborative diff review: a durable shared sidebar
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue