fix(acp): address Codex review — strict ctx.get, correct fiber-ownership doc + test
- AgentLoop.resume uses `this.ctx.get('sessionPersistence')` (strict) instead
of the `, false` overload: still topology-independent, but an inactive/
absent backend reads as undefined (rejected by the existing guard) rather
than being handed back mid-teardown.
- Correct the bridge teardown comment: an ACP-created agent's registry entry
binds to the BRIDGE fiber (the factory is reached through the bridge's
traceable proxy, so AgentLoop.start's `this.ctx.effect` registration uses the
caller context), not the AgentLoop fiber — so an ACP-only HMR dispose
reclaims it. Add a regression test pinning that ownership.
- Sync the ctx.get guidance in the post-mortem, packages/AGENTS.md, and the
dsh-code-review skill to the strict form.
This commit is contained in:
6 files changed
+53
-27
No files matched your search
@@ -152,20 +152,22 @@ export class AgentLoop extends Service implements AgentFactory {
|
||||
* by the time this runs the service exists.
|
||||
*/
|
||||
async resume(options: ResumeAgentOptions): Promise<Agent> {
|
||||
// Read the service through `ctx.get(name, false)` — a direct global-store
|
||||
// lookup keyed by the isolate symbol — NOT `this.ctx.sessionPersistence`.
|
||||
// AgentLoop deliberately does NOT inject `sessionPersistence` (injecting it
|
||||
// would pend non-persistent demos forever). The property proxy resolves a
|
||||
// service by walking the current fiber's parent chain; from AgentLoop's own
|
||||
// fiber (which lacks the inject) that walk never reaches the sibling backend
|
||||
// fiber and throws "cannot get property … without inject". Worse, when the
|
||||
// call arrives via a traceable shadow (e.g. the ACP bridge child fiber →
|
||||
// `ctx.agents.resume()` → `this.factory.resume()`), the walk starts at the
|
||||
// SHADOW's root fiber and fails the same way. `ctx.get(…, false)` sidesteps
|
||||
// the fiber walk entirely (the same bypass the proxy itself takes when
|
||||
// `!ctx.fiber.runtime`), so resume works from any caller fiber. `false`
|
||||
// skips the ACTIVE-state check, since the backend lives on another fiber.
|
||||
const persistence = this.ctx.get('sessionPersistence', false)
|
||||
// Read the service through `ctx.get('sessionPersistence')` — a direct
|
||||
// global-store lookup keyed by the isolate symbol — NOT
|
||||
// `this.ctx.sessionPersistence`. AgentLoop deliberately does NOT inject
|
||||
// `sessionPersistence` (injecting it would pend non-persistent demos
|
||||
// forever). The `ctx.<name>` property proxy resolves a service by an
|
||||
// ancestor-only walk of the current fiber's parent chain; from AgentLoop's
|
||||
// own fiber (which lacks the inject) that walk never reaches the sibling
|
||||
// backend fiber and throws "cannot get property … without inject". Worse,
|
||||
// when the call arrives via a traceable shadow (e.g. the ACP bridge child
|
||||
// fiber → `ctx.agents.resume()` → `this.factory.resume()`), the walk starts
|
||||
// at the shadow's origin fiber and fails the same way. `ctx.get(name)`
|
||||
// sidesteps the fiber walk entirely (a store lookup by the global isolate
|
||||
// key), so resume works from any caller fiber. It is strict by default: a
|
||||
// backend that is not ACTIVE (absent, or mid-teardown) reads as undefined
|
||||
// and we reject below, rather than handing back an unusable handle.
|
||||
const persistence = this.ctx.get('sessionPersistence')
|
||||
if (persistence === undefined) {
|
||||
throw new Error('cannot resume: session persistence is not configured (load a dsh-session-persistence backend)')
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user