Repository navigation
pty, runner, server: observe governed PTY executions before the reap (CSRG-U5) - #95
Merged
Merged
Conversation
The pinned Codex PTY reaps a PTY child in its own waiter at once, so U5 observed a governed PTY execution only after the reap. A descendant that appeared, with its root exiting, before any observation saw it was then lost to DevGuard's tracking. The Codex patch recorded in #93 lets that waiter offer an observer one bounded window while the exited child is still unreaped. - codespace-pty: spawn_observed, with ExitWindow (release it, or drop it to release the child at once), ExitWatch and WindowEnd. Codex types stay inside the adapter. - runner: a PTY process with an exit observer, that is a governed execution, is spawned observed, with OBSERVE_BOUND as the window's bound. - When the window comes, the reaper's observer runs as for a pipe root (BeforeReap, bounded); AfterReap follows the reap as before. - While a PTY root waits in its window, termination and the timeout leave it to its reaper, as for a pipe root, so how it ended is reported unchanged. - Processes without an observer spawn as before. - Tests: - adapter, on both Unix paths: the window comes while the child is unreaped; an unreleased window is reaped at its bound and refuses a late release; a dropped window reaps at once. - runner, PTY: the observer sees the root unreaped, then reaped; a stalled observer holds it at most the bound; a failing observer releases it at once (pipe and PTY); termination and the timeout in the window keep its result and call no kill hook; output drains in full in the window. - The governed launch test now expects two observations on a PTY. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…e authority (CSRG-U5) - The fixture authority binary gains three commands, macOS only: `pause` and `resume` for its background reconciler, so that only an owner's Observe reconciles meanwhile, and `hold <ms>` for its lock, as a slow transition would hold it. - A governed PTY root that leaves a descendant ignoring the terminal's hangup. With the reconciler paused around the exit, only the window's observation can adopt the descendant. The attempt stays charged while the descendant runs and is released after it ends. With observed spawns switched off, the old after-reap-only behaviour, this test fails with the attempt Suspect. - A stalled observation: the authority is held through the window. The root is reaped at the bound, and the descendant, still running when DevGuard can look again, cannot be proven the scope's. The attempt stays Suspect, also after the descendant ends. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The pages that described PTY observation after the reap as an interim state now describe the window, in English and Korean: - The roadmap's CSRG-U5 section: - observation before the reap, for pipe and PTY alike; - termination and the timeout while a PTY root waits in its window; - the PTY paragraph; - the "not claimed" line; - the current status. - The patch record's "Use in CodeSpace" row. - The architecture page's current behaviour. - A follow-up sentence in the policy's case study. Translations recorded. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
novelKR
marked this pull request as ready for review
October 12, 2026 00:39
novelKR
pushed a commit
to novelKR/DevGuard
that referenced
this pull request
Oct 12, 2026
…n note) CodeSpace merged novelKR/CodeSpace#95 on 2026-10-12 (main 181a020): the recorded patch on the pinned Codex (novelKR/CodeSpace#93) now gives a governed PTY root the same observation before the reap as a governed pipe root, completing the PTY option the owner chose on 2026-10-11. The CS-RG plan's dated current-state note said that until a separate Codex change lands, U5 observes PTY executions only after Codex reaps them. Date the note 2026-10-12 and say what holds now, English and Korean. The units ledger is unchanged: U5 stays merged-verified, U6 not started, CS-RG in-progress with qualification not-run. Korean counterpart reviewed; planning-milestones-cs-rg hashes recorded. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This was referenced Oct 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Requested by Seongjae
Step 5 of option 3 in the owner's 2026-10-11 PTY decision. Governed PTY executions now get the same observation before the reap as governed pipe executions, through the Codex patch recorded in #93. Ungoverned PTY executions spawn exactly as before.
No pin change.
Issue
Scope: the CSRG-U5 follow-up that #92 and #93 prepared. Tracked in #76 and novelKR/DevGuard#14. This PR does not close an issue.
mainat3d051fa(#93's merge)634a19f6b9826e3with the recorded patch (tree19999371), DevGuard6e7e065; both unchangedSummary
PTY adapter (
codespace-pty).spawn_observedwraps the patch'sspawn_pty_process_observed. It offersExitWindow,ExitWatch,WindowEndandWindowExpired; Codex types stay inside the adapter.ExitWindowto let the child be reaped; dropping it releases the child at once.Runner.
OBSERVE_BOUND(2 s) as the window's bound.BeforeReapthrough the pipe path's own boundedobserve, and then the window is released.AfterReapfollows Codex's reap, as before.spawn_inheritingwith no descriptor is whatspawndid.Termination and the timeout in the window. I found this while designing, before writing the code.
has_exited()is still false. Without a guard, aterminate_processor a timeout arriving then would record a kill, and a root that had exited on its own would be reported asterminatedortimeout.exited_unreaped, pinned by U5'san_exited_child_keeps_its_one_reaper_whatever_else_acts_on_it.exited, and the PTY termination and timeout paths leave the root to its reaper. This applies the pipe contract to the PTY rather than making a new decision.DevGuard fixture authority (test binary). It gains
pauseandresumefor its reconciler, andhold <ms>for its lock, macOS only.Docs, in English and Korean.
Commits:
dc6bdbcpty, runner: observe a governed PTY root before its reap70a2441devguard, server: governed PTY window tests against DevGuard's fixture authority634a19fdocs: governed PTY executions are observed before the reapContract changes
terminate_processor a timeout arriving while a governed PTY root waits in its window no longer kills it or records a kill. The process reports how it ended, and the kill hook (DevGuardTerminate) is not called. A pipe root behaves the same way.Tests
W3 experiment B's cases on the PTY path, and pipe/PTY parity:
a_surviving_pty_descendant_keeps_a_governed_attempt_charged_until_it_ends. The reconciler is paused around the exit, so only the window's observation can adopt the descendant. With observed spawns switched off, this test fails with the attempt suspecta_pty_childs_observer_sees_the_exited_root_unreaped_then_reaped(replaces U5's after-reap-only test); the gateway's governed launch-once tests on a PTYa_pty_observer_that_does_not_return_does_not_keep_the_child_unreaped; gatewaya_stalled_observation_leaves_a_pty_survivor_suspect, with the authority held through the windowa_failing_observer_does_not_hold_the_child(pipe and PTY); adaptera_dropped_window_releases_the_child_at_once; the gateway lost-authority test (PTY)an_exited_pty_child_keeps_how_it_ended_whatever_else_acts_on_it, the PTY counterpart of the pipe'san_exited_child_keeps_its_one_reaper_whatever_else_acts_on_it. Without theexitedguard it fails withterminatedagainstexited 3a_pty_childs_output_drains_while_it_is_unreaped(200,000 bytes in the window)an_observed_child_is_offered_its_window_before_the_reap(both Unix paths),an_unreleased_window_is_reaped_at_its_boundVerified on the owner's Mac (macOS 27.0, Apple M1). Every run used a minimal environment (
env -iwith HOME, PATH and TMPDIR), so no session variable reached any test child.--features devguard.validate-upstream.py all: every stage passed;linux-isolationneeds Linux and did not run. Integration ran 663 tests.macos-core macos-fork-race: passed. The gateway's DevGuard tests (38, the D6 cases and the new PTY window tests among them) passed. The fork race ran 400 trials with 0 failed, across 61,478 children.CI on
634a19f: CI run 38187762188 passed all 17 jobs: plan, format and pin, policy scan, the three clippy legs, the seven unit legs, Linux isolation, integration, macOS contracts, and therustsummary. Documentation site run 38187762532 passed.Security scenarios
Out of scope