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
49 changes: 49 additions & 0 deletions dag/test/claim/required_regen_admission_witness_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module test.claim.required_regen_admission_witness
import v2.workflow.required_regen {
CommittedNotEmitted,
EmittedNotCommitted,
EmittedNotCommittedShadowsHandMaintained,
MirrorMissingShadowsHandMaintainedSource,
EmptyCommittedPopulation,
EmptyEmitResult,
CommittedMirrorNoLongerEmitted,
Expand Down Expand Up @@ -198,6 +200,53 @@ test fn witness_new_surface_alone_still_refuses() -> Bool {
}
}

// THE DAMAGING-REMEDY CONTROL, and it has two halves that must hold TOGETHER.
// An emitted basename that collides with hand-authored source under a hand-maintained directory
// refuses under its OWN cause, naming the directory -- because the two remedies attached to
// MirrorMissingForEmittedSurface (install the mirror, or investigate an invented surface) both
// destroy hand-authored code when applied to this class.
// The RED half is the second assertion: a genuine orphan mirror in the SAME run must STILL refuse
// as MirrorMissingForEmittedSurface. A fix that silenced the collision by excluding it from the
// compared population would take the orphan with it, and this test would go green on a wall that
// no longer stands. Separation, not membership: neither path may appear under the other's cause.
test fn witness_hand_maintained_collision_refuses_under_its_own_remedy() -> Bool {
match required_regen_sync_admission(
generated_outcomes: [
SurfaceMatches { relative_path: "std_algebra.rs" },
EmittedNotCommitted { relative_path: "brand_new_surface.rs" },
EmittedNotCommittedShadowsHandMaintained {
relative_path: "shared_fill.rs",
hand_maintained_homes: ["cli_run"]
},
EmittedNotCommittedShadowsHandMaintained {
relative_path: "mod.rs",
hand_maintained_homes: ["cli_run", "module_path_index"]
}
],
hand_outcomes: [],
authority_digest: "fnv1a64:deadbeefdeadbeef",
planned_surfaces: 4,
executed_surfaces: 4
) {
RequiredRegenSyncRefused { refusals } =>
(refusals |> any(r => match r {
MirrorMissingShadowsHandMaintainedSource { entries } =>
(entries |> any(e => e == "shared_fill.rs (hand-maintained under cli_run)"))
&& (entries |> any(e =>
e == "mod.rs (hand-maintained under cli_run, module_path_index)"))
&& !(entries |> any(e => e == "brand_new_surface.rs"))
_ => false
}))
&& (refusals |> any(r => match r {
MirrorMissingForEmittedSurface { paths } =>
(paths |> any(p => p == "brand_new_surface.rs"))
&& !(paths |> any(p => p == "shared_fill.rs"))
_ => false
}))
RequiredRegenSyncRunnable { attempt: _ } => false
}
}

test fn witness_hand_unverifiable_refuses_naming_the_entry() -> Bool {
match required_regen_sync_admission(
generated_outcomes: [SurfaceMatches { relative_path: "std_algebra.rs" }],
Expand Down
110 changes: 104 additions & 6 deletions src/v1/stage0/src/required_regen_host.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Host realization for `v2.workflow.required_regen` — committed seed vs fresh emit.

use serde::Serialize;
use std::collections::{BTreeSet, HashMap};
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::fs;
use std::io::Write;
use std::path::Path;
Expand Down Expand Up @@ -505,7 +505,10 @@ pub fn run_required_regen_fixed_point(
return Err("refusal: fixed-point emit produced zero files".to_string());
}
let emitted_basenames = generated_basenames_from_emit(&emitted);
if let Some(reason) = validate_compared_populations(&committed_basenames, &emitted_basenames) {
let hand_dir_shadows = hand_maintained_dir_shadows(&workspace.join("src/v1/stage0/src"))?;
if let Some(reason) =
validate_compared_populations(&committed_basenames, &emitted_basenames, &hand_dir_shadows)
{
return Err(reason);
}
let pass2 = tree_digest_from_map(&emitted, &committed_basenames)?;
Expand Down Expand Up @@ -629,7 +632,10 @@ fn adjudicate_generated_surface(
emitted_basenames: &[String],
) -> Result<GeneratedSurfaceAdjudicated, String> {
let committed = committed_generated_basenames(stage0_src)?;
if let Some(reason) = validate_compared_populations(&committed, emitted_basenames) {
let hand_dir_shadows = hand_maintained_dir_shadows(stage0_src)?;
if let Some(reason) =
validate_compared_populations(&committed, emitted_basenames, &hand_dir_shadows)
{
return Ok(GeneratedSurfaceAdjudicated::Refused { reason });
}
let sync = compare_generated_surfaces(stage0_src, emitted, &committed)?;
Expand Down Expand Up @@ -841,7 +847,82 @@ fn committed_generated_basenames(stage0_src: &Path) -> Result<Vec<String>, Strin
Ok(names.into_iter().collect())
}

fn validate_compared_populations(committed: &[String], emitted: &[String]) -> Option<String> {
/// The only seam where `HAND_MAINTAINED_STAGE0_DIRS` reaches the population comparison, and it
/// CLASSIFIES a refusal rather than excluding anything from one.
///
/// Both compared populations key on basename, and the committed walk enumerates only the top level
/// of the stage0 crate, so a file living inside a hand-maintained DIRECTORY is invisible to it. An
/// emitted basename equal to one of those files therefore lands in `emitted_not_committed`, where
/// the two remedies on offer -- install the produced mirror, or investigate an emitter that
/// invented a surface -- BOTH destroy hand-authored code: installing overwrites it with generated
/// bytes, deleting removes it. This map lets that population be named under its own cause with the
/// remedy that actually applies (de-collide the module name).
///
/// IT DOES NOT EXCLUDE, AND THAT IS THE WHOLE DESIGN. Teaching `is_hand_maintained_path` about the
/// directory list would drop the colliding path out of the compared population entirely, which
/// silently stops comparing a genuinely generated surface -- a wrong refusal traded for no
/// refusal. Same failure as making the committed walk descend, entered from the other side.
///
/// ZERO EXPOSURE, stated so this is not read as repairing a live defect. Emitted Rust filenames are
/// flat by construction (`v1.compiler.emit_core_support` `module_to_filename` is split(".") joined
/// with "_" under `rust_source_root()`), so the emitter cannot write into a hand-maintained
/// directory; the collision is reachable only by authoring a module whose bare name equals one of
/// those files. Measured 2026-08-22: zero collisions in the corpus, required-regen green on main
/// at 90986d19469, and no upstream guard was found that would refuse such a module name (the
/// nearest candidates, `gunbc.stage0_rust_source_lifecycle_scaffold`
/// `classified_residue_disjoint_holds` and the generated/hand disposition joins beside it, are
/// scoped to top-level stage0 paths and cannot see a subdirectory file).
fn hand_maintained_dir_shadows(stage0_src: &Path) -> Result<BTreeMap<String, Vec<String>>, String> {
let mut shadows = BTreeMap::new();
for dir_name in HAND_MAINTAINED_STAGE0_DIRS {
let dir = stage0_src.join(dir_name);
if !dir.is_dir() {
continue;
}
collect_dir_shadows(&dir, dir_name, &mut shadows)?;
}
// Sorted so the refusal text is a function of the collision, not of the roster's authoring
// order: two clones must print the same remedy for the same tree.
for homes in shadows.values_mut() {
homes.sort();
}
Ok(shadows)
}

fn collect_dir_shadows(
dir: &Path,
home: &str,
shadows: &mut BTreeMap<String, Vec<String>>,
) -> Result<(), String> {
for entry in fs::read_dir(dir).map_err(|e| format!("read dir {}: {e}", dir.display()))? {
let entry = entry.map_err(|e| format!("read dir entry under {}: {e}", dir.display()))?;
let path = entry.path();
if path.is_dir() {
collect_dir_shadows(&path, home, shadows)?;
continue;
}
if let Some(basename) = path.file_name().and_then(|n| n.to_str()) {
if is_compared_generated_basename(basename) {
// EVERY HOME, NOT THE LAST ONE SEEN. `insert` here was last-write-wins, so one
// basename hand-authored under two hand-maintained directories -- `mod.rs` being
// the obvious candidate -- refused while naming only one of them, sending the
// author to the wrong file. Authority for the list shape:
// `v2.workflow.required_regen` `EmittedNotCommittedShadowsHandMaintained`.
let homes = shadows.entry(basename.to_string()).or_default();
if !homes.iter().any(|h| h == home) {
homes.push(home.to_string());
}
}
}
}
Ok(())
}

fn validate_compared_populations(
committed: &[String],
emitted: &[String],
hand_dir_shadows: &BTreeMap<String, Vec<String>>,
) -> Option<String> {
if committed.is_empty() {
return Some("refusal: committed generated population is empty".to_string());
}
Expand All @@ -851,9 +932,17 @@ fn validate_compared_populations(committed: &[String], emitted: &[String]) -> Op
let committed_set: BTreeSet<&str> = committed.iter().map(String::as_str).collect();
let emitted_set: BTreeSet<&str> = emitted.iter().map(String::as_str).collect();
let mut emitted_not_committed = Vec::new();
let mut shadowing_hand_maintained = Vec::new();
for name in emitted {
if !committed_set.contains(name.as_str()) {
emitted_not_committed.push(name.clone());
if committed_set.contains(name.as_str()) {
continue;
}
match hand_dir_shadows.get(name.as_str()) {
Some(homes) => shadowing_hand_maintained.push(format!(
"{name} (hand-maintained under {})",
homes.join(", ")
)),
None => emitted_not_committed.push(name.clone()),
}
}
let mut committed_not_emitted = Vec::new();
Expand Down Expand Up @@ -885,6 +974,15 @@ fn validate_compared_populations(committed: &[String], emitted: &[String]) -> Op
"refusal: committed mirror is no longer emitted — {committed_not_emitted:?}; the emitter stopped producing these surfaces, so either the authority that emitted them was removed on purpose (delete the committed mirror) or it regressed (restore it) — do NOT install anything for this class"
));
}
if !shadowing_hand_maintained.is_empty() {
// A THIRD CAUSE BECAUSE THE OTHER TWO REMEDIES DAMAGE THIS CLASS. Authority:
// `v2.workflow.required_regen` `MirrorMissingShadowsHandMaintainedSource`. The refusal is
// not softer than the one above -- the line still stops -- it is the same stop pointed at
// the move that actually resolves the state.
reasons.push(format!(
"refusal: emitted surface collides with hand-maintained source — {shadowing_hand_maintained:?}; the emitted basename addresses a file that is hand-authored under a hand-maintained directory, so BOTH remedies for a missing mirror would damage it (installing overwrites hand-authored code with generated bytes; deleting destroys it). Rename the emitting module so its basename no longer collides, or move the hand-maintained file — do NOT install anything for this class"
));
}
if reasons.is_empty() {
None
} else {
Expand Down
104 changes: 99 additions & 5 deletions src/v2/workflow/required_regen.dag
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ type RegenSurfaceOutcome
}
| EmittedNotCommitted { relative_path: String }
| CommittedNotEmitted { relative_path: String }
| EmittedNotCommittedShadowsHandMaintained {
relative_path: String
hand_maintained_homes: List<String>
}

type HandMaintainedOutcome
= HandMatches { filename: String }
Expand Down Expand Up @@ -68,9 +72,36 @@ type HandMaintainedOutcome
// the repair before it buys is that the first branch is now ACTIONABLE — the bytes exist on
// disk instead of only inside the process refusing — and the second branch stays refused, which
// is the arm that matters.
// A FOURTH POPULATION STATE, SPLIT OUT OF THE THIRD FOR THE SAME REASON THE THIRD WAS SPLIT OUT
// OF THE SECOND -- and this one is about the REMEDY, not the diagnosis.
// `MirrorMissingForEmittedSurface` offers exactly two moves: install the produced mirror, or
// investigate an emitter that invented a surface. Both are correct for a genuine orphan and both
// DAMAGE hand-authored source. The compared populations key on BASENAME, and the committed side
// enumerates only the top level of the stage0 crate, so an emitted basename that collides with a
// file living inside a hand-maintained DIRECTORY (`HAND_MAINTAINED_STAGE0_DIRS`) lands in the
// emitted-not-committed set with those two remedies attached: installing overwrites hand-authored
// code with generated bytes, deleting destroys it. The only non-damaging response left to an
// author who reads the refusal and believes it is to ignore the wall -- which is how a correct
// wall decays into advice, fastest for the authors who take it most seriously.
//
// SO THE COLLISION REFUSES UNDER ITS OWN NAME AND ITS OWN REMEDY (de-collide the module name),
// AND IT IS NOT SILENCED. Excluding the colliding path from the compared population instead --
// by teaching the hand-maintained predicate about the directory list -- would drop a genuinely
// generated surface out of the comparison entirely, which is the false green this split exists
// to avoid: a wrong refusal replaced by no refusal.
//
// ZERO EXPOSURE TODAY, AND THE REASON IS WORTH RECORDING because it is what bounds this variant.
// Emitted Rust filenames are FLAT by construction (`v1.compiler.emit_core_support`
// `module_to_filename` is split(".") |> join("_") under `rust_source_root()`), so the emitter can
// never write INTO a hand-maintained directory; the collision is reachable only through a module
// authored with a bare name equal to one of those directories' files. Measured 2026-08-22: zero
// such collisions in the corpus, and required-regen green on main at 90986d19469
// (first_generation_equal=true planned=132 executed=132). The variant is a wall for a state one
// .dag file away, not a repair of an observed failure.
type RequiredRegenRefusal
= GeneratedDrift { paths: List<String> }
| MirrorMissingForEmittedSurface { paths: List<String> }
| MirrorMissingShadowsHandMaintainedSource { entries: List<String> }
| CommittedMirrorNoLongerEmitted { paths: List<String> }
| CompileRefused { reason: String }
| HandUnverifiableRefused { entries: List<String> }
Expand Down Expand Up @@ -120,6 +151,7 @@ fn collect_byte_drift_paths(
SurfaceDrifted { relative_path: path } => Cons { head: path, tail: acc }
EmittedNotCommitted { relative_path: _ } => acc
CommittedNotEmitted { relative_path: _ } => acc
EmittedNotCommittedShadowsHandMaintained { relative_path: _, hand_maintained_homes: _ } => acc
SurfaceMatches { relative_path: _ } => acc
}
}
Expand All @@ -132,6 +164,7 @@ fn collect_emitted_not_committed_paths(
SurfaceDrifted { relative_path: _ } => acc
EmittedNotCommitted { relative_path: path } => Cons { head: path, tail: acc }
CommittedNotEmitted { relative_path: _ } => acc
EmittedNotCommittedShadowsHandMaintained { relative_path: _, hand_maintained_homes: _ } => acc
SurfaceMatches { relative_path: _ } => acc
}
}
Expand All @@ -144,6 +177,7 @@ fn collect_committed_not_emitted_paths(
SurfaceDrifted { relative_path: _ } => acc
EmittedNotCommitted { relative_path: _ } => acc
CommittedNotEmitted { relative_path: path } => Cons { head: path, tail: acc }
EmittedNotCommittedShadowsHandMaintained { relative_path: _, hand_maintained_homes: _ } => acc
SurfaceMatches { relative_path: _ } => acc
}
}
Expand All @@ -157,6 +191,54 @@ fn hand_is_unverifiable(o: HandMaintainedOutcome) -> Bool {
}
}

// EVERY HOME, NOT THE LAST ONE SEEN. The homes are a LIST because one basename can be
// hand-authored under more than one hand-maintained directory — `mod.rs` is the obvious
// candidate, being the name most likely to appear in two module directories at once. A carrier
// holding a single home would make the extra ones unrepresentable, so the host's map would have
// resolved the collision by last-write-wins and the refusal would name ONE directory while
// silently dropping the others. That refusal still fires and still launders nothing, but it
// sends an author to the wrong file — which is the failure this whole variant exists to prevent,
// one notch quieter (finding: smart-ram-730 on #8867).
//
// The entry renders as "path (hand-maintained under A, B)" so the refusal names both halves of
// the collision: an author cannot act on the basename alone, because the whole point is that ONE
// basename addresses several different files.
fn render_homes(acc: String, home: String) -> String {
if acc == "" {
home
} else {
concat(acc, concat(", ", home))
}
}

fn collect_shadowing_entries(
acc: List<String>,
o: RegenSurfaceOutcome
) -> List<String> {
match o {
SurfaceDrifted { relative_path: _ } => acc
EmittedNotCommitted { relative_path: _ } => acc
CommittedNotEmitted { relative_path: _ } => acc
EmittedNotCommittedShadowsHandMaintained {
relative_path: path,
hand_maintained_homes: homes
} => Cons {
head: concat(
path,
concat(
" (hand-maintained under ",
concat(
fold_list(xs: homes, empty: "", cons: fn(a, h) { render_homes(acc: a, home: h) }),
")"
)
)
),
tail: acc
}
SurfaceMatches { relative_path: _ } => acc
}
}

