fix: bind omp lifecycle reports to the pane's agent process - #3026
fix: bind omp lifecycle reports to the pane's agent process#3026caner-akca wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Greptile SummaryThe PR binds Oh My Pi lifecycle authority to the reporting process, makes standalone agent waits return freshly probed state, and avoids publishing idle for turns with scheduled continuations.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains.
|
| Filename | Overview |
|---|---|
| src/ipc.rs | Adds platform-specific retrieval of the connected local client's process ID. |
| src/api/server.rs | Captures peer identity before reading the request and stamps it only onto lifecycle-report methods. |
| src/terminal/state.rs | Stores and enforces the OMP reporter lease on hook authority, with focused teardown and replacement coverage. |
| src/api/wait.rs | Removes stale event-status substitution and returns status only from a current probe, except for the existing release-final-status path. |
| src/integration/assets/omp/herdr-agent-state.ts | Suppresses idle reporting for intermediate ends that have an automatic continuation scheduled. |
| tests/cli/agent_wait.rs | Adds an end-to-end regression test proving a transient idle event does not complete a wait whose current state is working. |
Sequence Diagram
sequenceDiagram
participant OMP as OMP process
participant API as Local API server
participant App as App event handling
participant State as TerminalState
participant Wait as agent wait
OMP->>API: pane.report_agent / session
API->>API: Read kernel peer PID
API->>App: Stamped lifecycle report
App->>State: Apply report with reporter PID
alt Same process or no live lease
State->>State: Update lifecycle authority
State-->>Wait: Publish status event
Wait->>State: Probe current agent state
State-->>Wait: Fresh snapshot
else Foreign process while lease is live
State->>State: Reject report
end
Reviews (2): Last reviewed commit: "fix: bind omp lifecycle reports to the p..." | Re-trigger Greptile
A nested Oh My Pi session inherits the pane's herdr environment, so its extension reported as the pane's agent and re-anchored lifecycle authority at its own session. When the nested session finished, the pane read idle while its own agent was still mid-turn, and `agent wait` returned that. The server now reads the connected peer's process id from the kernel and stamps it onto lifecycle reports, so it can never be supplied by a payload. A leased reporter source claims the pane with its authority, and reports from any other process are refused for as long as that authority is live. The lease is stored on the authority record, so it is released exactly when the authority is and a restarted agent is never gated by its predecessor. Only omp is leased: its extension runs in-process and reuses that process for every report. Shell-asset integrations report from a new process each time and keep the previous first-writer behavior. Standalone `agent wait` no longer substitutes a status observed in an event into a later snapshot. That returned a status the same snapshot could already contradict, leaving callers no way to detect the bad result. The omp hook also treated every non-retryable `agent_end` as idle. Upstream marks an end that has already scheduled a continuation with `willContinue`, so those no longer settle the pane. refs herdrdev#2851
d6bcd75 to
eceda2b
Compare
|
thanks for investigating. the pid lease is too large for this issue, and |
Fixes the three defects reported in #2851.
The takeover
The Oh My Pi extension enables itself from the inherited pane environment, so a nested OMP session started inside a pane reported as that pane's agent. Its session claim replaced the live one, authority re-anchored to the child, and when the child finished the pane read idle while its own agent was still mid-turn.
agent waitreturned that idle, and the parent's later reports were then rejected as stale, so polling never recovered.Reports carry no trustworthy owner, so the server now takes one from the kernel.
src/ipc.rsreads the connected peer's process id —LOCAL_PEERPIDon macOS,SO_PEERCREDon Linux,GetNamedPipeClientProcessIdon Windows — andsrc/api/server.rsstamps it ontopane.report_agent/pane.report_agent_session. The field is#[serde(skip)] #[schemars(skip)], following the existingownerprecedent, so it can never come from a payload and the JSON schema is unchanged.The peer id must be read while the connection is fresh: Darwin invalidates it once the peer closes, and lifecycle reporters open one short-lived connection per report.
TerminalStatestores that id onHookAuthority. A report for a leased source from any other process is refused while that authority is live. Keeping the lease on the authority record means it is released exactly when the authority is, so a restarted agent is never gated by its predecessor's process id.Only
herdr:ompis leased. Its extension runs inside the OMP process and reuses it for every report, which is what makes process identity meaningful. Shell-asset integrations report from a new process each time and keep the previous first-writer behavior.Identity decides alone — the session ref is deliberately not consulted, because a nested reporter can read and replay the pane's published ref, which would itself be a takeover route.
This is an accidental-cross-talk boundary, not a security boundary: process ids are reusable and Windows' client id can be misreported. Herdr's socket is same-user and mode 0600, so this guards against unrelated processes, not an attacker already running as the user.
The wait
Standalone
agent waitremembered a status seen in an event and pasted it over a freshly probed snapshot, returning a currentstate_change_seqwith a stale status — a result the caller had no field left to detect. The substitution is removed; the wait still wakes on every status event but reports only what a live probe observed.agent prompt --waitis unaffected; it already ran this way.The hook
Every non-retryable
agent_endscheduled idle, including intermediate loop ends. Upstream marks an end that has already queued a continuation withwillContinue, so those now return early. The field is optional, so=== truedegrades to existing behavior on older builds.OMP_INTEGRATION_VERSION8 -> 9.Testing
just cipasses on this base. Twolive_handofftests fail in my environment for want of an agent binary onPATH; I confirmed they fail identically on a pristine checkout of the same base.TerminalStateunit tests for the lease (foreign reporter refused through session claims, bare state reports, replayed session refs; lease released on every authority teardown and on agent change; non-leased sources keep first-writer replacement), a CLI test that a transient blip does not complete a wait, and a bun test thatwillContinuesuppresses idle while a real terminal end still settles the pane.startupplus idle against a live parent no longer ends the parent's wait. I also confirmed the guard is what does the work by temporarily disabling the leased-source predicate and watching the failure return.Scope
This closes the nested-session takeover and the two wait/hook defects. It does not attempt general reporter authentication for unrelated processes beyond the lease described above.