Repository navigation
codex, scripts, docs: carry the PTY pre-reap observer as a recorded patch on the pinned release - #93
Merged
Merged
Conversation
…atch on the pinned release
The pinned Codex PTY spawn (rust-v0.154.0) reaps its child in its own
waiter, so CodeSpace cannot observe a governed PTY execution's scope
before the reap; CSRG-U5 observes PTY executions after it, the interim
state of the owner's option 3. The owner chose to carry the fix as a
patch file on the official release, not a fork.
- third_party/codex-patches/0001-utils-pty-pre-reap-observation.patch:
one commit, as git format-patch, on rust-v0.154.0 (6b9826e3). It adds
codex_utils_pty::spawn_pty_process_observed and observe::{ExitObserver,
ExitOpportunity, ObservationOutcome, OpportunityExpired}. The single
waiter sees the exit with waitid(WNOWAIT), gives the observer one
bounded opportunity, then reaps as before and reports the outcome.
Without an observer nothing changes. Nine tests in the crate, each on
both Unix PTY paths.
- scripts/codex_patch.py applies, checks and reverts the patches that
docs/upstream-lock.md records. It requires the recorded patched tree
(19999371), computed in a scratch index, so a missing patch or any
other change in the checkout fails. Its tests cover each state.
- scripts/validate-upstream.py applies the patches before it
fingerprints its inputs, so CI and local validation build the recorded
source, and its report records the checkout's tree.
check-upstream-pin.sh also verifies the patched tree.
- docs/upstream-lock.md records the patch: file and SHA-256, patched
tree, capability, reason, provenance, verification, upstream status,
removal, pin changes and rollback. The install and update procedures
apply it, and revert it before the submodule moves. NOTICE states the
modification. English and Korean.
The submodule stays on openai/codex at 6b9826e3. No CodeSpace code uses
the observer yet; connecting it to the PTY adapter is a separate change.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The owner asked for a written policy for fixes that a Codex pin makes unavoidable, following the patch-file choice, and for a case study of how earlier Codex adapter conflicts were handled, so that later choices stay consistent. - docs/upstream-patches.md, in English and Korean: the order of options (adapter on the public API, pin update, recorded patch, CodeSpace-owned replacement), when a patch is chosen and why it comes before a CodeSpace-owned replacement, its form (official submodule, format-patch files, checked patched tree, no fork, no copied crate), its record, the upstream feature request, pin changes and approval. - Earlier cases: the adapter conflicts from the first pin to the PTY observer, grouped by how they were settled, what they show, and three open points found while collecting them. - The page is an implementation guide after the update procedure, and Codex reuse, the pin record, the update procedure and the overview link to it. The update procedure reviews patches under this policy instead of the suspended adaptation rule. No code, pin or dependency changes. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
novelKR
marked this pull request as ready for review
October 11, 2026 18:29
This was referenced Oct 11, 2026
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.
Issue
Scope: the Codex PTY hook of option 3 in the owner's CSRG-U5 decision (2026-10-11): U5 observes PTY executions after Codex's reap, and the pre-reap hook is prepared separately. On 2026-10-11 the owner chose to carry the hook as a patch file on the official pin, not as a fork. The owner also asked for a written policy for fixes that a Codex pin makes unavoidable, with a case study of earlier Codex adapter conflicts. This PR does not close an issue. Tracking: #76 and novelKR/DevGuard#14.
mainat0c21a7f(#92's merge)a75d030:374a3fcadds the patch, its scripts and records;a75d030adds the policy and case study (documentation only)6b9826e3onopenai/codexand DevGuard source6e7e065, both unchangedSummary
What this guarantees. Every build that goes through
scripts/validate-upstream.py, which is every CI job and the local gates, compiles Codexrust-v0.154.0plus exactly one recorded patch tocodex-utils-pty, and nothing else. The pin check and the validation refuse a checkout whose files are not the recorded patched tree.The patch.
third_party/codex-patches/0001-utils-pty-pre-reap-observation.patch(SHA-2566f61579830f311e3c259c0642864ea9eee3c653f12c7e838e97e9b1dd35b1fba, patched tree1999937194e3a68d982be85679557f0e50fe5408):spawn_pty_process_observedandobserve::{ExitObserver, ExitOpportunity, ObservationOutcome, OpportunityExpired}. The child's single waiter sees the exit withwaitid(WNOWAIT), gives the observer one opportunity for at most its bound, then reaps through the same child object as before. After the reap it reportsCompleted,TimedOut,FailedorUnavailable; an acknowledgement after the bound returnsOpportunityExpired.docs/handoff/2026-09-28-w3-decision-packet.md, section 3.2), ported fromrust-v0.159.0-alpha.11to this release and widened from macOS's fd-preserving path to both Unix paths.How it is applied.
scripts/codex_patch.py apply|check|revertreads the pinned commit, each patch file with its SHA-256, and the patched tree fromdocs/upstream-lock.md. It computes the checkout's tree in a scratch index, untracked files included and ignored ones left out.applybrings a clean checkout of the pinned commit to the patched tree, or confirms it is already there. Any other state fails: another commit, a changed patch file, or a stray change.scripts/validate-upstream.pyapplies the patches before it fingerprints its inputs. Its report gainscodex_patchesandinputs.codex_tree.scripts/check-upstream-pin.shrunscodex_patch.py checkafter the commit check.Documents, in English and Korean:
upstream-lock: the patch record (file, digest, patched tree, capability, reason, provenance, verification, upstream status, removal, pin changes, rollback) and the check commands.upstream-update: the one limited adaptation, and reverting the patches before the submodule moves.operations: apply the patch after every submodule update; Python 3 is now needed.NOTICE: the modification.codex-reuse,upstream-lock,upstream-updateand the overview link the policy below. The update procedure reviews patches under it instead of the suspended adaptation rule.Policy and case study.
docs/upstream-patches.md, in English and Korean, is a new implementation guide after the update procedure.git format-patchfiles, a checked patched tree, no fork and no copied crate. The page also covers the record, the upstream feature request, pin changes and approval.crates/patchhas no Rama resolver guard; the conflict recorded for the patch helper (W09-A: patch preflight without writes #27) predates the root's copy of Codex's[patch]entries (P0 filesystem: PathSandbox over isolated Codex LOCAL_FS #51), so whether it still holds is unverified; no reason is recorded for choosingrust-v0.154.0.Contract changes
None. No tool schema, error code, status value or ID changes.
For developers: after cloning or updating the submodule, run
python3 scripts/codex_patch.py applybefore building. While the patch is applied,git statusshowsthird_party/codexas modified.Tests
python3 -m unittest discover -s scripts/tests: 65 passed, 10 of them new forcodex_patch.py.codex_patch.py checkfails beforeapply.applygives tree19999371…, a secondapplychanges nothing, andPIN_ONLY=1 ./scripts/check-upstream-pin.shpasses. In a scratch clone,git apply -Rrestores tree74ba48a4…(the pinned commit's).python3 scripts/validate-upstream.py pin python format unit-pty clippy-adapterspassed on374a3fcwith the patch applied: the PTY adapter's 7 tests ran against the patched crate, and clippy with-D warningspassed for the patch, PTY, file-system and DevGuard adapters.a75d030:python3 -B scripts/check_docs.pyverified 18 paired documents after the five changed pairs were recorded, and the documentation site's 5 tests passed. The site build needs Node 24.21.0 and runs in CI.-D warnings; clippy for macOS and Windows targets.6e7e065.374a3fcwith the patch applied (tree19999371…):validate-upstream.py allpassed every stage it ran.linux-isolationneeds Linux and did not run. The integration stage ran 653 tests.macos-fork-racepassed: 400 runs, 62,602 children, no failure.macos-corefailed once, in one test. Indevguard::tests::sessions_opened_while_children_spawn_reach_no_child, one of 40 worker children listed descriptor 10, which is not a socket and which the baseline did not have. The stage passed onmain(0c21a7f, without the patch), and the test alone passed 20 times onmainand 20 times on374a3fc. The cause is not established. The worker's spawn marks every descriptor above 2 close-on-exec before exec (crates/runner/src/descriptors.rs), and this PR changes neither that path nor how the PTY crate handles descriptors.74ba48a4….374a3fc: CI run 38161241164, all 17 jobs passed, macOS contracts included; documentation site run 38161241672 passed.a75d030: CI run 38162895742, all 17 jobs passed; documentation site run 38162896180 passed.Security scenarios
Out of scope
ExitPoint::BeforeReapfor PTY): a separate PR after this one merges.macos-corefailure above, and the descriptor tests' failure messages, which print the child's whole environment: a separate PR.