fn collect_hand_unverifiable(
acc: List<String>,
o: HandMaintainedOutcome
Expand Down Expand Up @@ -213,6 +295,11 @@ fn required_regen_sync_admission(
empty: no_string_paths,
cons: fn(acc, o) { collect_emitted_not_committed_paths(acc: acc, o: o) }
)
let shadowing_entries = fold_list(
xs: generated_outcomes,
empty: no_string_paths,
cons: fn(acc, o) { collect_shadowing_entries(acc: acc, o: o) }
)
let unemitted_mirror_paths = fold_list(
xs: generated_outcomes,
empty: no_string_paths,
Expand All @@ -231,11 +318,18 @@ fn required_regen_sync_admission(
no_regen_refusals
}
),
right: if length(xs: unemitted_mirror_paths) > 0 {
[CommittedMirrorNoLongerEmitted { paths: unemitted_mirror_paths }]
} else {
no_regen_refusals
}
right: list_append(
left: if length(xs: unemitted_mirror_paths) > 0 {
[CommittedMirrorNoLongerEmitted { paths: unemitted_mirror_paths }]
} else {
no_regen_refusals
},
right: if length(xs: shadowing_entries) > 0 {
[MirrorMissingShadowsHandMaintainedSource { entries: shadowing_entries }]
} else {
no_regen_refusals
}
)
)
if length(xs: population_refusals) > 0 {
return RequiredRegenSyncRefused { refusals: population_refusals }
Expand Down