Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions dag/gunbc/gen_one_executable_keep_seed_growth.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
module gunbc.gen_one_executable_keep_seed_growth

import gunbc.roadmap_model { RoadmapNodeId }
import gunbc.seed_growth { SeedGrowthJustification }
import std.decl_ref { DeclarationRef, WholeDeclaration }

data gen_one_executable_keep_seed_growth_justification: SeedGrowthJustification = SeedGrowthJustification {
hand_authored_declarations: [
DeclarationRef {
module_path: "v1_compiler.cli_run.native_lane_runner",
decl_name: "keep_generation_one_executable",
field: WholeDeclaration
}
],

reason: "Generation two needs a surviving generation-one executable. Generation two is the BUILT v2.cli.compile_cli binary emitting the v2.compiler.compile closure, and before this declaration the only place that binary existed was the run's PrivateProbeRoot, which removes itself on drop, so no generation-one artifact outlived the //gunbc/instruments:v2-native-cli run that built it and nothing could invoke it as a program. The declaration copies the executable out of the probe root under its own sha256, re-hashes the copy against the identity the run recorded and refuses on any mismatch, then lets the root drop as designed. The root is not retained: its per-run cargo target dir has no consumer once the copy is verified. It prints the kept path together with the binary, closure and seed identities as one provenance record. It performs no part of the generation-two emission and admits nothing, so the seed still does not stand in for the successor step. WHO CONSUMES THE KEPT EXECUTABLE (DESIGN section 3c), stated as a declared frontier because the consumer does not land in this change: the generation-two emission of the self-host closure frontier lane (dashboard node adhoc-a1bbb2a6-2d3), which invokes the kept file as `<kept> emit --entry v2.compiler.compile --source-root dag --source-root src/v2` and records its termination against the kept path and binary identity this declaration prints. That invocation has already run once by hand on srv1 at gunbc#12182's head and produced the lane's first gen-two refusal, but a manual run is a receipt, not a modeled consumer. TRIGGER FOR THE FRONTIER: it becomes consumed by execution when that lane's door change (the census/closure-scoped ingest split, PR-c of that lane) lands the gen-two step as an instrument that spawns this path. If that lane closes without doing so, this declaration has no consumer and is deleted rather than kept. WHY A THROWAWAY IS ADMITTED (DESIGN section 6 scaffold presumption, section 5 scaffold admission): this is deliberately not terminal. It is admitted under the operator's seed Rust policy for this lane (brief of 2026-09-23: seed Rust only if very urgent and blocking major progress, and paired in the same program with the work to get off it). The admission is recorded outside this diff, in that brief and in the v2 Foundation manager's review of the diff, and not by this row's say-so. The pairing is the trigger below.",

owning_dissolution_lane: "v1-hand-queue-drain" as RoadmapNodeId,

trigger: "Delete this declaration when the v2.cli.compile_cli door writes its own crate, that is, when the generation-one executable can assemble and build an emitted closure as a program, without the seed's write_probe_crate, so that generation one is a named, invocable artifact instead of something recovered from a seed probe root. WHAT DOES NOT RETIRE IT: moving the copy to another host file; keeping the probe root through PrivateProbeRoot retain instead of copying; or the door emitting a closure's text while the seed still assembles the crate. Each of those leaves the seed as the only producer of the generation-one executable.",

current_boundary: "src/v1/stage0/src/cli_run/native_lane_runner.rs keep_generation_one_executable, called once from run_v2_native_cli after walk_cli_door, behind gunbc test //gunbc/instruments:v2-native-cli"
}
2 changes: 2 additions & 0 deletions dag/gunbc/seed_growth_admission.dag
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import gunbc.regen_digest_spelling_seed_growth { regen_digest_spelling_seed_grow
import gunbc.qualified_pipe_callee_seed_growth { qualified_pipe_callee_seed_growth_justification }
import gunbc.shared_fill_attribution_seed_growth { shared_fill_attribution_seed_growth_justification }
import gunbc.source_root_eval_driver_seed_growth { source_root_eval_driver_seed_growth_justification }
import gunbc.gen_one_executable_keep_seed_growth { gen_one_executable_keep_seed_growth_justification }
import gunbc.roadmap_authority { observation_scoped_run_seed_growth_justification }
import gunbc.target_invocation_seed_growth { target_invocation_seed_growth_justification }
import gunbc.bootstrap_operation_seed_growth {
Expand Down Expand Up @@ -267,6 +268,7 @@ fn seed_growth_justification_roster() -> List<SeedGrowthJustification> {
claim_batch_entry_closure_preflight_seed_growth_justification,
shared_fill_attribution_seed_growth_justification,
source_root_eval_driver_seed_growth_justification,
gen_one_executable_keep_seed_growth_justification,
census_memo_seed_growth_justification,
kind_reflection_seed_growth_justification,
typed_module_store_seed_growth_justification,
Expand Down
53 changes: 53 additions & 0 deletions src/v1/stage0/src/cli_run/native_lane_runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1347,6 +1347,9 @@ pub struct V2NativeCliHeld {
/// spoke of "the one argument the positive control supplies" -- both wrong since that arm became
/// an expecting-red probe, and corrected rather than left standing (review 69621).
pub door_refusal_exit_status: i64,
/// Where the generation-one executable was kept (`keep_generation_one_executable`), named by
/// its own sha256, carried so the instrument's receipt names the file generation two invokes.
pub generation_one_executable: String,
}

/// THE V2-EXCLUSIVE CLI, EMITTED AND BUILT. This is the door the self-host step stops in front of.
Expand Down Expand Up @@ -1762,6 +1765,54 @@ fn walk_cli_door(binary: &Path, workspace: &Path) -> Result<(i64, usize, i64), S
Ok((door_exit_status, emitted_bytes, refusal_status))
}

/// THE GENERATION-ONE EXECUTABLE OUTLIVES THE RUN, because generation two is that executable
/// emitting `v2.compiler.compile` and nothing else may stand in for it. The probe root is NOT
/// retained: once the executable is copied out and its copy re-hashes to the identity the run
/// recorded, the root and its per-run cargo target dir have no further consumer, so it drops as
/// `PrivateProbeRoot` is designed to. The copy is named by its own sha256, so the path names the
/// bytes that ran, and the printed line carries the closure and seed identities beside it so the
/// provenance is one record. Declared at `gunbc.gen_one_executable_keep_seed_growth`; it
/// dissolves when the door writes its own crate.
fn keep_generation_one_executable(prepared: &EmittedPreparation) -> Result<PathBuf, String> {
let base = prepared
._probe_root
.path()
.parent()
.ok_or_else(|| {
format!(
"V2-NATIVE REFUSAL cause=GenOneExecutableNotKept — probe root {} has no parent",
prepared._probe_root.display()
)
})?
.to_path_buf();
let kept = base.join(format!(
"v2-native-cli-gen-one-{}",
prepared.binary_identity
));
std::fs::copy(&prepared.binary_path, &kept).map_err(|e| {
format!(
"V2-NATIVE REFUSAL cause=GenOneExecutableNotKept — copy {} -> {}: {e}",
prepared.binary_path.display(),
kept.display()
)
})?;
if sha256_file(&kept)? != prepared.binary_identity {
return Err(format!(
"V2-NATIVE REFUSAL cause=GenOneExecutableNotKept — {} does not hash to {}",
kept.display(),
prepared.binary_identity
));
}
eprintln!(
"v2-native-cli: generation-one executable kept path={} binary_sha256={} closure_identity={} seed_sha256={}",
kept.display(),
prepared.binary_identity,
prepared.closure_identity,
prepared.seed_identity
);
Ok(kept)
}

pub fn run_v2_native_cli(source_roots: &[String]) -> Result<V2NativeCliHeld, String> {
let started = std::time::Instant::now();
eprintln!(
Expand All @@ -1781,6 +1832,7 @@ pub fn run_v2_native_cli(source_roots: &[String]) -> Result<V2NativeCliHeld, Str
// green — a door that accepts everything is a broken instrument, not a broken build.
let (door_exit_status, door_emitted_bytes, door_refusal_exit_status) =
walk_cli_door(&prepared.binary_path, &super::process_workspace_root())?;
let generation_one_executable = keep_generation_one_executable(&prepared)?;
// The counters are carried and not adjudicated here, on the same rule `run_self_host` follows:
// a non-clean build is an observation that did not hold, a refusal above is the subject never
// having been reached, and the instrument seam is the one place that knows the difference.
Expand All @@ -1793,6 +1845,7 @@ pub fn run_v2_native_cli(source_roots: &[String]) -> Result<V2NativeCliHeld, Str
door_exit_status,
door_emitted_bytes: door_emitted_bytes as i64,
door_refusal_exit_status,
generation_one_executable: generation_one_executable.display().to_string(),
})
}

Expand Down
4 changes: 3 additions & 1 deletion src/v1/stage0/src/target_invocation_host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1019,7 +1019,8 @@ fn run_v2_native_cli(source_roots: &[String]) -> InvocationOutcome {
},
message: format!(
"v2-native-cli: closure={} binary={} seed={} exit_status={} warning_count={} \
door_exit_status={} door_emitted_bytes={} door_refusal_exit_status={}",
door_exit_status={} door_emitted_bytes={} door_refusal_exit_status={} \
generation_one_executable={}",
held.closure_identity,
held.binary_identity,
held.seed_identity,
Expand All @@ -1028,6 +1029,7 @@ fn run_v2_native_cli(source_roots: &[String]) -> InvocationOutcome {
held.door_exit_status,
held.door_emitted_bytes,
held.door_refusal_exit_status,
held.generation_one_executable,
),
},
Err(cause) => InvocationOutcome {
Expand Down