Repository navigation
scripts: index a gateway's log before its file is written (P1R-C06) - #115
Merged
Merged
Conversation
The full recovery run on the qualification host failed on one termination sample whose release the harness never watched. The product released the attempt (`scope_terminated`); the harness had no attempt ID to watch. The gateway logged the launch when it started the target, but the harness's log reader wrote each line to the evidence before it parsed it. DG-1's cold load builds on the same volume as the evidence, and that interval's evidence writer lagged by up to 5.6 seconds. The reader was still waiting on the disk when the 5-second wait for the attempt ID ran out, so the sample went unwatched and the interval failed as unreleased. The reader now parses and indexes each line as the gateway writes it, then hands it to a thread of its own that writes the log file. A busy disk delays only the file. `Gateway.log()` returns what the gateway has logged whether or not the file has it yet, and the two scenarios that read a gateway's log use it. A log that cannot be written is reported to the bench's evidence writer as raw evidence that could not be written, so it makes a measurement interval inconclusive as the writer's own errors do. Ending or closing a gateway still waits until its log file is complete. The protocol states this in English and Korean. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
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
Part of #101: P1R-C06. The full recovery run on the qualification host failed again, this time on one termination sample that the harness could not watch. This fixes the harness and its protocol text before the candidate is frozen again. It follows #114 and does not close an issue.
mainatb5ddd59(the merge of #114)p1r-c06-recovery-2026-10-18-b5ddd59on the qualification host,MANIFEST.jsonSHA-256dbdee96032d7d715a56a729cb1b6b97ace2901bc93f834e9fdf85e2dc7945f02;verifyaccepts it (recorded and recomputedfailed). The five check suites passed, the candidate (1fe4928c…) passed, and the rehearsal (5b2237d8…) was inconclusive as designed6e7e065; both unchangedSummary
Before: the harness took a governed launch's attempt ID from the gateway's log only after it had written that line to the evidence file. When the disk under the evidence stalled, the attempt ID arrived late, and a termination sample could go unwatched. In the full run everything else passed: 55 functional scenarios (2 gaps not run), repetitions 1 and 3, repetition 2's idle interval, and every host sample at pressure level 1. Repetition 2's load interval failed on
terminationalone:exec_command.exec_commandanswered, with no attempt to watch. The sample was effective (the scope ended in 34 ms), but with one of 84 samples unreleased the release p99 is missing, which fails the interval.scope_terminated, charging nothing. The product did what it should.None of the three failures of the 41f83b6 run came back, and #114's waits did their job. In the five checks, the rehearsal and the full run, no termination or refusal sample was refused with
RECOVERY_PENDING, and eachkill-during-terminateround refused at its start was refused once and waited 86 to 105 ms.After: a gateway's log is indexed as the gateway writes it, whatever its file's disk does. A disk the load keeps busy delays only the log file, and a log that cannot be written is counted as raw evidence that could not be written.
How.
Gateway(scripts/qualify_host.py): the log's reader decodes, parses and indexes each line, keeps it in memory, and only then hands it to a writer thread of the gateway's own, which opens the log file and appends lines as fast as the disk takes them. The file stays a byte-exact copy of what the gateway wrote.join_readers, and with itcloseandend_gateway, also waits for that writer, so a gateway's log file is complete once it has ended, as before.Gateway.log()returns what the gateway has logged so far, whether or not the file has it yet, and all of it once the gateway has exited. The two scenarios that read a gateway's log (storewriter-lockand fenceconcurrent-gateways) use it instead of the file.Writer.failed). That writer counts it as one of its own errors, so it makes a measurement interval inconclusive as "raw evidence could not be written", and in the functional suites it is recorded in the writer's report. Before, such an error ended the reader, and with it the index.docs/recovery-qualification.mdand the Korean page): the harness section states where the attempt ID comes from and how the log is written. The registry hashes are recorded.The protocol freezes the harness with it, and a change after the first run is a new protocol, reviewed like any other change, whose affected runs are repeated. On this merge the candidate is frozen again and the whole
recoveryrun is repeated.Gatewayis shared with the CS-RG suites, which C06 reruns on the same candidate anyway.Contract changes
None. The product is unchanged; only the harness, its tests and the protocol text change. The evidence's files and rows are unchanged.
Tests
Verified here at the head of this branch, in a Linux cloud container, with debug builds of
codespace-mcpandcodespace-codex-runtime(the product is unchanged sinceb2cb042):python3 -B -m unittest discover -s scripts/tests: 126 passed, 2 of them new.executionreturns it andlog()has the line while the file's writer still waits. Once the FIFO is read, the file holds exactly what the gateway wrote. Againstb5ddd59's harness the same test fails as on the host:executionreturnsNoneafter its 5-second wait.DescriptorTestsstill finds no descriptor left open by an ended gateway.scripts/check_docs.py, and the docs site's test, build and check as the docs workflow runs them.recovery --participation off --repetitions 1under a soft limit of 256 (ulimit -Sn 256), at the protocol's durations: functional 34 passed, 2 gaps not run; the 10-minute idle interval passed (26 restarts); the 30-minute load interval was inconclusive by design here ("no load ran: there is no DevGuard service to run it") with nothing failing (79 restarts); the runinconclusive(exit 2),verifyverified. None of the 326 gateway logs (rivals' included) is empty, no evidence write failed, and the harness had at most 43 files open.MANIFEST.jsonSHA-25681c418b01f8990d913dabbc39c9f5c44f348f2b31213a98e0f1e1485bea12f50.Not verified here:
required, which runs only on macOS, and a disk stall under DG-1's load. On the merge, the qualification host builds the mergedmain, and the owner's paste runs the five checks, freezes the candidate, and repeats the rehearsal and the full run.Security scenarios
Out of scope
serving_ms(from starting a gateway to its first answer) had a p99 of 4.1 to 4.9 s in the load intervals and about 0.13 s idle. That time includes the harness's own synchronous evidence writes for a new gateway (its files and its row ingateways.jsonl) as well as the gateway's own start; how much of it the busy disk caused was not measured. No verdict rule reads that time, and it is noted for the report.