diff --git a/.abcd/development/brief/04-surfaces/35-drain.md b/.abcd/development/brief/04-surfaces/35-drain.md index 4d564c8fe..b195a727a 100644 --- a/.abcd/development/brief/04-surfaces/35-drain.md +++ b/.abcd/development/brief/04-surfaces/35-drain.md @@ -197,9 +197,12 @@ with no provider block, when it is one the machine's class map resolves (iss-2611080057001367); everything else keeps the provider allowlist. The map is read at the drive's start and again as each run starts; a run in progress whose model no map read during the drive names is refused at its next reviewer, naming -the model and the class map. The start refuses, before anything is reserved, a review set -with a reviewer no route on the machine can launch, naming the role, the model -and the configuration to set (`runner.Config.CanLaunch`, the admission the +the model and the class map. The runner settings, the provider blocks and the +denylist are read once, at the start, and hold until the drive ends; the review +set is read again as each run starts, as the class map is; the start's text says +so (iss-2611110527425474). The start refuses, before anything is reserved, a +review set with a reviewer no route on the machine can launch, naming the role, +the model and the configuration to set (`runner.Config.CanLaunch`, the admission the dispatch makes, asked of the configuration the drive's lanes launch on). Each iteration is one move under the drain's lock for that move alone; a lane is driven in-process through `loop.Drive` and `DriveReview`, every role on the diff --git a/.abcd/work/issues/resolved/iss-2611110527425474-a-drive-reads-the-machine-s-runner-and.md b/.abcd/work/issues/resolved/iss-2611110527425474-a-drive-reads-the-machine-s-runner-and.md new file mode 100644 index 000000000..5cd558229 --- /dev/null +++ b/.abcd/work/issues/resolved/iss-2611110527425474-a-drive-reads-the-machine-s-runner-and.md @@ -0,0 +1,17 @@ +--- +schema_version: 1 +id: "iss-2611110527425474" +slug: "a-drive-reads-the-machine-s-runner-and" +severity: "minor" +category: "bug" +source: "user-observation" +found_during: "autonomous run, live drive" +origin: researcher-authored +production_mode: hand-written +found_at: "internal/surface/cli/drain_drive.go" +remedy: "Say it where the person looks: one line in the drive's start text and one passage in the drain command page and the drain brief page, naming what is read once and that the class map and the review set are read again per run. Re-reading provider settings mid-drive is not proposed: it would move a trust decision the start's refusal now makes before anything is reserved." +resolution: "The drive's start text now says which settings are read once and that the class map and the review set are read again as each run starts; the drain command page and the drain brief page say the same." +impact: fix +--- + +A drive reads the machine's runner and provider settings once, at its start, and nothing says so. A provider block or a denylist entry changed in the machine's configuration while a drive runs takes effect only at the next start; the class map and the review set are the parts read again as each run starts. A person who changes the file to unblock a running drive sees no effect and no reason: on 10 Nov 2026 a live drive kept refusing its reviewers after the configuration had been corrected, until it was started again. Neither the start's text nor the drain page states which settings are read once. diff --git a/commands/drain.md b/commands/drain.md index f17c6ff66..a85b6df2f 100644 --- a/commands/drain.md +++ b/commands/drain.md @@ -61,7 +61,11 @@ other vendor's model, and every launch outside a drive keep the provider allowli reads the class map at its start and again as each run starts, so a run started after the map changed runs at the new routes. A run keeps the models it started with: one already in progress whose model no map read during the drive names is refused at its next reviewer, -naming the model. Map a class to it in `models.classes` and start the drive again. A review set with a reviewer +naming the model. Map a class to it in `models.classes` and start the drive again. The +runner settings, each `oracle.api.` block and the `oracle.denylist` are read once, at +the drive's start, and hold until the drive ends: a change to one of those takes effect at the +next start, and the start says so. The review set (`review.*` and `models.effort`) is read +again as each run starts, as the class map is. A review set with a reviewer no route on this machine can launch refuses the start, before anything is reserved, naming the role, the model and what to set: the denylist entry or `models.classes` for a model an entry refuses, `oracle.api.` otherwise. diff --git a/internal/surface/cli/drain_drive.go b/internal/surface/cli/drain_drive.go index 1408d6cfa..520281547 100644 --- a/internal/surface/cli/drain_drive.go +++ b/internal/surface/cli/drain_drive.go @@ -410,6 +410,11 @@ func driveConsent(cmd *cobra.Command, w io.Writer, f driveFlags, lanes, runs int fmt.Fprintf(w, " profile: %s, a separate login and settings on this one account; a stage's shell reads what this account can\n", name) fmt.Fprintln(w, " gates: a change to the Makefile, scripts/ or the hooks is not a drive's: it needs a person's own session") fmt.Fprintln(w, " first: one short live launch checks the tools, the guard and the shell, on the same subscription") + // What a change to the machine's configuration reaches during the drive + // (iss-2611110527425474): the runner settings, the provider blocks and the + // denylist are read once, before this text; the class map and the review + // set are read again as each run starts. + fmt.Fprintln(w, " settings: this machine's runner settings, provider blocks and denylist are read now and hold until the drive ends; the class map and the review set are read again as each run starts") fmt.Fprintln(w, " updates: a harness update during the run carries on only where the new file has the same signing team and passes one more such launch; elsewhere the run stops") fmt.Fprintln(w, " releases: "+fsutil.RedactHome(driveReleaseLine(f))) if !f.noSelfUpdate && f.self.Refusal == nil { diff --git a/internal/surface/cli/drain_drive_update_test.go b/internal/surface/cli/drain_drive_update_test.go index e7b37092b..948c12ceb 100644 --- a/internal/surface/cli/drain_drive_update_test.go +++ b/internal/surface/cli/drain_drive_update_test.go @@ -230,6 +230,11 @@ func TestNoSelfUpdateMakesNoRequest(t *testing.T) { if !strings.Contains(out.String(), "releases: none (--no-self-update)") { t.Fatalf("the consent line says none:\n%s", out.String()) } + // The start says what a later change to the machine's configuration + // reaches (iss-2611110527425474). + if !strings.Contains(out.String(), "settings: this machine's runner settings, provider blocks and denylist are read now and hold until the drive ends; the class map and the review set are read again as each run starts") { + t.Fatalf("the start does not say when the settings are read:\n%s", out.String()) + } if w.terminalCalls != 1 { t.Fatalf("the loop runs: %d", w.terminalCalls) }