Skip to content

feat(pi): publish observed harness state from the injected extension - #323

Merged
schickling-assistant merged 8 commits into
schickling/hs-04-rosterfrom
schickling/hs-05-pi
Aug 24, 2026
Merged

feat(pi): publish observed harness state from the injected extension#323
schickling-assistant merged 8 commits into
schickling/hs-04-rosterfrom
schickling/hs-05-pi

Conversation

@schickling

@schickling schickling commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

The pi producer — the first evented observed-state signal (the stronger signal DQ2 asks for), built on decision 0005's injected extension.

  • hooks/pi-channel.ts emits typed NDJSON state frames on pi's turn boundaries, with the idle edge on agent_settled — measured against the repo's own 2026-08-18 captures: ctx.isIdle() is still false through agent_end, and a queued follow-up turn starts exactly at that boundary, so an agent_end idle emit would publish a spurious idle blip. Frames drop silently with no channel (fail-open).

  • Ownership splits by phase: the channel owns the live record (it alone sees turn events; its stdio EOF bounds its evidence — heartbeats stop on EOF and the record ages out), the wrapper owns the terminal record with the real exit status. The channel drops queued live frames only against a terminal record its own session wrote — the incarnation's last word stands, while a predecessor's ended never silences a restarted seat.

  • ptySession is the wrapper's runtime/task ID (ST2_PI_CHANNEL_RUNTIME_ID), the actual pty registry key — hand-authored seats with custom task IDs probe correctly.

  • run_provider_observed returns a ProviderOutcome so the wrapper can record how a session ended before judging the exit.

  • pi 0.84.2 exposes no waiting-on-a-human event, so pi never sets blockedOn: human — and therefore no ask kind — in v1; documented limit. checks.pi-extension-types stays green against the pinned release.

  • Cycle-2: a fresh channel is a new session — it starts interrupted, so its first frame opens a fresh transition instead of claiming continuity across the restart.

  • Cycle-3: the wrapper mints the session token (exported as ST2_PI_CHANNEL_SESSION) and passes a terminal-only observer, so the stop path's pre-escalation ended write is real for pi; the extension attaches a stream-level stdin error listener so an EPIPE from a retiring channel can never take pi down.

  • Cycle-4: the extension stashes and unexports every ST2_PI_CHANNEL_* value (runtime id + ownership pair included), handing them only to the channel subprocess; the wrapper claims and exports the ownership sequence beside its token.

  • Cycle-6 (P1): the cycle-5 bounded-await landed as a use-before-declaration — a TDZ ReferenceError on every channel open, so no managed pi seat got a channel — and the type gate shipped it green. The declaration is hoisted, and the gate now transpiles and runtime-smokes the shipped asset (registration, double session_start, turn events, shutdown), with an injected-TDZ negative test proving the gate can fail.

Part of the #268 stack (#319#326).

🤖 Generated with Claude Code

@schickling schickling changed the title schickling/hs 05 pi feat(pi): publish observed harness state from the injected extension Aug 23, 2026
@schickling
schickling marked this pull request as ready for review August 23, 2026 18:18

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 97aaa9c535

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/pi_session.rs Outdated
Comment thread src/pi_channel.rs Outdated
@schickling
schickling force-pushed the schickling/hs-05-pi branch from 97aaa9c to 43f5213 Compare August 23, 2026 19:23

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 43f5213560

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/pi_channel.rs
@schickling
schickling force-pushed the schickling/hs-05-pi branch from 43f5213 to 199fb59 Compare August 23, 2026 21:47

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 199fb594f5

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/provider_session.rs
Comment thread hooks/pi-channel.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: c2dde7ff52

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/pi_session.rs
@schickling
schickling force-pushed the schickling/hs-05-pi branch from c2dde7f to 8a7f2a1 Compare August 23, 2026 23:01

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 8a7f2a195b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/provider_session.rs
Comment thread hooks/pi-channel.ts
@schickling
schickling force-pushed the schickling/hs-05-pi branch from 8a7f2a1 to b60cdc9 Compare August 23, 2026 23:35

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b60cdc977f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread hooks/pi-channel.ts
@schickling
schickling force-pushed the schickling/hs-05-pi branch from b60cdc9 to 9a5f8c5 Compare August 24, 2026 00:04

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a5f8c5930

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/provider_session.rs
@schickling
schickling force-pushed the schickling/hs-05-pi branch from 9a5f8c5 to 3e1f2e3 Compare August 24, 2026 00:37

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3e1f2e3dc6

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/pi_session.rs
@schickling
schickling force-pushed the schickling/hs-05-pi branch from 3e1f2e3 to 41708c0 Compare August 24, 2026 04:30

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 41708c0ca2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/pi_session.rs
let session = harness_state::session_token();
// The claim is written: it supersedes whatever the predecessor left — including a
// still-fresh live record — before the channel or terminal writer act under it.
let seq = harness_state::claim(&agent_dir, identity.clone(), "pi", &session)?;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid publishing a terminal claim before pi is observed

