Repository navigation
Wire compile_pool_ensure into fleet convergence: the managed slice is modeled but unreachable - #9141
gunbai-bot[bot] wants to merge 11 commits into
Conversation
…o fleet convergence Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ptiy92YHu7ig5W7ktiBzpZ
The annotation sat inside the service declaration body, which DESIGN 4c does not model. Found by execution: claim_executor --required-ci parse phase, seven refusals on this file. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ptiy92YHu7ig5W7ktiBzpZ
Two rows answered the same question and disagreed. Every BuildCacheInstance carried gunbc_managed_compile_pool_slice as intended_compile_pool unconditionally, while gunbc_compile_pool_placement said CompilePoolInRunnerSlots -- so the rendered cache unit named a Slice= that nothing provisions. Applying it would have had systemd create that cgroup implicitly WITH NO LIMITS: the same unbounded compile charge gunbc_compile_pool_doc measured, wearing the managed topology's name, with the budget model believing a bounded pool existed. Worse than the placement it was meant to improve on, because it looks converged. THE ROW MOVES TO gunbc.host_layout, AND THE HOME WAS FORCED BY MEASUREMENT RATHER THAN CHOSEN. Deriving intended_compile_pool from the placement row where it stood is impossible: gunbc.fleet_host_budget transitively REACHES gunbc.build_cache_instance, so the instance importing it closes a cycle, and acyclicity is the one structural law the import graph has. host_layout reaches neither consumer and both already import it, so the single authority costs no new import edge. The semantic argument agrees with the measurement -- where compile RSS is charged is a fact about how a host is laid out, which is that module's whole subject, and it already owns the slice NAME. The name and whether the name is managed were always one question in two homes. THE FIX IS CONSTRUCTION, NOT A CHECK. intended_compile_pool stops being a bare NonEmptyStr and carries CompilePoolPlacement itself, sourced from the single row. build_cache_unit then renders Slice= through a match, so the CompilePoolInRunnerSlots arm has NO SLICE NAME TO RENDER and the hazardous unit is not constructible -- rather than being constructible and avoided by remembering. runner_activation's pool-receipt binding answers false on that arm instead of comparing a receipt against a pool this fleet does not declare. THE ROW IS NOT FLIPPED. The fleet still declares CompilePoolInRunnerSlots, so both live tripwires keyed on that value stay green: test.claim.compile_pool_ensure_wiring_witness witness_live_topology_refuses_the_slice_ensure and test.claim.host_compile_pool live_topology_doc. The flip belongs with the wet convergence that installs the slice, which is what the dissolution trigger already demands. NOT VERIFIED LOCALLY: a whole-tree compile is OOM-killed in a session container (REAL_EXIT=137, swap disabled, shared slice), so this relies on CI to compile it. Reviewers should treat the required run as the first real check, not a formality. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
ServiceDirective is a nickname for SystemdServiceDirective, which is what extdeps.systemd.unit_file declares and what every other directive in this render already uses. Not a missing import: the bare name resolves nowhere in the corpus. Found by execution: required-ci floor, strict preparation. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ptiy92YHu7ig5W7ktiBzpZ
…y staging authority Two review findings (codex/gpt-5.6-sol, review 55280), both correct. 1. Every other HostToolchainKind is reached through a named func; CompilePool had none, so the kind was reachable from the dispatcher and the dispatcher from nobody. gunbc.host_compile_pool_provision provision_compile_pool is that entry point, thin, carrying no policy. 2. The install body hand-assembled a cat-heredoc and a sudo -n install -- a second authority for staging-and-installing a unit file beside the one gunbc.live_deploy.operations already owns. It now routes through deploy_stage_write_command and deploy_stage_install_command, which build from bash_build nodes rather than string assembly. The residue is the two lines live_deploy itself declares unmodelled (the stage-dir Let and the trap), both derived from deploy_stage_dir_var. Three witnesses added, each with an authorable RED: the first draft of the install body contained exactly the heredoc and sudo-install they refuse. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ptiy92YHu7ig5W7ktiBzpZ
An import list does not bind names here, but it does decide which modules a run LOADS, and gunbc.host_compile_pool_provision is a leaf entry point that nothing imports. Its symbols were absent rather than unbound, so the entry-point witness failed NoSuchFunction under gunbc run while passing under the floor, which loads all 3873 modules regardless. Measured: all eight witnesses now resolve, typecheck and evaluate to true. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ptiy92YHu7ig5W7ktiBzpZ
…on instance The placement carrier made intended_compile_pool conditional, and three floor witnesses went red. None of them was testing what its name says. - build_cache_ensure witness_the_generated_unit_reproduces_the_captured_environment asserted Slice=gunbc-compile-pool.slice as part of a CAPTURED environment. That capture was an env var set, and its SCCACHE_STARTUP_NOTIFY entry is the tell that no unit existed on that host at all -- so the Slice= line was never captured, it was our own intent pinned inside a fidelity witness. Moved to a both-arms witness beside the capacity idiom the same file already uses: absent under InRunnerSlots, present under SliceDeclared. - runner_activation_wall and runner_host_deploy built a fully-ready host from the PRODUCTION ci_cache_instance, so once the live row became the carrier they were asserting a fact about this fleet topology rather than about the activation fold. Fixtures now declare the pool; the live answer gets its own witness that asserts the fleet-wide refusal deliberately. That new witness returned false on its first run -- fully_verified_ready derives its instance from the fixture two calls away, so the live witness silently received the pool-declared one and asserted a refusal that could not happen. Split into fully_verified_ready_for so a witness chooses its own subject. Caught by running it. Measured: all five resolve and return true, including the negative control witness_bare_host_admission_cannot_yield_an_enable_command. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ptiy92YHu7ig5W7ktiBzpZ
* Produce BuildCacheInstanceReady from exact observations * Bind unavailable cache observations to endpoint owner * Refuse foreign unavailable observations before classification --------- Co-authored-by: Brian Searls <briansearls1@gmail.com>
|
Closing without merging. Adopted for review after this PR's session ended; the investigation is recorded here so the next reader finds it rather than redoing it. Nothing here is a criticism of the work. The refactor underneath is real and worth finishing — see What is worth salvaging at the bottom. 1. This branch's earlier work already merged, as #9062#9062 — same title, same branch That is why it advertises +1855. Squash-merge flattens the branch onto main without making its commits ancestors, so the merge base never advanced and a three-dot diff re-displays landed work as new: 19 of the 23 files are byte-identical to main. The 2. Two latent reverts, and neither is visible in the conflict listThe branch predates three main repairs. A branch predating N repairs carries N latent reverts, and only enumeration finds them:
3. The residue does not build, and its own witnesses disagreeReconstructed by branching from Compile — clean main's Witnesses: 14 of 16 pass. The two failures are the WIP's own new witnesses and are not mechanical:
4. Why this closes rather than lands trimmedLanding the 14 green and dropping the 2 reds would ship a publication path that installs over SSH without the anchoring its own sibling witness demands — behind a green. That is not an incomplete feature; it is a fail-open with a passing suite in front of it. And deleting the stale witness to reach green is the §5 antipattern verbatim: satisfying a check by editing the declaration while the realization goes unexamined. What is worth salvagingThe typed-publication refactor is genuine: It should be re-filed as one scoped piece of work — the typed-publication refactor plus the Unrelated, found in passingClean main carries 2 blocking diagnostics in |
Auto-opened by session-dashboard for session
stern-boar-129.Pushing to
session/stern-boar-129advances this PR.Worker attestation
Before flipping this PR to ready for review, confirm each item:
npm test,cargo test) and the result.Closes #Ndirective.Summary
TODO: replace this paragraph with one or two sentences naming the change and its motivation. Reviewers read this first.
Test plan