From 7c7de8c7862c4a6c84622430c4f0cdd2bb5f791f Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Thu, 20 Aug 2026 02:25:54 +0000 Subject: [PATCH 1/2] SHELL-DAG: migrate six retained_foreign call sites to typed operations MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Dissolves six confirmed retained_foreign (shell-string-concat) call sites in favor of typed shell/extdeps operations, per §3/§5: construction over string-building, single authority reused where it exists. Sites migrated (all in dag/gunbc/package_delivery.dag unless noted): 1. observe_protocol_schema_identity — codex app-server generate-json-schema invocation -> new codex_app_server.Cli.GenerateJsonSchema (added to the existing extdeps.llm.codex_app_server module, which already cites this executable/protocol). 2. observe_protocol_schema_identity — `find ... | sort` listing -> new shell.Find.FilesByNameSorted (extdeps/shell.dag), following the existing FilesAndSymlinksWithMode positional-parameter precedent so no path/glob can escape a quote. 3. finish_bisect_generate_protocol_schema_dir — duplicate of #1, same new op. 4. relocate_build_root_to_unique_publishing — `rmdir && mv -T` -> shell.Remove.EmptyDirectory + shell.Move.NoReplaceDirectory (both new operations on the existing shell.Remove/shell.Move services). 5. rename_publishing_noreplace — `mv -T` -> shell.Move.NoReplaceDirectory. 6. dag/tools/interpreter_dispatch_bijection_real_roster_transport.dag, real_roster_cargo_run — multi-line bash (set -euo pipefail; cd; export; two `cargo test --ignored --exact` invocations) -> new cargo.Build.TestWithCwdEnv (extdeps/rust/cargo_build.dag), composing `env -C test ` as one argv vector, called twice sequentially from real_roster_cargo_test_run with explicit caller-side short-circuit (cargo_outcome_holds) preserving the fail-fast semantics without shell chaining. Architectural calls made along the way (documented per task brief): - Used a narrow, domain-specific op (codex_app_server.Cli.GenerateJsonSchema) instead of shell.Exec.RunArgv + ProcessArgvExpansion/CliSurface, which has zero production consumers today and is disproportionate machinery for a one-off fixed 4-token argv. - shell.Remove.EmptyDirectory uses `rmdir` (refuses if non-empty) rather than `rm -rf`, preserving the original script's safety property. - relocate_build_root_to_unique_publishing computes a plain Bool in each branch rather than unifying two different services' anonymous output records across an if/else, to avoid a speculative cross-type merge. Also fixes two DESIGN §4c violations surfaced while landing the new operations: explanatory `//` comments were nested inside a `service { }` body (module-item grain only) — relocated into top-level `data ..._note` declarations in shell.dag and cargo_build.dag, matching the file's existing convention. And fixes an accidental interpolation hazard: the new cwd/env note's prose contained a literal `{workdir}`, which the compiler parsed as an unbound interpolation reference — reworded to plain prose. Verification: entry-scoped `gunbc compile` on both touched leaf files (package_delivery.dag, interpreter_dispatch_bijection_real_roster_transport.dag) is 0 blocking errors on both (395 / 14 pre-existing-pattern advisories, where-refinement-unenforced on non-literal FilePath/NonEmptyStr casts, unrelated to this change). gunbc.retained_shell_script's retained_foreign carries no fixed caller-count assertion, and none of these six sites appear in the host_language_transport_script wall_residue_live_test.dag roster, so no lens update is required. The interpreter_dispatch_bijection_real_roster witness (real git clone + cold cargo build, ~692s wall) was not executed in this session — its own test file documents it as "a cadence job, not a session job" requiring a runner with ~11 GiB and a local cargo; the hermetic cargo_execution_placement_witness_test.dag controls (which cover the placement-decision logic this site also uses) pass. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01WaiMx97tLCspkMg9rDkfjS --- dag/extdeps/llm/codex_app_server.dag | 23 ++++- dag/extdeps/rust/cargo_build.dag | 20 ++++- dag/extdeps/shell.dag | 43 ++++++++++ dag/gunbc/package_delivery.dag | 83 +++++-------------- ...spatch_bijection_real_roster_transport.dag | 69 +++++++++------ 5 files changed, 146 insertions(+), 92 deletions(-) diff --git a/dag/extdeps/llm/codex_app_server.dag b/dag/extdeps/llm/codex_app_server.dag index 3963f6f89ff..ef0c6307ba7 100644 --- a/dag/extdeps/llm/codex_app_server.dag +++ b/dag/extdeps/llm/codex_app_server.dag @@ -1,6 +1,6 @@ module extdeps.llm.codex_app_server -import std.types { NonEmptyStr, String, FilePath, Int } +import std.types { NonEmptyStr, String, FilePath, Int, Bool } import std.decl_ref { DeclarationRef, WholeDeclaration } import extdeps.external_authority { ExternalAuthority, ExternalModelScope, ExternalSubjectRef } import extdeps.uri { Uri, Https } @@ -64,6 +64,27 @@ type CodexAppServerExecutable { path: FilePath } +// The `generate-json-schema` subcommand is a separate invocation of the SAME executable this +// module cites the protocol schema from (codex_app_server_subject_note) — it is the tool this +// module's method vocabulary was derived from, not a different product surface. +service codex_app_server.Cli { + operation GenerateJsonSchema { + input { executable: CodexAppServerExecutable, output_dir: FilePath } + output { + success: Bool from "exit_success" + stdout: String from "stdout" + stderr: String from "stderr" + } + transport shell { + argv: ["{executable.path}", "app-server", "generate-json-schema", "-o", "{output_dir}"] + } + exit { + 0 => Unit + nonzero => String "codex app-server generate-json-schema failed" + } + } +} + data codex_app_server_request_line_emit_note: String = "Request lines are BUILT through extdeps.languages.json.emit, not hand-authored as escaped string literals (review 50540). The literals they replace carried their own JSON grammar — braces, quoting and separators spelled out in \\{ and \\\" escapes — which is a second JSON representation sitting beside the module that already owns one (DESIGN §3 dual representation), and it is the representation that cannot escape a value: a method name or client field containing a quote would have produced a malformed frame with nothing to refuse it. serialize_json applies the escaping, so the wire bytes are a consequence of the modeled value rather than of an author getting the backslashes right." fn codex_app_server_jsonrpc_request(id: Int, method: String, params: JsonValue) -> NonEmptyStr { diff --git a/dag/extdeps/rust/cargo_build.dag b/dag/extdeps/rust/cargo_build.dag index 5195dd8c6fb..11d079916d7 100644 --- a/dag/extdeps/rust/cargo_build.dag +++ b/dag/extdeps/rust/cargo_build.dag @@ -1,6 +1,6 @@ module extdeps.cargo_build -import std.types { FilePath } +import std.types { FilePath, NonEmptyStr } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } @@ -13,6 +13,8 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { data cargo_compile_env: Map = empty_map() +data cargo_test_with_cwd_env_note: String = "cargo.Build.TestWithCwdEnv: env composes cwd (-C) and process env vars (leading VAR=val argv words) into ONE argv vector, matching the shell.Find.Files precedent of argv-native env -C workdir substitution — no shell is needed to chain a cd/export prefix onto a cargo invocation (SHELL-DAG dissolution of the interpreter_dispatch_bijection_real_roster_transport retained_foreign multi-line script: set -euo pipefail; cd; export; two cargo test invocations, now two sequential typed calls with caller-side short-circuit)." + fn cargo_build_jobs_flag(count: Int) -> List { ["--jobs", to_string(count)] } @@ -93,6 +95,22 @@ service cargo.Build { } } + operation TestWithCwdEnv { + input { workdir: FilePath, cargo_bin: NonEmptyStr, env: List = [], extra_args: List = [] } + output { + success: Bool from "exit_success" + exit_code: Int from "exit_code" + stdout: String from "stdout" + stderr: String from "stderr" + } + transport shell { argv: ["env", "-C", "{workdir}", env, "{cargo_bin}", "test", extra_args] } + exit { + 0 => Unit + 101 => String "Tests failed" + nonzero => String "cargo test error" + } + } + operation Nextest { input { extra_args: List = [], build_jobs_args: List = [] } output { diff --git a/dag/extdeps/shell.dag b/dag/extdeps/shell.dag index d357b77424b..6354bdde528 100644 --- a/dag/extdeps/shell.dag +++ b/dag/extdeps/shell.dag @@ -13,6 +13,8 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { data find_files_and_symlinks_positional_note: String = "The script body is a FIXED literal owned here, and root arrives as the positional parameter $1 rather than being spliced into it — so no path can escape a quote, which is exactly what a caller-side concat into a single-quoted find string permitted (review 50535). The pipe to sort stays inside the operation because it is load-bearing: find walks directories in filesystem order, and the caller digests the resulting listing into a tree identity, so an unsorted read would make that identity depend on traversal order. It cannot move into the substrate today — std.primitives declares a sort contract but no callable sort exists (probed, 2026-08-08), which is the dissolve-on for folding this ordering back out of the shell. GNU find -printf keeps this operation Linux-only, per the caller's own linux_find_note." +data files_by_name_sorted_positional_note: String = "shell.Find.FilesByNameSorted: root and name_glob arrive as positional parameters ($1, $2) rather than being spliced into the script body, for the same reason as FilesAndSymlinksWithMode above — no path or glob can escape a quote. The pipe to sort stays inside the operation because the caller digests the listing into a manifest and needs traversal-order independence (SHELL-DAG dissolution of package_delivery.dag's protocol-schema-bundle file listing, previously a retained_foreign concat-built find | sort script)." + service shell.Find { operation ListDirs { @@ -61,6 +63,27 @@ service shell.Find { nonzero => String "Find command failed" } } + + operation FilesByNameSorted { + input { root: FilePath, name_glob: NonEmptyStr } + output { + success: Bool from "exit_success" + stdout: String from "stdout" + stderr: String from "stderr" + } + readonly + transport shell { + argv: [ + "sh", "-c", + "find \"$1\" -type f -name \"$2\" | sort", + "sh", "{root}", "{name_glob}", + ] + } + exit { + 0 => Unit + nonzero => String "Find command failed" + } + } } service shell.Env { @@ -257,6 +280,16 @@ service shell.Remove { nonzero => String "rm -rf failed" } } + + operation EmptyDirectory { + input { path: FilePath } + output { success: Bool from "exit_success" } + transport shell { argv: ["rmdir", "{path}"] } + exit { + 0 => Unit "Directory removed; rmdir refuses when non-empty, which is the safety this relies on" + nonzero => String "rmdir failed" + } + } } service shell.Move { @@ -269,6 +302,16 @@ service shell.Move { nonzero => String "mv failed" } } + + operation NoReplaceDirectory { + input { source: FilePath, destination: FilePath } + output { success: Bool from "exit_success" } + transport shell { argv: ["mv", "-T", "{source}", "{destination}"] } + exit { + 0 => Unit "Directory moved; -T treats destination as a normal path (no nest into an existing dir), equivalent to renameat2(RENAME_NOREPLACE) for directories on Linux" + nonzero => String "mv -T failed" + } + } } service shell.Chmod { diff --git a/dag/gunbc/package_delivery.dag b/dag/gunbc/package_delivery.dag index 61416fc6e40..ca30304651a 100644 --- a/dag/gunbc/package_delivery.dag +++ b/dag/gunbc/package_delivery.dag @@ -48,6 +48,7 @@ import extdeps.version { VersionIdentity } import extdeps.http.client import extdeps.shell import extdeps.shell.exec +import extdeps.llm.codex_app_server { CodexAppServerExecutable } import extdeps.filesystem.filesystem_io import extdeps.tools.npm import gunbc.host_cli_dependency { @@ -72,7 +73,6 @@ import extdeps.languages.json.emit { JsonKeyValue, serialize_json, } import extdeps.languages.json.parse { parse_json } -import gunbc.retained_shell_script { retained_foreign } import extdeps.ollama.binary_release { OllamaBinaryRelease, ollama_required_release, @@ -1409,31 +1409,17 @@ fn observe_protocol_schema_identity( if made.success == false { none } else { - let script = retained_foreign( - body: concat( - "'", - concat( - native_executable as String, - concat( - "' app-server generate-json-schema -o '", - concat(schema_dir as String, "'"), - ), - ), - ), - reason: "Codex generate-json-schema observation pending typed WitnessBin argv enrollment" as NonEmptyStr, + let gen = codex_app_server.Cli.GenerateJsonSchema( + executable: CodexAppServerExecutable { path: native_executable }, + output_dir: schema_dir, ) - let gen = shell.Exec.Run(script: script) if gen.success == false { none } else { - let list_script = retained_foreign( - body: concat( - "find '", - concat(schema_dir as String, "' -type f -name '*.json' | sort"), - ), - reason: "Protocol schema bundle file list pending typed Find enrollment" as NonEmptyStr, + let listed = shell.Find.FilesByNameSorted( + root: schema_dir, + name_glob: "*.json" as NonEmptyStr, ) - let listed = shell.Exec.Run(script: list_script) if listed.success == false { none } else { @@ -1738,24 +1724,13 @@ fn relocate_build_root_to_unique_publishing( if staged.success == false { none } else { - let script = retained_foreign( - body: concat( - "rmdir '", - concat( - staged.path as String, - concat( - "' && mv -T '", - concat( - build_root as String, - concat("' '", concat(staged.path as String, "'")), - ), - ), - ), - ), - reason: "Exclusive unique publishing relocate: rmdir mktemp placeholder then mv -T build root onto that name" as NonEmptyStr, - ) - let run = shell.Exec.Run(script: script) - if run.success == false { + let emptied = shell.Remove.EmptyDirectory(path: staged.path) + let moved = if emptied.success == false { + false + } else { + shell.Move.NoReplaceDirectory(source: build_root, destination: staged.path).success + } + if moved == false { let _ = shell.Remove.RecursiveForce(path: staged.path) none } else { @@ -1768,17 +1743,7 @@ fn rename_publishing_noreplace( publishing: FilePath, dest: FilePath, ) -> Bool { - let script = retained_foreign( - body: concat( - "mv -T '", - concat( - publishing as String, - concat("' '", concat(dest as String, "'")), - ), - ), - reason: "Atomic no-nest publication rename (GNU mv -T / renameat2 RENAME_NOREPLACE equivalent for dirs)" as NonEmptyStr, - ) - shell.Exec.Run(script: script).success + shell.Move.NoReplaceDirectory(source: publishing, destination: dest).success } fn codex_runtime_release_ready_with_current_link( @@ -2568,20 +2533,10 @@ fn finish_bisect_generate_protocol_schema_dir( if made.success == false { false } else { - let script = retained_foreign( - body: concat( - "'", - concat( - native_executable as String, - concat( - "' app-server generate-json-schema -o '", - concat(schema_dir as String, "'"), - ), - ), - ), - reason: "Protocol schema interpreter bisect generate-json-schema pending typed WitnessBin argv enrollment" as NonEmptyStr, - ) - shell.Exec.Run(script: script).success + codex_app_server.Cli.GenerateJsonSchema( + executable: CodexAppServerExecutable { path: native_executable }, + output_dir: schema_dir, + ).success } } diff --git a/dag/tools/interpreter_dispatch_bijection_real_roster_transport.dag b/dag/tools/interpreter_dispatch_bijection_real_roster_transport.dag index beda2dcfafc..0271341a743 100644 --- a/dag/tools/interpreter_dispatch_bijection_real_roster_transport.dag +++ b/dag/tools/interpreter_dispatch_bijection_real_roster_transport.dag @@ -2,7 +2,7 @@ module tools.interpreter_dispatch_bijection_real_roster_transport import extdeps.git.inspect import extdeps.shell -import gunbc.retained_shell_script { retained_foreign } +import extdeps.cargo_build import gunbc.cargo_execution_placement { CargoPlacement, LocalRunner, @@ -21,8 +21,9 @@ import gunbc.cargo_execution_placement { } import std.decl_ref { DeclarationRef, WholeDeclaration } import std.logic { Bool } +import std.types { FilePath, NonEmptyStr, List, String } -data interpreter_dispatch_bijection_real_roster_transport_note: String = "R1 closeout item TWO real-crate bijection receipt (gunbc#7825): executes the two #[ignore] integration tests in src/v1/stage0/tests/interpreter_dispatch_bijection_real_roster_red.rs via shell.Exec.Run with RUSTC_WRAPPER cleared — real git clone, real gunbc run main_wet regen, real cargo build -p v1-compiler on the clone. cargo.Build.Test routes through ctrl-build remote in this environment and is intentionally not used here. Claim-A compile-red siblings stay in the default local cargo test run; this transport is the falsifier_self_host_wet enrollment path for claim-B." +data interpreter_dispatch_bijection_real_roster_transport_note: String = "R1 closeout item TWO real-crate bijection receipt (gunbc#7825): executes the two #[ignore] integration tests in src/v1/stage0/tests/interpreter_dispatch_bijection_real_roster_red.rs via two sequential cargo.Build.TestWithCwdEnv calls (env -C RUSTC_WRAPPER= CTRL_BUILD_MODE=local CARGO_BUILD_JOBS=4 test ..., short-circuiting on the first failure) — real git clone, real gunbc run main_wet regen, real cargo build -p v1-compiler on the clone. Migrated off a hand-built retained_foreign multi-line bash script (set -euo pipefail; cd; export; two invocations) onto typed argv (SHELL-DAG dissolution). cargo.Build.Test (the bare, no-cwd operation) routes through ctrl-build remote in this environment and is intentionally not used here. Claim-A compile-red siblings stay in the default local cargo test run; this transport is the falsifier_self_host_wet enrollment path for claim-B." data interpreter_dispatch_bijection_real_roster_memory_envelope_note: String = "MEMORY PREDICTION (Lane D, 2026-08-06; construction pin still-bat-561 msg_e79bf117). WITNESS NEEDS: per direction — git clone --local (no target/), gunbc run main_wet on the clone (pre-built release gunbc), cold release cargo build -p v1-compiler --lib in the clone; two directions sequential so peak is max(per-direction). DOMINANT PEAK: in-clone cold rustc lib build. CONSTRUCTION: transport shell exports CARGO_BUILD_JOBS=4 before both cargo test invocations so the fleet-measured premise (jobs=4) is the executed premise — not a note beside an unenforced conditional. ANCHORS: gunbc_ci_native_bundle_batch_clamp_basis_note cgroup peak 11940978688 B (~11.1 GiB, cold cargo, jobs=4); v1 width-1 floor 10.7 GiB cgroup under 15 GiB throttle; claim_batch resolve ~2.4 GiB before shell. PREDICTED PEAK on falsifier runner slot: ~10–12 GiB cgroup, ~4–5 GiB headroom under gunbc_runner_slot_desired().memory_max (16 GiB kill / 15 GiB high; live read falsifier 31047744902 srv3-03). VERDICT: fits the declared slot under pinned jobs=4. STACKING RISK (fleet memory-tight tonight): batch-1 discovery co-residency ~5–6 GiB before batch-2 wet rows. LOCAL SIGKILL CONTROL: claim_batch --wet killed host-tree cargo test compile at 97s before clone+build (children-max-rss 2.7 GiB); same host completed direction-1 through clone+build in 346s wall — kill is not clone peak evidence. WALL ROUTED TO OPERATOR (not solved here): ~692s whole transport vs gunbc_falsifier_self_host_wet_receipt_wall_budget 600s — basis and regime below in dashboard routing; witness not shrunk." @@ -40,23 +41,19 @@ data real_roster_placement_requirement: CargoSubjectPlacementRequirement = Requi }, } -fn interpreter_dispatch_bijection_real_roster_red_shell(root: String, cargo_bin: String) -> String { - concat( - "set -euo pipefail\nexport CARGO_BUILD_JOBS=4\n", - concat( - "cd ", - concat( - root, - concat( - "\n", - concat( - concat("env RUSTC_WRAPPER= CTRL_BUILD_MODE=local CARGO_BUILD_JOBS=4 ", concat(cargo_bin, " test -p v1-compiler --test interpreter_dispatch_bijection_real_roster_red --release -- --ignored --exact w_red_real_roster_row_with_no_real_handler_arm_refuses_compile\n")), - concat("env RUSTC_WRAPPER= CTRL_BUILD_MODE=local CARGO_BUILD_JOBS=4 ", concat(cargo_bin, " test -p v1-compiler --test interpreter_dispatch_bijection_real_roster_red --release -- --ignored --exact w_red_real_handler_arm_with_no_real_roster_row_refuses_compile\n")) - ) - ) - ) - ) - ) +data real_roster_test_env: List = [ + "RUSTC_WRAPPER=", + "CTRL_BUILD_MODE=local", + "CARGO_BUILD_JOBS=4", +] + +fn real_roster_test_extra_args(exact_test_name: String) -> List { + [ + "-p", "v1-compiler", + "--test", "interpreter_dispatch_bijection_real_roster_red", + "--release", + "--", "--ignored", "--exact", exact_test_name, + ] } // ONE observation, and no probe order. The former shell named /opt/cargo/bin/cargo @@ -101,13 +98,12 @@ fn real_roster_cargo_decision() -> CargoPlacementDecision { // the clone failed, or the compile wrongly SUCCEEDED when the test requires it to refuse // were indistinguishable, so the failure could not be triaged and therefore could not be // ranked or owned. -fn real_roster_cargo_run(cargo_bin: String) -> CargoInvocationOutcome { - let root = git.Inspect.Toplevel() - let run = shell.Exec.Run( - script: retained_foreign( - body: interpreter_dispatch_bijection_real_roster_red_shell(root: root.path, cargo_bin: cargo_bin), - reason: "interpreter dispatch bijection real roster cargo integration tests" - ) +fn real_roster_cargo_test_run(root: FilePath, cargo_bin: NonEmptyStr, exact_test_name: String) -> CargoInvocationOutcome { + let run = cargo.Build.TestWithCwdEnv( + workdir: root, + cargo_bin: cargo_bin, + env: real_roster_test_env, + extra_args: real_roster_test_extra_args(exact_test_name: exact_test_name), ) if run.success { CargoInvocationPassed @@ -116,6 +112,27 @@ fn real_roster_cargo_run(cargo_bin: String) -> CargoInvocationOutcome { } } +// Two sequential invocations, short-circuiting after the first failure — the structured +// equivalent of `set -euo pipefail` chaining two commands: the second only runs when the +// first passed, and a failure reports which of the two rows it came from. +fn real_roster_cargo_run(cargo_bin: String) -> CargoInvocationOutcome { + let root = git.Inspect.Toplevel() + let first = real_roster_cargo_test_run( + root: root.path, + cargo_bin: cargo_bin as NonEmptyStr, + exact_test_name: "w_red_real_roster_row_with_no_real_handler_arm_refuses_compile", + ) + if cargo_outcome_holds(o: first) == false { + first + } else { + real_roster_cargo_test_run( + root: root.path, + cargo_bin: cargo_bin as NonEmptyStr, + exact_test_name: "w_red_real_handler_arm_with_no_real_roster_row_refuses_compile", + ) + } +} + fn run_interpreter_dispatch_bijection_real_roster_outcome() -> CargoInvocationOutcome { match real_roster_cargo_decision() { PlacementRefused { cause: c } => CargoInvocationNotAttempted { refusal: c } From 69f9364260c26cbf0f78c19cd416eab558b79475 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Thu, 20 Aug 2026 02:57:49 +0000 Subject: [PATCH 2/2] relocate_build_root_to_unique_publishing: split the state-space conflation review on #8621 (eager-crane-282): the mktemp placeholder being non-empty (an exclusivity violation -- something else wrote into a name this call believed was exclusively its own) and an ordinary move refusal (destination exists, cross-device, permissions) against a confirmed-empty placeholder were collapsed into one Bool at the binding, even though the new typed operations (shell.Remove.EmptyDirectory, shell.Move.NoReplaceDirectory) had just created the distinction. Introduces UniquePublishingRelocateOutcome (Ready | PlaceholderNotEmpty | Refused) so the caller sees the two failure states separately and reports a distinct cause string for each. The not-empty arm no longer runs the recursive-force cleanup, since rm -rf on a placeholder this call does not own would destroy whatever the other writer put there; cleanup stays on the move-refusal arm where the placeholder is confirmed empty and ours. rename_publishing_noreplace is left untouched (pre-existing, out of scope per the review). --- dag/gunbc/package_delivery.dag | 48 +++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 13 deletions(-) diff --git a/dag/gunbc/package_delivery.dag b/dag/gunbc/package_delivery.dag index ca30304651a..49ea3ee4dd6 100644 --- a/dag/gunbc/package_delivery.dag +++ b/dag/gunbc/package_delivery.dag @@ -1711,30 +1711,48 @@ fn validate_existing_codex_runtime_release( data codex_runtime_release_publish_note: String = "Publication uses a UNIQUE same-parent staging directory (mktemp -d ..publishing.XXXXXX), never a deterministic ..publishing path. Tree-identity scratch (materialized-tree.canonical) is ALWAYS outside the publishing/release tree — passed as scratch_dir — so validation cannot plant a file into the tree it is measuring. Final install is GNU mv -T (no-target-directory): equivalent to renameat2(RENAME_NOREPLACE) for directories on Linux — never nests into an existing winner. On AlreadyExists, delete the contender staging tree and validate the winner with the same external scratch." +// `emptied.success == false` and `moved.success == false` are NOT the same state (review +// on #8621): the former means the mktemp placeholder was not empty -- something else wrote +// into a name this call believed was exclusively its own, an exclusivity violation with no +// established remedy -- while the latter is an ordinary move refusal (destination exists, +// cross-device, permissions) against a placeholder this call knows is empty and its own. +// Collapsing both to one Bool, which the pre-typed shell script necessarily did (one exit +// code), is the state-space conflation DESIGN lists under recurring failure modes; the typed +// operations below create the distinction, so it is kept to the caller rather than discarded +// at the binding. The recursive-force cleanup therefore only runs on the move-refusal arm -- +// not-empty is left untouched rather than swept, since rm -rf on a placeholder this call does +// not own would destroy whatever the other writer put there. +type UniquePublishingRelocateOutcome + = UniquePublishingRelocateReady { + path: FilePath + } + | UniquePublishingPlaceholderNotEmpty + | UniquePublishingRelocateRefused + fn relocate_build_root_to_unique_publishing( build_root: FilePath, parent: FilePath, hex: String, -) -> FilePath? { +) -> UniquePublishingRelocateOutcome { let template = concat( parent as String, concat("/.", concat(hex, ".publishing.XXXXXX")), ) as FilePath let staged = shell.Mktemp.DirWithTemplate(template: template) if staged.success == false { - none + UniquePublishingRelocateRefused } else { let emptied = shell.Remove.EmptyDirectory(path: staged.path) - let moved = if emptied.success == false { - false - } else { - shell.Move.NoReplaceDirectory(source: build_root, destination: staged.path).success - } - if moved == false { - let _ = shell.Remove.RecursiveForce(path: staged.path) - none + if emptied.success == false { + UniquePublishingPlaceholderNotEmpty } else { - Present { value: staged.path } + let moved = shell.Move.NoReplaceDirectory(source: build_root, destination: staged.path) + if moved.success == false { + let _ = shell.Remove.RecursiveForce(path: staged.path) + UniquePublishingRelocateRefused + } else { + UniquePublishingRelocateReady { path: staged.path } + } } } } @@ -1814,11 +1832,15 @@ fn release_codex_runtime_bundle_immutable( parent: parent, hex: hex, ) { - Absent => + UniquePublishingPlaceholderNotEmpty => + CodexRuntimeReleaseFailed { + cause: "unique publishing staging placeholder was not empty (exclusivity violation, not swept)" as NonEmptyStr, + } + UniquePublishingRelocateRefused => CodexRuntimeReleaseFailed { cause: "unique publishing staging relocate refused" as NonEmptyStr, } - Present { value: publishing } => + UniquePublishingRelocateReady { path: publishing } => if write_codex_runtime_receipt_sidecar( release_root: publishing, receipt_identity: receipt.receipt_identity,