When pi launches but its extension fails open—for example because ctx.isIdle is unavailable, the channel subprocess cannot start, or the protocol is rejected—nothing replaces this claim while the provider remains alive. harness_state::claim writes a fresh Ended record with reason superseded, and terminal records bypass the PTY liveness check, so roster and doctor consumers falsely report the running seat as ended for the 15-minute freshness horizon. Keep the takeover fence from being exposed as a definite terminal observation until the channel publishes state or the wrapper observes an actual exit.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 4a07c90 on schickling/hs-01-envelope (owning layer): readers derive indeterminate with the distinct reason 'claimed' from a fresh exitless superseded record -- the takeover placeholder is a fence, not an observation, so a live seat whose harness never publishes its first frame no longer reads dead for the freshness horizon; fencing, aging, and persistence are unchanged. The pi layer picks this up unchanged, and spec.md's projection table documents the row.

Posted on behalf of @schickling
field value
agent_identity unknown
agent_persona generalist
agent_supervisor unavailable
agent_tool OMP
agent_tool_version 18.0.3
agent_runtime OMP 18.0.3
tooling_profile dotfiles@f33cd9c-dirty

schickling and others added 2 commits August 24, 2026 16:31
The shipped extension emits observational state frames on agent_start/
agent_end (the exact span ctx.isIdle() covers) plus an idle-proof seed at
session start. The channel owns the live record: it maps recognized state
frames to observations, heartbeats exactly as long as its stdio connection
lives, and on EOF leaves the record to age rather than asserting a state
nobody watches. The session wrapper owns the one fact the channel cannot
see and writes the terminal record with the provider's real exit status,
via a new run_provider_observed that reports the exit instead of judging
it. pi 0.84.2 exposes no waiting-on-a-human event, so no pi frame ever
sets blockedOn.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… sessions

Review-pass fixes: idle emits on agent_settled instead of agent_end —
measured against the repo's own pi captures, ctx.isIdle() is still false
through agent_end and a queued follow-up turn starts exactly there, so
the old edge blipped a spurious idle before it; the channel drops queued
live frames once the wrapper's terminal record is on disk (the flock
serializes but does not order two processes); and ptySession records the
wrapper's runtime ID, delivered to the channel via ST2_PI_CHANNEL_RUNTIME_ID
beside the existing three env vars. checks.pi-extension-types stays green
against pinned pi, proving the settle event exists on that surface.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
schickling and others added 6 commits August 24, 2026 16:31
The channel writer starts interrupted, so a restarted seat opens a new
transition instead of coalescing with — or being suppressed by — its
predecessor's record, including a predecessor's terminal ended.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The extension attaches a stream-level stdin error listener so an EPIPE
from a retiring channel can never take pi down; the wrapper mints the
session incarnation token, exports it beside the other channel env, and
both its terminal writer and the channel adopt it — the terminal record
owns exactly this session's live records.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The extension stashes and unexports ALL ST2_PI_CHANNEL_* values — the
runtime id and ownership pair included — handing them only to the
channel subprocess, so no pi tool child inherits this seat's registry key
or record ownership. The wrapper claims the ownership sequence at startup
and exports it beside the token; the channel and the terminal writer act
under the same directional claim.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… its predecessor

The wrapper's claim is a written supersession before the channel acts;
the extension awaits (bounded) the previous channel's exit before
spawning its replacement, so a predecessor cannot drain queued frames
into the new session's records after the seed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ipped extension

The cycle-5 bounded-await landed as a use-before-declaration — a TDZ
ReferenceError on every channel open, so no managed pi seat got a
channel at all — and the type gate shipped it green. The declaration is
hoisted beside closeChild, and the gate now transpiles the real asset
and drives it through registration, a double session_start (the exact
region the regression lived in), the turn events, and shutdown; the
injected-TDZ negative test fails the gate as required.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Found by the cycle-7 self-review's error-arm sweep: channel-env, hook-set
verification, and extension-injection failures after the written claim
left the placeholder as the last word. They now write a real terminal
record (ended, launch-error) before propagating.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@schickling-assistant
schickling-assistant merged commit 72c5c0f into main Aug 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants