Skip to content

feat(codex): publish observed harness state from the control pump - #321

Merged
schickling-assistant merged 12 commits into
schickling/hs-02-vrs-intentfrom
schickling/hs-03-codex
Aug 24, 2026
Merged

feat(codex): publish observed harness state from the control pump#321
schickling-assistant merged 12 commits into
schickling/hs-02-vrs-intentfrom
schickling/hs-03-codex

Conversation

@schickling

@schickling schickling commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

The Codex producer (#268 §A prerequisite + §B), on top of the envelope.

  • Watcher scoping (hard prerequisite): watch::watch_delivery_inputs forwards mutations only for the resources/inbox subtree and the status file; the delivery pump switches to it. This also removes the pre-existing self-wake where the pump's own 5-minute presence refresh woke it through the unfiltered agent-dir watch. Regression test proves harness-state/tmp/stream writes stay silent while inbox and status writes wake.
  • Projection: CodexObservedState::harness_observation()Held never enters the published vocabulary; ActiveWithoutTurn/ConflictingTurn project to active (the two rows Observed harness state: the activity-lease slice of #162, specified and made readable #268 §B corrects); Review/WaitingOnApproval/WaitingOnUserInputactive + blockedOn: human; AwaitingStatus/NotLoaded/SystemError withhold (no write, heartbeat suppressed — the record ages out). The projection test is behavioral: an all-indeterminate mapping fails it.
  • Wiring: the pump writes on every observed transition, re-stamps on the presence cadence only while evidence holds, and writes the terminal record when the wrapper completes.

Notably this needs no new Codex read path: the pump projects its own in-memory state, sidestepping the fact that control-state.json has no production reader.

  • Cycle-2: the stop flag is honored through every startup phase (graceful, recordless before the TUI exists); the restarted pump opens a fresh transition on takeover; the human-blocking holds name their ask kind (review/permission/question).

  • Cycle-3: a transition whose record write fails no longer counts as evidence — it is retained as pending and retried before any heartbeat; both codex writers adopt the runtime incarnation as their session token.

  • Cycle-4: the stop handler installs before ANY spawn (hook-trust preflight included, and exactly once — reinstalling would reset a raised flag); pending observations retry on every pump pass with only the heartbeat cadence-gated.

  • Cycle-7: Held{Review} projects plain activity — review's enter/exit are model-emitted items inside a running turn, so blockedOn stays none and review is a reserved ask word (the delivery hold is untouched); the preflight's initialize handshake and projection reads poll the stop flag between short socket timeouts.

  • Cycle-8: the stop flag reaches a silent WebSocket handshake — the handshake runs under the short poll timeout and resumes through tungstenite's interrupted state, checking stop on every resume, so a never-answering app-server no longer holds the launch for the whole startup timeout.

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

🤖 Generated with Claude Code

Refinement pass: the wrapper now installs the shared stop handler and the monitor observes it, ending the session through the ordinary terminal-write path — previously st2's own stop SIGTERMed the wrapper dead before the post-join write, leaving a stopped seat reading its last live state until the staleness horizon; the terminal record's exit carries the actually-observed ExitStatus on every arm (error text stays diagnostic in reason); evidence loss interrupts the writer so a state restated across an unproven interval opens a fresh transition; and ptySession records the wrapper's runtime ID.

@schickling schickling changed the title schickling/hs 03 codex feat(codex): publish observed harness state from the control pump 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: 2af6993885

ℹ️ 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/codex_app_server.rs Outdated
Comment thread src/codex_app_server.rs Outdated
Comment thread src/codex_app_server.rs Outdated
@schickling
schickling force-pushed the schickling/hs-03-codex branch from 2af6993 to 495d84f 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: 495d84ffa5

ℹ️ 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/codex_app_server.rs Outdated
Comment thread src/codex_app_server.rs Outdated
@schickling
schickling force-pushed the schickling/hs-03-codex branch from 495d84f to 1b36b3b 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: 1b36b3b0cb

ℹ️ 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/codex_app_server.rs Outdated

@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: 2578472b6d

ℹ️ 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/codex_app_server.rs Outdated
Comment thread src/codex_app_server.rs Outdated
@schickling
schickling force-pushed the schickling/hs-03-codex branch from 2578472 to 5bf821f 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: 5bf821f2b4

ℹ️ 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/codex_app_server.rs
@schickling
schickling force-pushed the schickling/hs-03-codex branch from 5bf821f to 6312ff8 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: 6312ff82b4

ℹ️ 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/codex_app_server.rs Outdated
Comment thread src/codex_app_server.rs
@schickling
schickling force-pushed the schickling/hs-03-codex branch from 6312ff8 to 32c8169 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: 32c81699c6

ℹ️ 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/codex_app_server.rs
@schickling
schickling force-pushed the schickling/hs-03-codex branch from 32c8169 to 3cae2af 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: 3cae2afdeb

ℹ️ 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/codex_app_server.rs Outdated
@schickling
schickling force-pushed the schickling/hs-03-codex branch from 3cae2af to 62ba0c8 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: 62ba0c82b4

ℹ️ 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/codex_app_server.rs
let stream = UnixStream::connect(&socket_path).unwrap();
let stopper = std::thread::spawn(|| {
std::thread::sleep(Duration::from_millis(300));
crate::provider_session::STOP.store(true, std::sync::atomic::Ordering::SeqCst);

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 Isolate the global stop flag in the handshake test

When the test suite runs with Rust's default parallel execution, this test sets the process-global provider_session::STOP for all tests for roughly one polling interval. Concurrent app-server tests also call initialize_control, which reads this flag and can return None; those tests then fail at their .expect("no stop raised in tests") calls. Serialize every test that accesses this flag or inject a test-local stop flag so this test cannot poison unrelated handshakes.

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 c1c56c9 on schickling/hs-03-codex: flag-touching tests are serialized -- a shared test mutex orders every initialize_control reader against the handshake test that raises the process-global STOP, so parallel readers can no longer observe the raised flag and fail their no stop raised in tests expectations.

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

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 c1c56c9 on schickling/hs-03-codex: flag-touching tests are serialized -- a shared test mutex orders every initialize_control reader against the handshake test that raises the process-global STOP, so parallel readers can no longer observe the raised flag and fail their no stop raised in tests expectations.

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 delivery pump's watcher narrows to its two genuine inputs (inbox +
status) so runtime records written into the agent dir - presence temp
siblings, harness-state transitions - can never wake it. The pump
projects CodexObservedState into the generic record on every persisted
change: Held never leaks (human-blocking holds read active+blockedOn,
positively-active holds read active, unprovable holds withhold), the
heartbeat rides the existing presence cadence and stops on evidence
loss, and the wrapper publishes a terminal record once the pump is gone.

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

Review-pass fixes: the wrapper installs the shared stop handler and the
monitor observes it, ending the session through the ordinary
terminal-write path (previously st2's own stop SIGTERMed the wrapper dead
before the post-join write); the terminal record's exit carries the
actually-observed ExitStatus on every arm, error text stays diagnostic in
reason; evidence loss interrupts the writer so a state restated across an
unproven interval opens a fresh transition; and ptySession records the
wrapper's runtime ID, which only aliases the identity on driver-expanded
seats.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
schickling and others added 10 commits August 24, 2026 16:31
…e-readable ask kinds

SIGTERM is honored through connect/initialize/binding (graceful, before
the TUI exists no record is left behind), the restarted pump opens a
fresh transition instead of claiming continuity across its own gap, and
the human-blocking holds name their ask kind (review/permission/question).

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

A transition whose write fails no longer counts as evidence: it is
retained as pending and retried on the next pump pass before any
heartbeat may re-stamp the contradicted on-disk state. Both codex writers
adopt the runtime incarnation as their session token, so the terminal
record owns exactly this session's records.

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

The signal handler installs at the top of run_controlled_owned — before
the hook-trust preflight spawns its detached app-server — so a SIGTERM in
that window sets the polled stop flag instead of leaking a server and a
stale socket (and the flag is never reset mid-launch by a second
install). A pending observation retries on every pump pass; only the
heartbeat stays presence-cadence gated.

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

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

A claim that cannot be written degrades to a token-only writer with a
warning instead of erroring the pump (which killed the TUI through the
binding wait); a TUI spawn failure writes a real terminal record —
ended, exit unknown, reason launch-error — over the claim placeholder
that would otherwise misread as a takeover.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…poll the stop flag

Held{Review} projects plain activity — its enter and exit are
model-emitted items inside a running turn, so blockedOn stays none and
review becomes a reserved ask word no producer emits (the delivery hold
is untouched). The initialize handshake wait and the hook-trust
projection read now poll the stop flag between short socket timeouts,
with the startup timeout restored for later control reads.

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

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A short read timeout parks the handshake on its resumable Interrupted state
each poll interval, so a stop raised while the app-server never answers the
Upgrade request ends startup gracefully instead of blocking the launch for
the whole startup timeout.

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

An early failure return would otherwise reset first and let the stopper
re-poison the global flag for the rest of the single-threaded test process.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The handshake test flips the process-global STOP flag for a poll interval;
initialize_control tests running in parallel read that same global and fail
their no-stop expectations at random. A shared test lock now orders every
flag reader against its writer.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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-assistant
schickling-assistant merged commit a5d56c9 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