Skip to content

nav: local_planner_dead's "session-scoped" name rests on "exactly one fine worker per process", which nothing pins #787

Description

@djhenry

Raised as N1 in the round-6 review of #774 (#766). Not a defect today — the premise is true as of this writing, verified twice — but it is load-bearing prose with nothing underneath it, and its decay would be silent.

The premise

Exactly one fine steering worker (LocalPlanner) is constructed per client process.

Verified mechanically, by the reviewer and independently by me:

  • LocalPlanner::spawn is reached only via Walker::new;
  • the sole production Walker::new is in ActionLoop::new;
  • the sole production ActionLoop::new is in run_login_flow, inside the Ok(..) arm of the retry loop, which unconditionally return Ok(()) after run_gameplay_phase — and the slots are moved into it, so a second pass round that loop would not compile;
  • run_login_flow itself is called once, from ServerModel::run.

An unrelated comment in login.rs reaches the same conclusion for a different field ("no code path re-enters login after gameplay today").

Why it matters

NavStatus.local_planner_dead is latched and worker-scoped. The agent-facing documentation calls it session-scoped, and that name is defended as accurate precisely because the two spans coincide under this premise. At least four sentences rest on it directly:

where sentence
crates/eqoxide-ipc/src/lib.rs (field doc) "…exactly one fine worker exists per process and 'latched forever' and 'latched for this worker' coincide."
crates/eqoxide-ipc/src/lib.rs (field doc) "…which is why the agent-facing docs call the field session-scoped."
crates/eqoxide-http/src/observe.rs "…it reads as session-scoped from outside only because exactly one fine worker is built per process."
docs/http-api.md "…exactly one fine worker is built per client process, so from out here the two are the same span."

Several more ("this clear is a no-op in production", "on today's single-Walker process") depend on it more weakly.

Why it decays silently

There is no guard, no test and no E0027-style net over the single production Walker::new. The claim exists only as prose. The day an in-process relogin lands — which is the exact shape #774 hardened Walker::new against — those four sentences become false, the agent-facing name becomes wrong, and nothing in the tree goes red.

The obvious candidate is not one. a_new_walker_does_not_inherit_a_previous_workers_death_766 (eqoxide-nav) constructs a second Walker deliberately, over a deliberately dirty row. It cannot be the thing that fails when a second Walker appears in production, because building a second one is its whole method.

Suggested shape

The repo already uses source-scanning guards for premises of this kind (steering.rs's citation scan, slot.rs's two scans, action_loop.rs's include_str! of docs/http-api.md). The natural form here:

a scan asserting exactly one non-#[cfg(test)] Walker::new( call site in the tree, whose failure message names the four sentences above and says "the session-scoped name is now wrong; revisit them".

Two design notes for whoever picks this up:

  1. Scanning must exclude #[cfg(test)] regions, or the B9 test's own construction defeats it on day one.
  2. Per the guard reach lesson, whoever writes it should run it and show it going red on a planted second call site, not derive its reach by reading — a source scanner that silently stops short of its corpus looks identical to a passing one.

Not for #774

#774 is closed on this: it correctly declines to widen scope, and its round-6 decision to keep the "for the rest of the session" consequence statements rests on this premise being true today, which it is. This issue exists so the premise does not evaporate when it stops being true.

Metadata

Metadata

Assignees

No one assigned

    Labels

    agent-honestyClient reports success or state that is false — a lie an agent cannot detectseverity:lowLow severity

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions