Repository navigation
scripts, docs: the independent Runner's qualification harness and protocol (P1R-C06) - #112
Merged
Merged
Conversation
The qualification harness gains P1R-C06's recovery suites. recovery-lifecycle, recovery-store, recovery-fence, recovery-reconcile and recovery-observation test the five P1-RECOVERY units against an independent Runner that the harness starts in its own session, as an operator would: with participation off everywhere, and required on macOS against DevGuard's fixture authority. recovery runs them all and then measures gateway restarts. In each idle and loaded interval a fresh Runner holds governed pipe and PTY processes while gateways end in turn (input closed, SIGTERM, SIGUSR1, SIGKILL); every cycle another connection and a rival gateway probe the fence, a timeout falls with or without a gateway, and an approval is resumed across the restart, in flight when the gateway is killed. Each interval ends by draining its Runner. verify recomputes every recovery verdict from the raw rows, and CLAIMS gains the independent mode's cells. docs/recovery-qualification.md, in English and Korean, is the protocol, frozen with the harness. Operations gains the independent Runner's adoption and rollback. The guides, the gateway's flag help and its Claim log line no longer say that the mode is not supported yet: it is supported only on the combinations its qualification qualifies, none so far. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
6 of 8 tasks
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 · project thread
Issue
Part of #101: P1R-C06, the sixth and last P1-RECOVERY unit. This is its harness and protocol; the qualification run on the Mac follows the merge, and a docs-only report PR records the result. This PR does not close an issue.
mainat345864d(P1R-C05 and the P1R-C04 follow-up #111)8de5fdb6e7e065; both unchangedsetsid), with no LaunchAgent and no policy change. D7: Linuxoffis CI functional verification only, never a Linux qualification, and the CS-RG suites rerun on the same candidate once the Runner is drained. D12: thecodespaceconsumer keeps one instance, so each measurement interval registers a fresh Runner and drains it before the nextSummary
Before: the independent Runner that P1R-C01 to C05 built had no qualification. The harness covered only the CS-RG modes, nothing exercised a gateway restart against a real Runner with DevGuard or measured restarts while processes ran, and the docs said the mode was not supported yet without saying what would make it supported.
After:
scripts/qualify-devguard.pyhas six more suites. Five functional suites, one per unit, test each unit's behavior end to end against a real independent Runner that the harness starts as an operator would: 34 scenarios with participationoffeverywhere, 21 more withrequiredon macOS against DevGuard's fixture authority, and two gaps that every run records as not run. Therecoverysuite runs them all and then measures gateway restarts against the installed DevGuard service for whole idle and loaded intervals, three repetitions of 10 and 30 minutes under the full protocol. The new Gateway recovery qualification protocol, in English and Korean, says what is claimed, how each claim is shown, what passes and what evidence a run leaves; it is frozen with this harness. Operations gains "Independent Runner adoption and rollback". The mode stays unsupported everywhere until the Mac run qualifies a combination.How.
scripts/qualify-devguard.py):recovery-lifecycle(every way a gateway ends, original deadlines across restarts, the Runner's own SIGTERM, refused settings),recovery-store(records, the writer lock, schema refusal,records listandrelease),recovery-fence(a foreign connection, stale epochs, a stopped gateway, eight concurrent Claims, another database, concurrent gateways),recovery-reconcile(running and ended processes, approvals with a resume in flight, an authority outage, a missing record, gateways killed 0 to 160 ms intoexec_commandandterminate_process) andrecovery-observation(ring overflow, retention, Runner loss, a replaced Runner). Each scenario has its own Runner, operations database and work directory, and withrequiredits own fixture authority with a one-instance consumer. Commands carry tags whose marker files count how often each ran.recovery): each interval starts a fresh Runner that registers as the consumer's one instance and holds a governedcat(pipe) andsleep(PTY), a PTY that writes numbered lines and a pipe that bursts past the 256 KiB output ring on cue. Gateways are ended in turn with their input closed, SIGTERM, SIGUSR1 and SIGKILL. In every cycle the next gateway claims under the next epoch and finds the processes running; another connection's Claim and its mutating requests under three epochs must be refused as stale; a rival gateway must give up for the writer; the approval granted before the restart is resumed once by the next gateway, also when the gateway before was killed 0 to 160 ms after sending its resume; and a timeout target's deadline falls either while no gateway runs or while one serves. The control path is sampled on thecontrolsuite's schedules while a gateway serves, and slots without one are recorded asrestarting. The interval ends by draining the Runner through a gateway with the exit intentstop.scripts/qualify_analysis.py): restart, fence, rival, timeout (0.25 s early, 2 s late, recorded deadline unchanged), approval, execution and output-continuity metrics, the drain, and coverage shortfalls.verifyrecomputes them from the raw rows. A run that is not governed on macOS is namedindependent-offand never qualifies.scripts/qualify_host.py): the Runner process (started withsetsid, its log parsed for Claims), a minimal client of the runner wire (protocol 11) for the other connection, gateway ends by signal, a PID watch,running(a PID that is not a zombie), and read-only queries of the operations database.CLAIMSgains the independent mode's four cells. The guides (runner isolation, architecture, security model, agent integration, DevGuard integration, operations), the gateway's--runner-lifecyclehelp and its Claim log line now say that the mode is supported only on the combinations its qualification qualifies, so the report PR stays docs-only and the candidate frozen at this merge holds.Contract changes
None to MCP tools, error codes, status values or IDs. Two texts change: the gateway's
--runner-lifecyclehelp with theRunnerLifecycleMode::Independentdoc comment, and the gateway's log line for a Claim, which no longer adds "it is not a supported mode yet". The harness gains suites and--participation; the existing suites and their evidence are unchanged.Tests
Verified here at
8de5fdb, in a Linux cloud container running as root, with the Codex recorded patch applied:python3 -B -m unittest discover -s scripts/tests: 117 passed, 11 of them new intest_qualify_devguard.py(Runner log parsing, the wire client against a fake socket, output continuity, timeouts, restarts, approvals and markers, the drain, the Serving gate, argument checks, interval verdicts, andverifyof a synthetic sealed recovery run, as written and falsified).cargo fmt --check;cargo clippy --all-targets -- -D warningsfor the workspace and forcodespace-serverwithdevguard.scripts/check_docs.py(21 paired documents), and the docs site with Node 24.21.0:npm test(5 passed),npm run buildandsite.py check(45 HTML pages).recovery --rehearsal --participation off: all 34offscenarios passed, and the two gaps were recorded as not run. In the 2-minute idle interval, 5 restarts ended gateways in all four ways; 90 fenced requests changed nothing; none of the 6 rival gateways served; 4 timeout targets ended at most 65 ms after their original deadlines, 2 of them while no gateway ran; 5 approvals were resumed once each, one after its gateway was killed with the resume in flight; no tagged command ran twice; the PTY's 627 lines arrived whole, and the pipe's burst lost only the 22,524 lines that the Runner declared lost toring_overflow; and the drain claimed under epoch 7 and stopped the Runner with nothing left to terminate. The load interval was inconclusive, as it must be without DevGuard's service to run DG-1's load, so the run is inconclusive (exit 2), andverifyrecomputed every verdict unchanged.Not verified here: anything with
required, since DevGuard governs only on macOS; the measurement against the installed service and under DG-1's load; and the full protocol's durations. The Mac run does these.Security scenarios
codespaceinstance or charge is left, and an interval that finds one active as it begins is inconclusive.Out of scope