Problem
A Pylon server can host multiple Prime provider instances, but public SDK recovery currently derives an owned session's launchEnv from ambient process.env during attach. Initial workers inherit the caller-scoped daemon environment; recovered workers can instead receive the Pylon host process environment. Two instances in one Node process can therefore recover with the same or wrong Prime home, PATH, API keys, or credential overrides.
The current SDK also lets DaemonAgentConnection.dispose() swallow complete_owned_session failure, so a caller cannot prove that its owned worker was completed before tearing down or replacing an instance.
Required public SDK contract
- Add an opt-in, caller-supplied, defensively cloned
ownedSessionLaunchEnv snapshot. Capture it once for stock client-owned connections and use that exact snapshot for initial attach, direct-connect fallback, reattach, worker recovery, and daemon/supervisor replacement instead of later ambient process.env.
- In opted-in mode, launch workers with that exact snapshot plus only documented Prime-owned bootstrap keys. Keep the environment transient. Do not persist, fingerprint, log, or expose it in descriptors, owner registries, snapshots, events, proofs, results, or errors.
- Freeze the public SDK feature token as
caller_owned_session_environment_cleanup_v1. Callers must require this root token, the server's negotiated offer, and a current successful post-attach proof before relying on the contract.
- Expose
getOwnedSessionContractProof() as a safe current-attach proof. It may contain protocol/schema/app/build and supervisor/local-transport generations, but never raw hello data, owner/session tokens, PIDs, sockets, paths, environment values, or secrets. Invalidate it on disconnect or replacement and republish it only after a new successful owned attach.
- Preserve owner scoping. A caller must never complete or recover another owner's worker.
- Add single-flight
disposeOwnedSession() with bounded, fixed, secret-free outcomes for completed, already completed, owner mismatch, active/stopping timeout with uncertain cleanup, transport failure, unsupported peers, and replacement-settled only when settlement is tied to this connection's prior successful owned-attach proof and opaque session identity. Proving historical ownership from an arbitrary replacement client would require a durable owner-scoped receipt and is out of scope.
- Keep existing
dispose(): Promise<void> as legacy best-effort compatibility. Do not advertise the frozen token when the caller did not opt in or the complete proof cannot be made.
The existing daemon wire already carries launchEnv; this should remain a focused public-client contract rather than a daemon redesign.
Acceptance coverage
- Create two connections in one Node process with disjoint environment sentinels A/B.
- Prove exact isolation on initial attach, worker crash/recovery, daemon reconnect, and daemon replacement.
- Change ambient
process.env to a third sentinel and prove it reaches neither recovered worker.
- Prove launch values never appear in descriptors, owner state, snapshots, logs, events, or error text.
- Prove wrong owners cannot complete or recover a worker.
- Prove strict cleanup outcomes across success, already-complete, timeout/uncertain transport, replacement, and owner mismatch.
- Preserve compatibility for callers that do not opt into the new contract, but do not advertise the frozen capability in that mode.
Scope
This issue owns the Prime public SDK isolation/cleanup primitive only. Pylon home resolution, provider cache fencing, UI, resource budgets, and multi-instance enablement belong in a separate Pylon issue. It is independent of Prime #20 and Comet.
Problem
A Pylon server can host multiple Prime provider instances, but public SDK recovery currently derives an owned session's
launchEnvfrom ambientprocess.envduring attach. Initial workers inherit the caller-scoped daemon environment; recovered workers can instead receive the Pylon host process environment. Two instances in one Node process can therefore recover with the same or wrong Prime home, PATH, API keys, or credential overrides.The current SDK also lets
DaemonAgentConnection.dispose()swallowcomplete_owned_sessionfailure, so a caller cannot prove that its owned worker was completed before tearing down or replacing an instance.Required public SDK contract
ownedSessionLaunchEnvsnapshot. Capture it once for stock client-owned connections and use that exact snapshot for initial attach, direct-connect fallback, reattach, worker recovery, and daemon/supervisor replacement instead of later ambientprocess.env.caller_owned_session_environment_cleanup_v1. Callers must require this root token, the server's negotiated offer, and a current successful post-attach proof before relying on the contract.getOwnedSessionContractProof()as a safe current-attach proof. It may contain protocol/schema/app/build and supervisor/local-transport generations, but never raw hello data, owner/session tokens, PIDs, sockets, paths, environment values, or secrets. Invalidate it on disconnect or replacement and republish it only after a new successful owned attach.disposeOwnedSession()with bounded, fixed, secret-free outcomes for completed, already completed, owner mismatch, active/stopping timeout with uncertain cleanup, transport failure, unsupported peers, and replacement-settled only when settlement is tied to this connection's prior successful owned-attach proof and opaque session identity. Proving historical ownership from an arbitrary replacement client would require a durable owner-scoped receipt and is out of scope.dispose(): Promise<void>as legacy best-effort compatibility. Do not advertise the frozen token when the caller did not opt in or the complete proof cannot be made.The existing daemon wire already carries
launchEnv; this should remain a focused public-client contract rather than a daemon redesign.Acceptance coverage
process.envto a third sentinel and prove it reaches neither recovered worker.Scope
This issue owns the Prime public SDK isolation/cleanup primitive only. Pylon home resolution, provider cache fencing, UI, resource budgets, and multi-instance enablement belong in a separate Pylon issue. It is independent of Prime #20 and Comet.