From f11b90c1b65684cb787810966968c5ff8bd28937 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Thu, 28 May 2026 23:40:36 +0000 Subject: [PATCH 01/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 2 +- src/v3/compiler/Cargo.toml | 4 + .../src/bin/detect_ci_affected_components.rs | 115 ++++++++++++++++++ src/v3/compiler/src/lib.rs | 1 + .../compiler/src/v4_ci_component_affected.rs | 111 +++++++++++++++++ .../claim/workflow/ci_component_affected.dag | 56 +++++++++ src/v4/workflow/ci.dag | 86 ++++++++++++- 7 files changed, 372 insertions(+), 3 deletions(-) create mode 100644 src/v3/compiler/src/bin/detect_ci_affected_components.rs create mode 100644 src/v3/compiler/src/v4_ci_component_affected.rs create mode 100644 src/v4/test/claim/workflow/ci_component_affected.dag diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dbb6190205b..eaad791ac6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,7 +83,7 @@ jobs: run: git fetch origin main:refs/remotes/origin/main - name: Detect affected components id: detect - run: bash scripts/detect-affected-components.sh "${{ github.event_name }}" "$GITHUB_OUTPUT" + run: cargo run -p v3-compiler --bin detect-ci-affected-components -- "${{ github.event_name }}" "$GITHUB_OUTPUT" ci: if: github.event.pull_request.draft != true needs: [affected] diff --git a/src/v3/compiler/Cargo.toml b/src/v3/compiler/Cargo.toml index bf5a8cbaab3..fe72eb7f89f 100644 --- a/src/v3/compiler/Cargo.toml +++ b/src/v3/compiler/Cargo.toml @@ -93,3 +93,7 @@ path = "src/bin/r1c_e_emit_gates.rs" [[bin]] name = "gunbc-ci" path = "src/bin/gunbc_ci.rs" + +[[bin]] +name = "detect-ci-affected-components" +path = "src/bin/detect_ci_affected_components.rs" diff --git a/src/v3/compiler/src/bin/detect_ci_affected_components.rs b/src/v3/compiler/src/bin/detect_ci_affected_components.rs new file mode 100644 index 00000000000..4c85154b342 --- /dev/null +++ b/src/v3/compiler/src/bin/detect_ci_affected_components.rs @@ -0,0 +1,115 @@ +// Host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (T-24). +// Replaces scripts/detect-affected-components.sh — path buckets live in ci.dag only. +#![allow(clippy::disallowed_macros)] + +use std::io::Write; +use std::process::{Command, ExitCode}; +use std::{env, fs, io}; + +use v3_compiler::v4_ci_component_affected::ci_component_affected_from_changed_paths; + +fn usage() -> ! { + eprintln!( + "usage: detect-ci-affected-components \n\ + event_name: pull_request | push\n\ + output_file: GitHub Actions GITHUB_OUTPUT path" + ); + std::process::exit(2); +} + +fn diff_range(event_name: &str) -> &'static str { + if event_name == "pull_request" { + "origin/main...HEAD" + } else { + "HEAD~1..HEAD" + } +} + +fn git_changed_paths(range: &str) -> Vec { + let output = Command::new("git") + .args(["diff", "--name-only", range]) + .output(); + match output { + Ok(out) if out.status.success() => String::from_utf8_lossy(&out.stdout) + .lines() + .filter(|line| !line.is_empty()) + .map(str::to_string) + .collect(), + Ok(out) => { + eprintln!( + "warning: git diff --name-only {range} exited {}; treating as no changes", + out.status + ); + Vec::new() + } + Err(e) => { + eprintln!("warning: git diff failed ({e}); treating as no changes"); + Vec::new() + } + } +} + +fn write_github_output(path: &str, flags: v3_compiler::v4_ci_component_affected::CiComponentAffected) -> io::Result<()> { + let mut file = fs::OpenOptions::new().append(true).open(path)?; + writeln!(file, "v2={}", flags.v2)?; + writeln!(file, "v3={}", flags.v3)?; + writeln!(file, "v4={}", flags.v4)?; + writeln!(file, "workflow_policy={}", flags.workflow_policy)?; + Ok(()) +} + +fn main() -> ExitCode { + let mut args = env::args().skip(1); + let event_name = args.next().unwrap_or_else(|| usage()); + let output_file = args.next().unwrap_or_else(|| usage()); + if args.next().is_some() { + usage(); + } + + let range = diff_range(event_name.as_str()); + let changed = git_changed_paths(range); + + eprintln!("Changed files in {range}:"); + if changed.is_empty() { + eprintln!(" (none detected)"); + } else { + for path in &changed { + eprintln!(" {path}"); + } + } + eprintln!(); + + let flags = ci_component_affected_from_changed_paths(changed.iter().map(String::as_str)); + + eprintln!( + "v2 affected: {}", + if flags.v2 { "yes" } else { "no (skipping v2 fixed-point)" } + ); + eprintln!( + "v3 affected: {}", + if flags.v3 { + "yes" + } else { + "no (skipping v3 CI per freeze 2026-05-15)" + } + ); + eprintln!( + "v4 affected: {}", + if flags.v4 { + "yes (running v2→v4 bootstrap viability test)" + } else { + "no (skipping v4 bootstrap test)" + } + ); + eprintln!( + "workflow_policy (Gate #103 surface): {}", + if flags.workflow_policy { "yes" } else { "no" } + ); + + if let Err(e) = write_github_output(&output_file, flags) { + eprintln!("error: write {output_file}: {e}"); + return ExitCode::from(1); + } + + ExitCode::SUCCESS +} diff --git a/src/v3/compiler/src/lib.rs b/src/v3/compiler/src/lib.rs index 4eee9d02500..d20f8d7343e 100644 --- a/src/v3/compiler/src/lib.rs +++ b/src/v3/compiler/src/lib.rs @@ -4098,6 +4098,7 @@ pub mod lens_unused_parameters { /// DB-8 / m1_3 / R1C-E: shared `PROGRAM_FIXTURES` + reflected harness table. pub mod emit_rust_roundtrip_fixtures; pub mod gunbc_ci; +pub mod v4_ci_component_affected; pub mod post_emit_verifier; pub mod r1c_e_gates; pub mod test_runner; diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs new file mode 100644 index 00000000000..56b6d2efb4a --- /dev/null +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -0,0 +1,111 @@ +//! v4 `workflow/ci.dag` component affected-set — host transport for GitHub Actions. +//! +//! **Authority:** `src/v4/workflow/ci.dag` (`ci_component_affected_from_git_diff` and +//! `ci_changed_path_affects_*`). This module is the CI runner projection only; path buckets +//! must not be duplicated in workflow YAML (gate #103). + +/// Structural mirror of `CiComponentAffected` in `src/v4/workflow/ci.dag`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CiComponentAffected { + pub v2: bool, + pub v3: bool, + pub v4: bool, + pub workflow_policy: bool, +} + +/// Map `git diff --name-only` paths to component flags (same semantics as `ci.dag`). +pub fn ci_component_affected_from_changed_paths<'a, I>(changed: I) -> CiComponentAffected +where + I: IntoIterator, +{ + let mut out = CiComponentAffected { + v2: false, + v3: false, + v4: false, + workflow_policy: false, + }; + for path in changed { + if ci_changed_path_affects_v2(path) { + out.v2 = true; + } + if ci_changed_path_affects_v3(path) { + out.v3 = true; + } + if ci_changed_path_affects_v4(path) { + out.v4 = true; + } + if ci_changed_path_affects_workflow_policy(path) { + out.workflow_policy = true; + } + } + out +} + +pub fn ci_changed_path_affects_v2(path: &str) -> bool { + path.starts_with("src/v2/") || path == "Cargo.toml" || path == "Cargo.lock" +} + +pub fn ci_changed_path_affects_v3(path: &str) -> bool { + path.starts_with("src/v3/") || path.starts_with("dsl/") +} + +pub fn ci_changed_path_affects_v4(path: &str) -> bool { + path.starts_with("src/v4/") + || path.starts_with("fixtures/v4-mvp1/") + || path.starts_with("scripts/v4-mvp1") + || path.starts_with("scripts/v4-m1") + || path.starts_with("scripts/v4-testclaim-") + || path.starts_with("dsl/std/") + || path == "Cargo.toml" + || path == "Cargo.lock" +} + +pub fn ci_changed_path_affects_workflow_policy(path: &str) -> bool { + path.starts_with(".github/workflows/") + || path.starts_with("src/v4/workflow/ci") + || path.starts_with("src/v3/compiler/src/v4_ci_component_affected") + || path.starts_with("src/v3/compiler/src/bin/detect_ci_affected_components") + || path.starts_with("scripts/check-workflow-path-regex-inventory") + || path.starts_with("scripts/workflow-path-regex-forbidden-substrings") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn v2_workspace_deps_without_src_v2() { + assert!(ci_changed_path_affects_v2("Cargo.lock")); + assert!(!ci_changed_path_affects_v3("Cargo.lock")); + assert!(ci_changed_path_affects_v4("Cargo.lock")); + } + + #[test] + fn v3_freeze_ignores_cargo_toml_for_v3_only() { + assert!(!ci_changed_path_affects_v3("Cargo.toml")); + assert!(ci_changed_path_affects_v3("src/v3/compiler/src/lib.rs")); + assert!(ci_changed_path_affects_v3("dsl/std/node.dag")); + } + + #[test] + fn workflow_policy_includes_modeled_ci_authority() { + assert!(ci_changed_path_affects_workflow_policy( + "src/v4/workflow/ci.dag" + )); + assert!(ci_changed_path_affects_workflow_policy( + ".github/workflows/ci.yml" + )); + } + + #[test] + fn aggregate_fixture_matches_shell_script_buckets() { + let flags = ci_component_affected_from_changed_paths([ + "src/v4/workflow/ci.dag", + "docs/unrelated.md", + ]); + assert!(!flags.v2); + assert!(!flags.v3); + assert!(flags.v4); + assert!(flags.workflow_policy); + } +} diff --git a/src/v4/test/claim/workflow/ci_component_affected.dag b/src/v4/test/claim/workflow/ci_component_affected.dag new file mode 100644 index 00000000000..5e2c0114700 --- /dev/null +++ b/src/v4/test/claim/workflow/ci_component_affected.dag @@ -0,0 +1,56 @@ +// src/v4/test/claim/workflow/ci_component_affected.dag +// Scope: T-24 receipt — git diff path buckets → CiComponentAffected flags (dissolves detect-affected-components.sh). +// Status: structural claims; host transport is `detect-ci-affected-components` (v3-compiler bin). + +module v4.test.claim.workflow.ci_component_affected + +import v4.lens.edit_locus { GitDiffNameOnly, RepoPath } +import v4.std.collection { List } +import v4.std.logic { Bool } +import v4.workflow.ci { + CiComponentAffected, + ci_component_affected_from_git_diff +} + +data ci_comp_path_src_v2: RepoPath = "src/v2/stage0/Cargo.toml" +data ci_comp_path_cargo_lock: RepoPath = "Cargo.lock" +data ci_comp_path_src_v3: RepoPath = "src/v3/compiler/src/lib.rs" +data ci_comp_path_dsl_std: RepoPath = "dsl/std/node.dag" +data ci_comp_path_src_v4: RepoPath = "src/v4/workflow/ci.dag" +data ci_comp_path_workflow_yml: RepoPath = ".github/workflows/ci.yml" +data ci_comp_path_unrelated: RepoPath = "docs/README.md" + +fn ci_comp_flags_for(paths: List) -> CiComponentAffected { + ci_component_affected_from_git_diff(git_diff: GitDiffNameOnly { changed_paths: paths }) +} + +fn ci_comp_v2_from_src_v2_holds() -> Bool { + let f = ci_comp_flags_for(paths: [ci_comp_path_src_v2]) + f.v2 && !f.v3 && !f.v4 +} + +fn ci_comp_v3_from_dsl_holds() -> Bool { + let f = ci_comp_flags_for(paths: [ci_comp_path_dsl_std]) + !f.v2 && f.v3 && !f.v4 +} + +fn ci_comp_v4_and_policy_from_ci_dag_holds() -> Bool { + let f = ci_comp_flags_for(paths: [ci_comp_path_src_v4]) + f.v4 && f.workflow_policy +} + +fn ci_comp_cargo_lock_v2_v4_not_v3_holds() -> Bool { + let f = ci_comp_flags_for(paths: [ci_comp_path_cargo_lock]) + f.v2 && !f.v3 && f.v4 +} + +fn ci_comp_unrelated_all_false_holds() -> Bool { + let f = ci_comp_flags_for(paths: [ci_comp_path_unrelated]) + !f.v2 && !f.v3 && !f.v4 && !f.workflow_policy +} + +data ci_comp_v2_claim_passes: Bool = ci_comp_v2_from_src_v2_holds() +data ci_comp_v3_claim_passes: Bool = ci_comp_v3_from_dsl_holds() +data ci_comp_v4_policy_claim_passes: Bool = ci_comp_v4_and_policy_from_ci_dag_holds() +data ci_comp_cargo_lock_claim_passes: Bool = ci_comp_cargo_lock_v2_v4_not_v3_holds() +data ci_comp_unrelated_claim_passes: Bool = ci_comp_unrelated_all_false_holds() diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 4e95b1658e4..fcdd6348da8 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -1,6 +1,6 @@ // src/v4/workflow/ci.dag -// Scope: CI pipeline AS DATA; gunbc job/gate DAG + eager well-formedness; Wave-0 TestClaim roster selection; ci.yml projection deferred. -// Status: filled — declarative core + eager well-formedness + T-21/T-24 affected-set TestClaim selection (structural v2 gate only) + T-38 dissolution step declared (TestClaimCorpusEvalCommand job/gate/cache-digest; IRT-1 call site — ci_select_from_affected_set narrows roster to content_hash frontier — lands with dissolution PR that replaces scripts/v4-testclaim-corpus-gate.sh). +// Scope: CI pipeline AS DATA; gunbc job/gate DAG + eager well-formedness; Wave-0 TestClaim roster selection; YamlStatic workflow projection deferred (full `ci_pipeline` → `.github/workflows/ci.yml` lands with T-24 emission slice). +// Status: filled — declarative core + eager well-formedness + T-21/T-24 component affected-set (dissolves scripts/detect-affected-components.sh via `ci_component_affected_from_git_diff` + `detect-ci-affected-components` host transport) + T-21/T-24 TestClaim roster selection + T-38 dissolution step declared (TestClaimCorpusEvalCommand job/gate/cache-digest; IRT-1 call site — ci_select_from_affected_set narrows roster to content_hash frontier — lands with dissolution PR that replaces scripts/v4-testclaim-corpus-gate.sh). module v4.workflow.ci @@ -24,6 +24,7 @@ import v4.lens.affected_set { RerunNodeSetProduced, affected_set_rerun_nodes } +import v4.lens.edit_locus { GitDiffNameOnly, RepoPath } import v4.std.change { AffectedSet } import v4.compiler.eval { EvalContext, @@ -54,6 +55,7 @@ import v4.std.algebra { count_where, filter, for_all, + is_prefix_of, length, unique } @@ -98,6 +100,16 @@ type CiPipeline { gates: List } +// RULING-1: 🟢 pretty-much-done — GitHub Actions `affected` job outputs (v2/v3/v4/workflow_policy). +// Structural replacement for scripts/detect-affected-components.sh (T-21/T-24); host transport: +// `cargo run -p v3-compiler --bin detect-ci-affected-components` (must stay aligned with these predicates). +type CiComponentAffected { + v2: Bool + v3: Bool + v4: Bool + workflow_policy: Bool +} + // 🟡 gated — live-workflow projection interim (docs/r3-program-plan.md gates #98 `ci_yml_hand_authority_dissolved` and #100 `project_github_actions_landed`) — bind node://adhoc-35324347-e8a Lens-CI activation — dissolve-on-arrival: emitted/projected GitHub Actions workflow reads `ci_pipeline`/`LensCiCommand` directly and this step-name carrier is deleted; forbidden: adding signal/job/policy facts here instead of projecting them from `ci_pipeline`. type LensCiLiveWorkflowSignal { smoke_step_name: String @@ -588,3 +600,73 @@ fn ci_select_from_affected_set(roster: List, affected: AffectedSet) - rerun: affected_set_rerun_nodes(affected_set_value: affected) ) } + + +fn ci_repo_path_has_prefix(path: RepoPath, prefix: RepoPath) -> Bool { + is_prefix_of(prefix: prefix, xs: path, eq: fn(left, right) { left == right }) +} + + +fn ci_changed_path_affects_v2(changed: RepoPath) -> Bool { + ci_repo_path_has_prefix(path: changed, prefix: "src/v2/") + || changed == "Cargo.toml" + || changed == "Cargo.lock" +} + + +fn ci_changed_path_affects_v3(changed: RepoPath) -> Bool { + ci_repo_path_has_prefix(path: changed, prefix: "src/v3/") + || ci_repo_path_has_prefix(path: changed, prefix: "dsl/") +} + + +fn ci_changed_path_affects_v4(changed: RepoPath) -> Bool { + ci_repo_path_has_prefix(path: changed, prefix: "src/v4/") + || ci_repo_path_has_prefix(path: changed, prefix: "fixtures/v4-mvp1/") + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-mvp1") + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-m1") + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-testclaim-") + || ci_repo_path_has_prefix(path: changed, prefix: "dsl/std/") + || changed == "Cargo.toml" + || changed == "Cargo.lock" +} + + +fn ci_changed_path_affects_workflow_policy(changed: RepoPath) -> Bool { + ci_repo_path_has_prefix(path: changed, prefix: ".github/workflows/") + || ci_repo_path_has_prefix(path: changed, prefix: "src/v4/workflow/ci") + || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/v4_ci_component_affected") + || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/bin/detect_ci_affected_components") + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/check-workflow-path-regex-inventory") + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/workflow-path-regex-forbidden-substrings") +} + + +fn ci_any_changed_path_matches( + changed_paths: List, + predicate: fn(RepoPath) -> Bool +) -> Bool { + count_where(xs: changed_paths, predicate: predicate) != 0 +} + + +fn ci_component_affected_from_git_diff(git_diff: GitDiffNameOnly) -> CiComponentAffected { + CiComponentAffected { + v2: ci_any_changed_path_matches( + changed_paths: git_diff.changed_paths, + predicate: ci_changed_path_affects_v2 + ), + v3: ci_any_changed_path_matches( + changed_paths: git_diff.changed_paths, + predicate: ci_changed_path_affects_v3 + ), + v4: ci_any_changed_path_matches( + changed_paths: git_diff.changed_paths, + predicate: ci_changed_path_affects_v4 + ), + workflow_policy: ci_any_changed_path_matches( + changed_paths: git_diff.changed_paths, + predicate: ci_changed_path_affects_workflow_policy + ) + } +} From b1d1df6ecd13a9703154c9e7bf662260a2f8d303 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Thu, 28 May 2026 23:42:23 +0000 Subject: [PATCH 02/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dsl/gunbc/ci_github_actions_workflow.dag | 2 +- scripts/detect-affected-components.sh | 122 ------------------ .../v4_workflow_ci_runner_dag_smoke_test.rs | 1 + 3 files changed, 2 insertions(+), 123 deletions(-) delete mode 100755 scripts/detect-affected-components.sh diff --git a/dsl/gunbc/ci_github_actions_workflow.dag b/dsl/gunbc/ci_github_actions_workflow.dag index 92b6b391686..5287f8ff341 100644 --- a/dsl/gunbc/ci_github_actions_workflow.dag +++ b/dsl/gunbc/ci_github_actions_workflow.dag @@ -132,7 +132,7 @@ data gunbc_ci_github_actions_workflow: Workflow = { }, RunStep { name: Some { value: "Detect affected components" }, id: Some { value: "detect" }, - run: "bash scripts/detect-affected-components.sh \"${{ github.event_name }}\" \"$GITHUB_OUTPUT\"", + run: "cargo run -p v3-compiler --bin detect-ci-affected-components -- \"${{ github.event_name }}\" \"$GITHUB_OUTPUT\"", shell: Bash, env: none, working_directory: none, diff --git a/scripts/detect-affected-components.sh b/scripts/detect-affected-components.sh deleted file mode 100755 index eae9a6a3c19..00000000000 --- a/scripts/detect-affected-components.sh +++ /dev/null @@ -1,122 +0,0 @@ -#!/usr/bin/env bash -# scripts/detect-affected-components.sh -# -# Detects which v* components are affected by the current PR / push so CI -# can gate heavy v2 / v3 jobs accordingly (frozen-buildable discipline). -# -# Usage: -# scripts/detect-affected-components.sh -# -# event_name: "pull_request" | "push" -# output_file: a file to write GitHub Actions outputs into (one per line: -# key=value). Pass "$GITHUB_OUTPUT" from the workflow. -# -# Writes: -# v2=true|false — true if src/v2/ or workspace deps (Cargo.toml/lock) changed -# (v2 binary is frozen-buildable + the v4 bootstrap stage; -# deps changes can break the build) -# v3=true|false — true if src/v3/ or dsl/ changed -# (v3 is FROZEN — workspace dep changes do NOT trigger v3 CI; -# we don't care if v3 incidentally breaks because v3 is abandoned; -# if v3 is ever revived, the first src/v3/ PR catches latent breakage) -# v4=true|false — true if src/v4/ or workspace deps changed -# (triggers v2→v4 bootstrap viability test) -# workflow_policy=true|false — true if GitHub Actions workflow definitions, this -# script (affects which jobs run, including Gate #103), or the -# Gate #103 path-regex ratchet scripts changed. Independent of -# v2/v3/v4: PRs that touch only `.github/workflows/ci.yml` must still -# run fail-closed workflow policy checks (INVARIANTS P2/P3) and the -# MVP-1 end-to-end gate when its ci.yml wiring changes (ci job gates -# MVP-1 on workflow_policy || v4). -# -# Why this lives in a script (not inline in ci.yml): -# Gate #103 (`ci_uses_affected_set_selection`) policy forbids path-selection -# substrings in workflow YAML — see scripts/workflow-path-regex-forbidden- -# substrings.txt. The detection logic itself is not the v3 affected-set -# lens; it's the *gating* signal that decides whether the v3 lens (and v3 -# build) need to run at all. By living here it is exempt from the YAML -# substring check while preserving the policy intent (no path-regex -# selection inside workflow YAML). -# -# When v3 is unfrozen and the v3 lens becomes the canonical affected-set -# authority again, this script can be replaced by an invocation of that -# lens — the workflow integration point stays the same. - -set -euo pipefail - -event_name="${1:-pull_request}" -output_file="${2:-/dev/stdout}" - -if [ "$event_name" = "pull_request" ]; then - diff_range="origin/main...HEAD" - # Caller is expected to have fetched origin/main (via fetch-depth: 0 or - # a prior fetch step). If not, the diff falls back to empty and both - # outputs become "false" — safe default for a fresh-checkout case. -else - # push event — diff against the previous commit on this ref - diff_range="HEAD~1..HEAD" -fi - -changed=$(git diff --name-only "$diff_range" 2>/dev/null || true) - -echo "Changed files in $diff_range:" >&2 -if [ -n "$changed" ]; then - echo "$changed" | sed 's/^/ /' >&2 -else - echo " (none detected)" >&2 -fi -echo "" >&2 - -# v2 affected: src/v2/ touched, OR workspace deps changed. -# Workspace deps can break v2 build even if v2 sources aren't touched. -if echo "$changed" | grep -qE '^src/v2/|^Cargo\.(toml|lock)$'; then - v2_state="true" - echo "v2 affected: yes" >&2 -else - v2_state="false" - echo "v2 affected: no (skipping v2 fixed-point)" >&2 -fi - -# v3 affected: src/v3/ OR dsl/ ONLY. Workspace deps (Cargo.toml/lock) do NOT -# trigger v3 CI under the freeze — we don't care if v3 incidentally breaks -# because v3 is abandoned. If v3 is ever revived, the first src/v3/ PR catches -# any latent dep-bump breakage anyway. -if echo "$changed" | grep -qE '^src/v3/|^dsl/'; then - v3_state="true" - echo "v3 affected: yes" >&2 -else - v3_state="false" - echo "v3 affected: no (skipping v3 CI per freeze 2026-05-15)" >&2 -fi - -# v4 affected: src/v4/ touched OR workspace deps changed (deps can break v2 build, -# which v4 depends for bootstrap). Also dsl/std/ — MVP-1 gate compile dep pool -# (fixtures/v4-mvp1/add); dsl/std-only PRs must re-run the add receipt. -# scripts/v4-mvp1*, scripts/v4-m1*, and scripts/v4-testclaim-* — v4 CI shell -# gates (MVP-1 e2e, M1 rust emit probe, T-22 TestClaim corpus bridge). -if echo "$changed" | grep -qE '^src/v4/|^fixtures/v4-mvp1/|^scripts/v4-mvp1|^scripts/v4-m1|^scripts/v4-testclaim-|^dsl/std/|^Cargo\.(toml|lock)$'; then - v4_state="true" - echo "v4 affected: yes (running v2→v4 bootstrap viability test)" >&2 -else - v4_state="false" - echo "v4 affected: no (skipping v4 bootstrap test)" >&2 -fi - -# Gate #103 workflow / policy surface — orthogonal to compiler v2/v3/v4 buckets. -# Include this file: edits here change `workflow_policy` / v2/v3/v4 outputs and must -# not skip Gate #103 (INVARIANTS P3 fail-closed gating). -if echo "$changed" | grep -qE '^\.github/workflows/|^scripts/detect-affected-components\.sh|^scripts/check-workflow-path-regex-inventory\.sh|^scripts/workflow-path-regex-forbidden-substrings\.txt'; then - workflow_policy_state="true" - echo "workflow_policy (Gate #103 surface): yes" >&2 -else - workflow_policy_state="false" - echo "workflow_policy (Gate #103 surface): no" >&2 -fi - -# Emit GitHub Actions outputs (or stdout if no output file given) -{ - echo "v2=$v2_state" - echo "v3=$v3_state" - echo "v4=$v4_state" - echo "workflow_policy=$workflow_policy_state" -} >> "$output_file" diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 44c38eae1d7..8719ebb6f96 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -186,6 +186,7 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { for name in [ "ci_select_from_rerun_nodes", "ci_select_from_affected_set", + "ci_component_affected_from_git_diff", "test_claim_in_rerun_frontier", "ci_all_gate_run_policies_resolve", ] { From 24e8ba919c4c1af9a9a25ba757ccc283973ba308 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Thu, 28 May 2026 23:53:40 +0000 Subject: [PATCH 03/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 1 + scripts/v4-m1-rust-emit-probe.sh | 11 +- src/v3/compiler/src/lib.rs | 1 + src/v3/compiler/src/v4_ci_runner_pool.rs | 105 ++++++++++++++++++ .../v4_workflow_ci_runner_dag_smoke_test.rs | 26 +++++ .../claim/workflow/runner_pool_m1_probe.dag | 38 +++++++ src/v4/workflow/ci.dag | 104 +++++++++++++++++ 7 files changed, 284 insertions(+), 2 deletions(-) create mode 100644 src/v3/compiler/src/v4_ci_runner_pool.rs create mode 100644 src/v4/test/claim/workflow/runner_pool_m1_probe.dag diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index eaad791ac6b..1f3a691f01e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -234,6 +234,7 @@ jobs: timeout-minutes: 20 env: V4_M1_RUST_EMIT_OUT: ${{ runner.temp }}/v4-rust-emit + V4_M1_CARGO_CHECK_JOBS: "4" run: bash scripts/v4-m1-rust-emit-probe.sh - name: v2 → v4 bootstrap compile (fail-closed full) if: needs.affected.outputs.v4 == 'true' diff --git a/scripts/v4-m1-rust-emit-probe.sh b/scripts/v4-m1-rust-emit-probe.sh index b991025feb7..5d2d266ff2a 100755 --- a/scripts/v4-m1-rust-emit-probe.sh +++ b/scripts/v4-m1-rust-emit-probe.sh @@ -15,6 +15,8 @@ # V4_M1_RUSTC_LOG — cargo check log (default: ${OUT}.rustc.log) # V4_M1_RUST_EMIT_PROBE_STRICT — if 1, exit non-zero when compile or rustc fails # V4_M1_RUSTC_TIMEOUT_SECS — optional timeout for cargo check (CI: 600) +# V4_M1_CARGO_CHECK_JOBS — parallelism cap for cargo check (default: modeled +# m1_probe_cargo_check_jobs in src/v4/workflow/ci.dag) set -euo pipefail @@ -112,12 +114,17 @@ if [[ "$compile_status" -eq 0 && -f "$out/Cargo.toml" ]]; then if [[ -n "${GITHUB_ACTIONS:-}" && -z "$rustc_timeout" ]]; then rustc_timeout=600 fi + # Cap parallelism: many concurrent CI runs each fan out rustc workers through + # ctrl-build wrappers; without a cap the aggregate process count can reach swap + # on shared self-hosted runners (incident 2026-05-28). Default comes from + # v4.workflow.ci `m1_probe_cargo_check_jobs` (srv1/srv2 pool model). + cargo_check_jobs="${V4_M1_CARGO_CHECK_JOBS:-4}" set +e if [[ -n "$rustc_timeout" ]]; then timeout --preserve-status "$rustc_timeout" \ - "$cargo_bin" check --manifest-path "$out/Cargo.toml" 2>&1 | tee "$rustc_log" + "$cargo_bin" check --jobs "$cargo_check_jobs" --manifest-path "$out/Cargo.toml" 2>&1 | tee "$rustc_log" else - "$cargo_bin" check --manifest-path "$out/Cargo.toml" 2>&1 | tee "$rustc_log" + "$cargo_bin" check --jobs "$cargo_check_jobs" --manifest-path "$out/Cargo.toml" 2>&1 | tee "$rustc_log" fi rustc_status=${PIPESTATUS[0]} set -e diff --git a/src/v3/compiler/src/lib.rs b/src/v3/compiler/src/lib.rs index d20f8d7343e..e58f70b1152 100644 --- a/src/v3/compiler/src/lib.rs +++ b/src/v3/compiler/src/lib.rs @@ -4099,6 +4099,7 @@ pub mod lens_unused_parameters { pub mod emit_rust_roundtrip_fixtures; pub mod gunbc_ci; pub mod v4_ci_component_affected; +pub mod v4_ci_runner_pool; pub mod post_emit_verifier; pub mod r1c_e_gates; pub mod test_runner; diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs new file mode 100644 index 00000000000..f3fda1c2505 --- /dev/null +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -0,0 +1,105 @@ +//! Structural mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. + +/// Structural mirror of `RunnerArch::Arm64` (single host arch today). +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RunnerArch { + Arm64, +} + +/// Structural mirror of `SelfHostedRunnerPool` in `src/v4/workflow/ci.dag`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct SelfHostedRunnerPool { + pub host: &'static str, + pub arch: RunnerArch, + pub core_count: u32, + pub runner_count: u32, + pub jobserver_token_cap: u32, +} + +pub const CI_SRV1_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { + host: "srv1", + arch: RunnerArch::Arm64, + core_count: 128, + runner_count: 20, + jobserver_token_cap: 25, +}; + +pub const CI_SRV2_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { + host: "srv2", + arch: RunnerArch::Arm64, + core_count: 128, + runner_count: 30, + jobserver_token_cap: 36, +}; + +pub const CI_SELF_HOSTED_RUNNER_POOLS: [SelfHostedRunnerPool; 2] = + [CI_SRV1_POOL, CI_SRV2_POOL]; + +pub fn ci_runner_pool_min_jobserver_token_cap(pools: &[SelfHostedRunnerPool]) -> u32 { + pools + .iter() + .map(|p| p.jobserver_token_cap) + .min() + .unwrap_or(0) +} + +pub fn ci_runner_pool_max_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { + pools.iter().map(|p| p.runner_count).max().unwrap_or(0) +} + +pub fn ci_runner_pool_min_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { + pools + .iter() + .map(|p| p.runner_count) + .min() + .unwrap_or(0) +} + +pub fn ci_runner_pool_total_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { + pools.iter().map(|p| p.runner_count).sum() +} + +pub fn ci_runner_pool_host_count(pools: &[SelfHostedRunnerPool]) -> u32 { + pools.len() as u32 +} + +pub fn ci_m1_probe_cargo_fanout_slots(pools: &[SelfHostedRunnerPool]) -> u32 { + let min_runners = ci_runner_pool_min_runner_count(pools); + let max_runners = ci_runner_pool_max_runner_count(pools); + let total_runners = ci_runner_pool_total_runner_count(pools); + let hosts = ci_runner_pool_host_count(pools); + let spread = max_runners.saturating_sub(min_runners); + if spread == 0 { + return 1; + } + (total_runners - min_runners) * hosts / spread +} + +pub fn ci_m1_probe_cargo_check_jobs_from_pools(pools: &[SelfHostedRunnerPool]) -> u32 { + let fanout = ci_m1_probe_cargo_fanout_slots(pools).max(1); + ci_runner_pool_min_jobserver_token_cap(pools) / fanout +} + +/// Modeled authority for `data m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. +pub fn m1_probe_cargo_check_jobs() -> u32 { + ci_m1_probe_cargo_check_jobs_from_pools(&CI_SELF_HOSTED_RUNNER_POOLS) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn srv_pools_match_operator_spec() { + assert_eq!(CI_SRV1_POOL.runner_count, 20); + assert_eq!(CI_SRV1_POOL.jobserver_token_cap, 25); + assert_eq!(CI_SRV2_POOL.runner_count, 30); + assert_eq!(CI_SRV2_POOL.jobserver_token_cap, 36); + } + + #[test] + fn m1_probe_cargo_check_jobs_derived_as_four() { + assert_eq!(ci_m1_probe_cargo_fanout_slots(&CI_SELF_HOSTED_RUNNER_POOLS), 6); + assert_eq!(m1_probe_cargo_check_jobs(), 4); + } +} diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 8719ebb6f96..3da800d3b22 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -304,6 +304,32 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { m1_step.contains(&format!("run: bash {script_path}")), "{CI_YML_PATH}: `{step_name}` must invoke the modeled probe script" ); + assert!( + CI_DAG.contains("type SelfHostedRunnerPool"), + "{CI_DAG_PATH}: must model self-hosted runner pools (T-24 addendum)" + ); + assert!( + CI_DAG.contains("data ci_srv1_pool: SelfHostedRunnerPool") + && CI_DAG.contains("runner_count: 20") + && CI_DAG.contains("jobserver_token_cap: 25") + && CI_DAG.contains("data ci_srv2_pool: SelfHostedRunnerPool") + && CI_DAG.contains("runner_count: 30") + && CI_DAG.contains("jobserver_token_cap: 36"), + "{CI_DAG_PATH}: srv1/srv2 pool rows must match operator spec" + ); + assert!( + CI_DAG.contains("data m1_probe_cargo_check_jobs: Int"), + "{CI_DAG_PATH}: M1 cargo parallelism must be a derived Int fact" + ); + let m1_jobs = v3_compiler::v4_ci_runner_pool::m1_probe_cargo_check_jobs(); + assert_eq!( + m1_jobs, 4, + "Rust transport mirror of m1_probe_cargo_check_jobs must match ci.dag fleet model" + ); + assert!( + m1_step.contains(&format!("V4_M1_CARGO_CHECK_JOBS: \"{m1_jobs}\"")), + "{CI_YML_PATH}: M1 step must project modeled cargo-check job cap" + ); } #[test] diff --git a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag new file mode 100644 index 00000000000..c1ac33cc683 --- /dev/null +++ b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag @@ -0,0 +1,38 @@ +// src/v4/test/claim/workflow/runner_pool_m1_probe.dag +// Scope: T-24 self-hosted runner pool + derived M1 cargo-check parallelism (operator srv1/srv2 spec). + +module v4.test.claim.workflow.runner_pool_m1_probe + +import v4.std.collection { List } +import v4.std.logic { Bool } +import v4.workflow.ci { + SelfHostedRunnerPool, + ci_m1_probe_cargo_check_jobs_from_pools, + ci_m1_probe_cargo_fanout_slots, + ci_self_hosted_runner_pools, + ci_srv1_pool, + ci_srv2_pool, + m1_probe_cargo_check_jobs +} + +fn runner_pool_srv1_runner_count_holds() -> Bool { + ci_srv1_pool.runner_count == 20 +} + +fn runner_pool_srv2_jobserver_cap_holds() -> Bool { + ci_srv2_pool.jobserver_token_cap == 36 +} + +fn runner_pool_m1_fanout_slots_holds() -> Bool { + ci_m1_probe_cargo_fanout_slots(pools: ci_self_hosted_runner_pools) == 6 +} + +fn runner_pool_m1_cargo_jobs_holds() -> Bool { + (m1_probe_cargo_check_jobs == 4) + && (ci_m1_probe_cargo_check_jobs_from_pools(pools: ci_self_hosted_runner_pools) == 4) +} + +data runner_pool_srv1_claim_passes: Bool = runner_pool_srv1_runner_count_holds() +data runner_pool_srv2_claim_passes: Bool = runner_pool_srv2_jobserver_cap_holds() +data runner_pool_fanout_claim_passes: Bool = runner_pool_m1_fanout_slots_holds() +data runner_pool_m1_jobs_claim_passes: Bool = runner_pool_m1_cargo_jobs_holds() diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index fcdd6348da8..a783d7045b8 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -110,6 +110,19 @@ type CiComponentAffected { workflow_policy: Bool } +// RULING-1: 🟢 pretty-much-done — self-hosted fleet substrate (operator 2026-05-28: srv1/srv2 Ampere Altra). +// Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. +type RunnerArch + = Arm64 + +type SelfHostedRunnerPool { + host: Symbol + arch: RunnerArch + core_count: Int + runner_count: Int + jobserver_token_cap: Int +} + // 🟡 gated — live-workflow projection interim (docs/r3-program-plan.md gates #98 `ci_yml_hand_authority_dissolved` and #100 `project_github_actions_landed`) — bind node://adhoc-35324347-e8a Lens-CI activation — dissolve-on-arrival: emitted/projected GitHub Actions workflow reads `ci_pipeline`/`LensCiCommand` directly and this step-name carrier is deleted; forbidden: adding signal/job/policy facts here instead of projecting them from `ci_pipeline`. type LensCiLiveWorkflowSignal { smoke_step_name: String @@ -136,6 +149,29 @@ data structural_v2_compile: Symbol = structural_v2_compile data lens_ci_registry_signal: Symbol = lens_ci_registry_signal data m1_rust_emit_probe_signal: Symbol = m1_rust_emit_probe_signal data testclaim_corpus_eval_signal: Symbol = testclaim_corpus_eval_signal +data ci_srv1_host: Symbol = ci_srv1_host +data ci_srv2_host: Symbol = ci_srv2_host + +data ci_srv1_pool: SelfHostedRunnerPool = { + host: ci_srv1_host + arch: Arm64 + core_count: 128 + runner_count: 20 + jobserver_token_cap: 25 +} + +data ci_srv2_pool: SelfHostedRunnerPool = { + host: ci_srv2_host + arch: Arm64 + core_count: 128 + runner_count: 30 + jobserver_token_cap: 36 +} + +data ci_self_hosted_runner_pools: List = [ + ci_srv1_pool, + ci_srv2_pool +] data lens_ci_required_lenses: List = [ Complexity, @@ -636,6 +672,7 @@ fn ci_changed_path_affects_workflow_policy(changed: RepoPath) -> Bool { ci_repo_path_has_prefix(path: changed, prefix: ".github/workflows/") || ci_repo_path_has_prefix(path: changed, prefix: "src/v4/workflow/ci") || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/v4_ci_component_affected") + || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/v4_ci_runner_pool") || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/bin/detect_ci_affected_components") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/check-workflow-path-regex-inventory") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/workflow-path-regex-forbidden-substrings") @@ -670,3 +707,70 @@ fn ci_component_affected_from_git_diff(git_diff: GitDiffNameOnly) -> CiComponent ) } } + + +fn ci_runner_pool_min_jobserver_token_cap(pools: List) -> Int { + fold(pools, init: ci_srv2_pool.jobserver_token_cap, f: fn(acc, pool) { + if pool.jobserver_token_cap < acc { + pool.jobserver_token_cap + } else { + acc + } + }) +} + + +fn ci_runner_pool_max_runner_count(pools: List) -> Int { + fold(pools, init: 0, f: fn(acc, pool) { + if pool.runner_count > acc { + pool.runner_count + } else { + acc + } + }) +} + + +fn ci_runner_pool_min_runner_count(pools: List) -> Int { + fold(pools, init: ci_srv1_pool.runner_count, f: fn(acc, pool) { + if pool.runner_count < acc { + pool.runner_count + } else { + acc + } + }) +} + + +fn ci_runner_pool_total_runner_count(pools: List) -> Int { + fold(pools, init: 0, f: fn(acc, pool) { + acc + pool.runner_count + }) +} + + +fn ci_runner_pool_host_count(pools: List) -> Int { + length(xs: pools) +} + + +// Modeled concurrent M1 cargo-check fanout across the fleet: spread peer slots across +// hosts so one probe does not claim more than min(jobserver_token_cap) / fanout_slots. +fn ci_m1_probe_cargo_fanout_slots(pools: List) -> Int { + let min_runners = ci_runner_pool_min_runner_count(pools: pools) + let max_runners = ci_runner_pool_max_runner_count(pools: pools) + let total_runners = ci_runner_pool_total_runner_count(pools: pools) + let hosts = ci_runner_pool_host_count(pools: pools) + (total_runners - min_runners) * hosts / (max_runners - min_runners) +} + + +fn ci_m1_probe_cargo_check_jobs_from_pools(pools: List) -> Int { + ci_runner_pool_min_jobserver_token_cap(pools: pools) + / ci_m1_probe_cargo_fanout_slots(pools: pools) +} + + +data m1_probe_cargo_check_jobs: Int = ci_m1_probe_cargo_check_jobs_from_pools( + pools: ci_self_hosted_runner_pools +) From e948ea5f4b8455c54011238d48323f9c451047d2 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Thu, 28 May 2026 23:55:41 +0000 Subject: [PATCH 04/56] chore(ci): regen ci_github_actions_workflow.dag for M1 cargo-check env projection Co-authored-by: Cursor --- dsl/gunbc/ci_github_actions_workflow.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dsl/gunbc/ci_github_actions_workflow.dag b/dsl/gunbc/ci_github_actions_workflow.dag index 5287f8ff341..db98857872f 100644 --- a/dsl/gunbc/ci_github_actions_workflow.dag +++ b/dsl/gunbc/ci_github_actions_workflow.dag @@ -473,7 +473,7 @@ data gunbc_ci_github_actions_workflow: Workflow = { id: none, run: "bash scripts/v4-m1-rust-emit-probe.sh", shell: Bash, - env: { "V4_M1_RUST_EMIT_OUT": "${{ runner.temp }}/v4-rust-emit" }, + env: { "V4_M1_RUST_EMIT_OUT": "${{ runner.temp }}/v4-rust-emit", "V4_M1_CARGO_CHECK_JOBS": "4" }, working_directory: none, if_condition: Some { value: "needs.affected.outputs.v4 == 'true' || needs.affected.outputs.workflow_policy == 'true'" }, continue_on_error: true, From f39cf8cd9869ac612039b957e21d03255fd9ede2 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:01:01 +0000 Subject: [PATCH 05/56] fix(T-24): align workflow_policy Rust paths with ci.dag + P5 SG-0 census MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add v4_ci_runner_pool to ci_changed_path_affects_workflow_policy so the detect-ci-affected-components host transport matches ci.dag authority. Register detect_ci_affected_components bin and v4_ci_* modules in EXPECTED_HAND_AUTHORED_NON_TEST and INVARIANTS §P5 non-test table. Co-authored-by: Cursor --- INVARIANTS.md | 3 +++ .../compiler/src/v4_ci_component_affected.rs | 24 +++++++++++++++++++ .../tests/integration/sg0_census_test.rs | 3 +++ 3 files changed, 30 insertions(+) diff --git a/INVARIANTS.md b/INVARIANTS.md index ae16bb03061..c5f034bcc96 100644 --- a/INVARIANTS.md +++ b/INVARIANTS.md @@ -475,6 +475,7 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED |------|---------| | `src/v3/compiler/benches/tier3_mirror_perf.rs` | **ROADMAP:** `ROADMAP.md` — **Tier-3 perf-budget Phase-1** / T-Tier3-Dissolution (`docs/briefs/r3-pb-tier3-perf-budget-worker.md`; parent brief #1331). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when Tier3 host mirrors dissolve per `docs/r3-structure.md` §Acceptance (Criterion harness no longer targets hot Rust substrate entrypoints). **Interim ratchet:** frozen `tier3_baseline.json` + bench stays `--locked` clean under CI. | | `src/v3/compiler/build.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor`; **authority:** `dsl/gunbc/compiler.dag` **stage0** (`stage0.hand_maintained_src` / regen edges surfaced to Cargo). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** `build.rs` mirror retires when stage ordering + copy/hash contracts are enforced only via `.dag` emit programs (`SELF_HOSTING.md` §2). **Interim ratchet:** bootstrap snapshot + fmt/ci gates keep `build.rs` aligned with `compiler.dag`. | +| `src/v3/compiler/src/bin/detect_ci_affected_components.rs` | **TASKS.md** T-24 — host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (dissolves `scripts/detect-affected-components.sh`; path buckets single-authority in `src/v4/workflow/ci.dag`). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR as the bin. **Dissolution:** delete when affected-component projection runs from `.dag` eval / generated CI runner without this hand `main`. **Interim ratchet:** `v4_ci_component_affected` unit tests + `v4_workflow_ci_runner_dag_smoke_test` alignment with `ci.dag`. | | `src/v3/compiler/src/bin/gunbc_ci.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** + **T-Workflow-As-Data** — `bin/gunbc_ci` host shim for modeled CI (`dsl/gunbc/ci.dag`). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when CI selection + receipts are emitted/invoked without a hand `main` (`SELF_HOSTING.md` §2.2). **Interim ratchet:** `gunbc_ci` integration tests + SG-0 census. | | `src/v3/compiler/src/bin/r1c_e_emit_gates.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / R1C-E emit gates (`docs/r3-program-plan.md` T-Emit `.dag` `TestClaim` lane). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit-gate checks are invoked only from generated/bootstrap harness without this bin. **Interim ratchet:** `r1c_e_gates.rs` shared checks + integration harness. | | `src/v3/compiler/src/bin/regen_bootstrap.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — regen **bootstrap** stage host entry (`dsl/gunbc/regen*.dag` family). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when bootstrap regen is a single declared pipeline command with no parallel Rust `main`. **Interim ratchet:** `regen_bootstrap_emit.rs` + bootstrap snapshot CI. | @@ -503,6 +504,8 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED | `src/v3/compiler/src/emit_rust_bin_shim.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | | `src/v3/compiler/src/emit_rust_roundtrip_fixtures.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | | `src/v3/compiler/src/enforced_lens_application.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **Plan:** `docs/r3-program-plan.md` §1.8 gate **#95** `opt_in_iteration_parallelism_via_lens_application_demonstrated` — parallelism iteration LAS consumer routes violation decisions through authored `parallelism_enforcement_violates` in `src/v3/lenses/parallelism.dag` via `apply_lens_declaration` in `src/v3/compiler/src/lens_declaration_apply.rs` (single substrate authority); Rust maps only `loop_iteration_parallel_emission_indicator` → observed `ParallelismMode`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Co-receipt (same PR, P5 single surface):** gate **#95** SG-0 census net **+1** on `EXPECTED_HAND_AUTHORED_TEST` + pairing `(c)` text are prepended via `scripts/ci-merge/sg0-pr-body-append.3131.txt`; that append is the **single** checkable PR-body bundle listing every gate **#95** co-touched non-test path (`enforced_lens_application.rs`, `dag.rs`, `lib.rs`, `lower.rs` — roles spelled out in the prepend) alongside this amended row. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | +| `src/v3/compiler/src/v4_ci_component_affected.rs` | **TASKS.md** T-24 — Rust mirror of `ci_component_affected_from_git_diff` path buckets (`src/v4/workflow/ci.dag` is authority; must stay aligned per `ci.dag` workflow_policy predicates). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when `detect-ci-affected-components` invokes `.dag` eval over `ci.dag` predicates with no parallel Rust path logic. **Interim ratchet:** `workflow_policy_paths_match_ci_dag_authority` unit test + integration smoke. | +| `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_derived_as_four` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | | `src/v3/compiler/src/gunbc_ci.rs` | **ROADMAP:** `ROADMAP.md` § **Forward-Tracked Lane: T-Workflow-As-Data** (≈L57–L63; substrate lane feeding program gate **#103** `ci_uses_affected_set_selection` per `docs/r3-program-plan.md` + `docs/briefs/r3-wave1-s6-slice7-affected-set-impl-worker.md`). **Additional ROADMAP receipt:** `ROADMAP.md` § **Lane acceptance** row **T-TestGen** / `testgen_manual_claim_is_first_class` (first-class `TestClaim` execution) + row **T-PB-B** / `pb_rust_tests_outside_residual_zero` (tests-as-data) carry the Lens-CI `MechanicalReverification` host bridge for `v4.lens.subsumption.DissolutionSubsumption` rows while the `.dag` TestClaim runner is staged. **Dissolution:** remove when `CIWorkflowDag` affected-gate dispatch is owned by `.dag` programs / generated `TestClaim` receipts (or the dag compiler emits selection) with **no** parallel Rust mirror over the `dsl/gunbc/ci.dag` carrier; also remove the `MechanicalReverification` host bridge when the v4 `.dag` TestClaim runner consumes `MechanicalReverification { test_claim }` rows and reports the same `Verified` / `NotVerified` / `Unverifiable` verdict as substrate data. **Interim ratchet:** `select_affected_gates` + in-module hermetic tests pin symmetric edge-expansion semantics consistent with `CIGateEdge { from, to }` in `dsl/gunbc/ci.dag`; `mechanical_reverification_verdict` + in-module hermetic tests pin fail-closed subsumption verdicts with nominal `DiffId`, `TestClaimId`, and `ProducerStageId` mirrors. | | `src/v3/compiler/src/infer.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | | `src/v3/compiler/src/int_literal_ranges.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index 56b6d2efb4a..3f4cea841a6 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -64,6 +64,7 @@ pub fn ci_changed_path_affects_workflow_policy(path: &str) -> bool { path.starts_with(".github/workflows/") || path.starts_with("src/v4/workflow/ci") || path.starts_with("src/v3/compiler/src/v4_ci_component_affected") + || path.starts_with("src/v3/compiler/src/v4_ci_runner_pool") || path.starts_with("src/v3/compiler/src/bin/detect_ci_affected_components") || path.starts_with("scripts/check-workflow-path-regex-inventory") || path.starts_with("scripts/workflow-path-regex-forbidden-substrings") @@ -95,6 +96,29 @@ mod tests { assert!(ci_changed_path_affects_workflow_policy( ".github/workflows/ci.yml" )); + assert!(ci_changed_path_affects_workflow_policy( + "src/v3/compiler/src/v4_ci_runner_pool.rs" + )); + } + + #[test] + fn workflow_policy_paths_match_ci_dag_authority() { + assert_eq!( + ci_changed_path_affects_workflow_policy("src/v4/workflow/ci.dag"), + true + ); + assert_eq!( + ci_changed_path_affects_workflow_policy("src/v3/compiler/src/v4_ci_runner_pool.rs"), + true + ); + assert_eq!( + ci_changed_path_affects_workflow_policy("src/v3/compiler/src/v4_ci_component_affected.rs"), + true + ); + assert_eq!( + ci_changed_path_affects_workflow_policy("src/v3/compiler/src/bin/detect_ci_affected_components.rs"), + true + ); } #[test] diff --git a/src/v3/compiler/tests/integration/sg0_census_test.rs b/src/v3/compiler/tests/integration/sg0_census_test.rs index 971a1002f48..d85bc09c209 100644 --- a/src/v3/compiler/tests/integration/sg0_census_test.rs +++ b/src/v3/compiler/tests/integration/sg0_census_test.rs @@ -276,6 +276,7 @@ const EXPECTED_HAND_AUTHORED_NON_TEST: &[&str] = &[ // survives. "src/v3/compiler/benches/tier3_mirror_perf.rs", "src/v3/compiler/build.rs", + "src/v3/compiler/src/bin/detect_ci_affected_components.rs", "src/v3/compiler/src/bin/gunbc_ci.rs", "src/v3/compiler/src/bin/r1c_e_emit_gates.rs", "src/v3/compiler/src/bin/regen_bootstrap.rs", @@ -356,6 +357,8 @@ const EXPECTED_HAND_AUTHORED_NON_TEST: &[&str] = &[ "src/v3/compiler/src/regen_tokenize.rs", "src/v3/compiler/src/self_host_receipt_p0.rs", "src/v3/compiler/src/test_runner.rs", + "src/v3/compiler/src/v4_ci_component_affected.rs", + "src/v3/compiler/src/v4_ci_runner_pool.rs", "src/v3/compiler/src/v4_hollow_alias_gate.rs", "src/v3/compiler/src/wall_clock_ratchet_manifest.rs", ]; From 3001a9ce9872af7252987a91d65c8e525110a77e Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:08:00 +0000 Subject: [PATCH 06/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 17 ++++++++++++++--- src/v3/compiler/src/v4_ci_runner_pool.rs | 13 +++++++++---- src/v4/workflow/ci.dag | 13 ++++++++++++- 3 files changed, 35 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1f3a691f01e..6d8bd3071d3 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -59,9 +59,9 @@ jobs: run: rustup default "$(rustup show active-toolchain | awk '{print $1; exit}')" - name: cargo fmt --all --check run: cargo fmt --all --check - # Affected-set detection — drives gating of v2/v3 jobs (frozen components - # only run their heavy CI when their source is touched, or on push-to-main - # for trunk verification). Cheap (~30s); other jobs depend on its outputs. + # Affected-set detection — drives gating of v2/v3/v4 jobs (path buckets modeled in + # `src/v4/workflow/ci.dag`; host transport `detect-ci-affected-components`). First + # run on a cold self-hosted runner compiles v3-compiler; subsequent steps gate on outputs. affected: if: github.event.pull_request.draft != true runs-on: [self-hosted, linux, arm64] @@ -72,12 +72,23 @@ jobs: v4: ${{ steps.detect.outputs.v4 }} workflow_policy: ${{ steps.detect.outputs.workflow_policy }} steps: + - name: Isolate toolchain dirs (srv1/srv2 shared-$HOME concurrent-rustup race) + run: | + echo "CARGO_HOME=$RUNNER_TEMP/cargo" >> "$GITHUB_ENV" + echo "RUSTUP_HOME=$RUNNER_TEMP/rustup" >> "$GITHUB_ENV" - name: Clear inherited GitHub auth header (shared runner HOME) run: git config --global --unset-all http.https://github.com/.extraheader || true - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 + - name: Setup Rust + uses: actions-rust-lang/setup-rust-toolchain@v1.16.0 + with: + cache: false + rustflags: '' + - name: Pin global rustup default (isolated RUSTUP_HOME has no default toolchain) + run: rustup default "$(rustup show active-toolchain | awk '{print $1; exit}')" - name: Fetch main for diff base if: github.event_name == 'pull_request' run: git fetch origin main:refs/remotes/origin/main diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index f3fda1c2505..c8ec2dac007 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -63,15 +63,20 @@ pub fn ci_runner_pool_host_count(pools: &[SelfHostedRunnerPool]) -> u32 { pools.len() as u32 } +pub fn ci_runner_pool_runner_spread(max_runners: u32, min_runners: u32) -> u32 { + if max_runners == min_runners { + 1 + } else { + max_runners - min_runners + } +} + pub fn ci_m1_probe_cargo_fanout_slots(pools: &[SelfHostedRunnerPool]) -> u32 { let min_runners = ci_runner_pool_min_runner_count(pools); let max_runners = ci_runner_pool_max_runner_count(pools); let total_runners = ci_runner_pool_total_runner_count(pools); let hosts = ci_runner_pool_host_count(pools); - let spread = max_runners.saturating_sub(min_runners); - if spread == 0 { - return 1; - } + let spread = ci_runner_pool_runner_spread(max_runners, min_runners); (total_runners - min_runners) * hosts / spread } diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index a783d7045b8..9d69db6671f 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -754,6 +754,15 @@ fn ci_runner_pool_host_count(pools: List) -> Int { } +fn ci_runner_pool_runner_spread(max_runners: Int, min_runners: Int) -> Int { + if max_runners == min_runners { + 1 + } else { + max_runners - min_runners + } +} + + // Modeled concurrent M1 cargo-check fanout across the fleet: spread peer slots across // hosts so one probe does not claim more than min(jobserver_token_cap) / fanout_slots. fn ci_m1_probe_cargo_fanout_slots(pools: List) -> Int { @@ -761,7 +770,9 @@ fn ci_m1_probe_cargo_fanout_slots(pools: List) -> Int { let max_runners = ci_runner_pool_max_runner_count(pools: pools) let total_runners = ci_runner_pool_total_runner_count(pools: pools) let hosts = ci_runner_pool_host_count(pools: pools) - (total_runners - min_runners) * hosts / (max_runners - min_runners) + (total_runners - min_runners) + * hosts + / ci_runner_pool_runner_spread(max_runners: max_runners, min_runners: min_runners) } From f972a23dcc9cc43e3b781acb5d7ad0874f31c719 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:09:29 +0000 Subject: [PATCH 07/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/bin/detect_ci_affected_components.rs | 11 +++++++++-- src/v3/compiler/src/lib.rs | 4 ++-- .../compiler/src/v4_ci_component_affected.rs | 8 ++++++-- src/v3/compiler/src/v4_ci_runner_pool.rs | 19 +++++++++++-------- 4 files changed, 28 insertions(+), 14 deletions(-) diff --git a/src/v3/compiler/src/bin/detect_ci_affected_components.rs b/src/v3/compiler/src/bin/detect_ci_affected_components.rs index 4c85154b342..1dcef490f6c 100644 --- a/src/v3/compiler/src/bin/detect_ci_affected_components.rs +++ b/src/v3/compiler/src/bin/detect_ci_affected_components.rs @@ -49,7 +49,10 @@ fn git_changed_paths(range: &str) -> Vec { } } -fn write_github_output(path: &str, flags: v3_compiler::v4_ci_component_affected::CiComponentAffected) -> io::Result<()> { +fn write_github_output( + path: &str, + flags: v3_compiler::v4_ci_component_affected::CiComponentAffected, +) -> io::Result<()> { let mut file = fs::OpenOptions::new().append(true).open(path)?; writeln!(file, "v2={}", flags.v2)?; writeln!(file, "v3={}", flags.v3)?; @@ -83,7 +86,11 @@ fn main() -> ExitCode { eprintln!( "v2 affected: {}", - if flags.v2 { "yes" } else { "no (skipping v2 fixed-point)" } + if flags.v2 { + "yes" + } else { + "no (skipping v2 fixed-point)" + } ); eprintln!( "v3 affected: {}", diff --git a/src/v3/compiler/src/lib.rs b/src/v3/compiler/src/lib.rs index e58f70b1152..d8006102634 100644 --- a/src/v3/compiler/src/lib.rs +++ b/src/v3/compiler/src/lib.rs @@ -4098,11 +4098,11 @@ pub mod lens_unused_parameters { /// DB-8 / m1_3 / R1C-E: shared `PROGRAM_FIXTURES` + reflected harness table. pub mod emit_rust_roundtrip_fixtures; pub mod gunbc_ci; -pub mod v4_ci_component_affected; -pub mod v4_ci_runner_pool; pub mod post_emit_verifier; pub mod r1c_e_gates; pub mod test_runner; +pub mod v4_ci_component_affected; +pub mod v4_ci_runner_pool; pub mod wall_clock_ratchet_manifest; pub mod serialize { use crate::dag::{Behavior, Dag}; diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index 3f4cea841a6..95cc6622a20 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -112,11 +112,15 @@ mod tests { true ); assert_eq!( - ci_changed_path_affects_workflow_policy("src/v3/compiler/src/v4_ci_component_affected.rs"), + ci_changed_path_affects_workflow_policy( + "src/v3/compiler/src/v4_ci_component_affected.rs" + ), true ); assert_eq!( - ci_changed_path_affects_workflow_policy("src/v3/compiler/src/bin/detect_ci_affected_components.rs"), + ci_changed_path_affects_workflow_policy( + "src/v3/compiler/src/bin/detect_ci_affected_components.rs" + ), true ); } diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index c8ec2dac007..6d6b41e859a 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -32,8 +32,7 @@ pub const CI_SRV2_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { jobserver_token_cap: 36, }; -pub const CI_SELF_HOSTED_RUNNER_POOLS: [SelfHostedRunnerPool; 2] = - [CI_SRV1_POOL, CI_SRV2_POOL]; +pub const CI_SELF_HOSTED_RUNNER_POOLS: [SelfHostedRunnerPool; 2] = [CI_SRV1_POOL, CI_SRV2_POOL]; pub fn ci_runner_pool_min_jobserver_token_cap(pools: &[SelfHostedRunnerPool]) -> u32 { pools @@ -48,11 +47,7 @@ pub fn ci_runner_pool_max_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { } pub fn ci_runner_pool_min_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { - pools - .iter() - .map(|p| p.runner_count) - .min() - .unwrap_or(0) + pools.iter().map(|p| p.runner_count).min().unwrap_or(0) } pub fn ci_runner_pool_total_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { @@ -104,7 +99,15 @@ mod tests { #[test] fn m1_probe_cargo_check_jobs_derived_as_four() { - assert_eq!(ci_m1_probe_cargo_fanout_slots(&CI_SELF_HOSTED_RUNNER_POOLS), 6); + assert_eq!( + ci_m1_probe_cargo_fanout_slots(&CI_SELF_HOSTED_RUNNER_POOLS), + 6 + ); assert_eq!(m1_probe_cargo_check_jobs(), 4); } + + #[test] + fn runner_spread_fail_closed_when_max_equals_min() { + assert_eq!(ci_runner_pool_runner_spread(20, 20), 1); + } } From 52d6d7e110d78ef6d99691295552578866e0bdf3 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:13:57 +0000 Subject: [PATCH 08/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/bin/detect_ci_affected_components.rs | 63 ++++++++++++------- .../compiler/src/v4_ci_component_affected.rs | 10 +++ src/v3/compiler/src/v4_ci_runner_pool.rs | 14 ++++- src/v4/workflow/ci.dag | 60 +++++++++++++++++- 4 files changed, 121 insertions(+), 26 deletions(-) diff --git a/src/v3/compiler/src/bin/detect_ci_affected_components.rs b/src/v3/compiler/src/bin/detect_ci_affected_components.rs index 1dcef490f6c..8738969e678 100644 --- a/src/v3/compiler/src/bin/detect_ci_affected_components.rs +++ b/src/v3/compiler/src/bin/detect_ci_affected_components.rs @@ -1,4 +1,4 @@ -// Host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (T-24). +// Host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff_read` (T-24). // Replaces scripts/detect-affected-components.sh — path buckets live in ci.dag only. #![allow(clippy::disallowed_macros)] @@ -6,7 +6,9 @@ use std::io::Write; use std::process::{Command, ExitCode}; use std::{env, fs, io}; -use v3_compiler::v4_ci_component_affected::ci_component_affected_from_changed_paths; +use v3_compiler::v4_ci_component_affected::{ + ci_component_affected_fail_closed, ci_component_affected_from_changed_paths, +}; fn usage() -> ! { eprintln!( @@ -25,26 +27,33 @@ fn diff_range(event_name: &str) -> &'static str { } } -fn git_changed_paths(range: &str) -> Vec { +enum GitDiffRead { + Ok(Vec), + FailClosed, +} + +fn git_read_changed_paths(range: &str) -> GitDiffRead { let output = Command::new("git") .args(["diff", "--name-only", range]) .output(); match output { - Ok(out) if out.status.success() => String::from_utf8_lossy(&out.stdout) - .lines() - .filter(|line| !line.is_empty()) - .map(str::to_string) - .collect(), + Ok(out) if out.status.success() => GitDiffRead::Ok( + String::from_utf8_lossy(&out.stdout) + .lines() + .filter(|line| !line.is_empty()) + .map(str::to_string) + .collect(), + ), Ok(out) => { eprintln!( - "warning: git diff --name-only {range} exited {}; treating as no changes", + "error: git diff --name-only {range} exited {}; fail-closed (all components affected)", out.status ); - Vec::new() + GitDiffRead::FailClosed } Err(e) => { - eprintln!("warning: git diff failed ({e}); treating as no changes"); - Vec::new() + eprintln!("error: git diff failed ({e}); fail-closed (all components affected)"); + GitDiffRead::FailClosed } } } @@ -70,19 +79,25 @@ fn main() -> ExitCode { } let range = diff_range(event_name.as_str()); - let changed = git_changed_paths(range); - - eprintln!("Changed files in {range}:"); - if changed.is_empty() { - eprintln!(" (none detected)"); - } else { - for path in &changed { - eprintln!(" {path}"); + let flags = match git_read_changed_paths(range) { + GitDiffRead::Ok(changed) => { + eprintln!("Changed files in {range}:"); + if changed.is_empty() { + eprintln!(" (none detected)"); + } else { + for path in &changed { + eprintln!(" {path}"); + } + } + eprintln!(); + ci_component_affected_from_changed_paths(changed.iter().map(String::as_str)) } - } - eprintln!(); - - let flags = ci_component_affected_from_changed_paths(changed.iter().map(String::as_str)); + GitDiffRead::FailClosed => { + eprintln!("Changed files in {range}: (read failed — fail-closed superset)"); + eprintln!(); + ci_component_affected_fail_closed() + } + }; eprintln!( "v2 affected: {}", diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index 95cc6622a20..67ed1774409 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -13,6 +13,16 @@ pub struct CiComponentAffected { pub workflow_policy: bool, } +/// Mirror of `ci_component_affected_fail_closed` — all components affected (INVARIANTS P3). +pub fn ci_component_affected_fail_closed() -> CiComponentAffected { + CiComponentAffected { + v2: true, + v3: true, + v4: true, + workflow_policy: true, + } +} + /// Map `git diff --name-only` paths to component flags (same semantics as `ci.dag`). pub fn ci_component_affected_from_changed_paths<'a, I>(changed: I) -> CiComponentAffected where diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index 6d6b41e859a..04aa21916ef 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -58,6 +58,18 @@ pub fn ci_runner_pool_host_count(pools: &[SelfHostedRunnerPool]) -> u32 { pools.len() as u32 } +pub fn ci_int_at_least_one(n: u32) -> u32 { + n.max(1) +} + +pub fn ci_runner_pool_has_nonuniform_runner_counts(pools: &[SelfHostedRunnerPool]) -> bool { + ci_runner_pool_max_runner_count(pools) != ci_runner_pool_min_runner_count(pools) +} + +pub fn ci_runner_pool_m1_probe_witness_holds(pools: &[SelfHostedRunnerPool]) -> bool { + !pools.is_empty() && ci_runner_pool_has_nonuniform_runner_counts(pools) +} + pub fn ci_runner_pool_runner_spread(max_runners: u32, min_runners: u32) -> u32 { if max_runners == min_runners { 1 @@ -76,7 +88,7 @@ pub fn ci_m1_probe_cargo_fanout_slots(pools: &[SelfHostedRunnerPool]) -> u32 { } pub fn ci_m1_probe_cargo_check_jobs_from_pools(pools: &[SelfHostedRunnerPool]) -> u32 { - let fanout = ci_m1_probe_cargo_fanout_slots(pools).max(1); + let fanout = ci_int_at_least_one(ci_m1_probe_cargo_fanout_slots(pools)); ci_runner_pool_min_jobserver_token_cap(pools) / fanout } diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 9d69db6671f..d9f30386ca9 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -110,6 +110,15 @@ type CiComponentAffected { workflow_policy: Bool } +// RULING-1: 🟢 pretty-much-done — host `git diff --name-only` read outcome (T-24 / INVARIANTS P3). +// `ReadFailClosed` selects the superset `ci_component_affected_fail_closed` (all flags true). +type CiGitDiffReadOutcome { + ReadOk: GitDiffNameOnly + ReadFailClosed: Diagnostic +} + +data ci_git_diff_read_fail_closed_reason: Symbol = ci_git_diff_read_fail_closed_reason + // RULING-1: 🟢 pretty-much-done — self-hosted fleet substrate (operator 2026-05-28: srv1/srv2 Ampere Altra). // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. type RunnerArch @@ -687,6 +696,16 @@ fn ci_any_changed_path_matches( } +fn ci_component_affected_fail_closed() -> CiComponentAffected { + CiComponentAffected { + v2: true + v3: true + v4: true + workflow_policy: true + } +} + + fn ci_component_affected_from_git_diff(git_diff: GitDiffNameOnly) -> CiComponentAffected { CiComponentAffected { v2: ci_any_changed_path_matches( @@ -709,6 +728,45 @@ fn ci_component_affected_from_git_diff(git_diff: GitDiffNameOnly) -> CiComponent } +fn ci_component_affected_from_git_diff_read(outcome: CiGitDiffReadOutcome) -> CiComponentAffected { + match outcome { + ReadOk { git_diff } => ci_component_affected_from_git_diff(git_diff: git_diff) + ReadFailClosed { .. } => ci_component_affected_fail_closed() + } +} + + +fn ci_int_at_least_one(n: Int) -> Int { + if n < 1 { + 1 + } else { + n + } +} + + +fn ci_runner_pool_is_nonempty(pools: List) -> Bool { + length(xs: pools) != 0 +} + + +fn ci_runner_pool_has_nonuniform_runner_counts(pools: List) -> Bool { + ci_runner_pool_max_runner_count(pools: pools) + != ci_runner_pool_min_runner_count(pools: pools) +} + + +fn ci_runner_pool_m1_probe_witness_holds(pools: List) -> Bool { + ci_runner_pool_is_nonempty(pools: pools) + && ci_runner_pool_has_nonuniform_runner_counts(pools: pools) +} + + +data ci_runner_pool_m1_probe_witness: Bool = ci_runner_pool_m1_probe_witness_holds( + pools: ci_self_hosted_runner_pools +) + + fn ci_runner_pool_min_jobserver_token_cap(pools: List) -> Int { fold(pools, init: ci_srv2_pool.jobserver_token_cap, f: fn(acc, pool) { if pool.jobserver_token_cap < acc { @@ -778,7 +836,7 @@ fn ci_m1_probe_cargo_fanout_slots(pools: List) -> Int { fn ci_m1_probe_cargo_check_jobs_from_pools(pools: List) -> Int { ci_runner_pool_min_jobserver_token_cap(pools: pools) - / ci_m1_probe_cargo_fanout_slots(pools: pools) + / ci_int_at_least_one(n: ci_m1_probe_cargo_fanout_slots(pools: pools)) } From 09a949ec8f696d776719eac2260e5ed94bc43b35 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:15:29 +0000 Subject: [PATCH 09/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/ci-merge/sg0-pr-body-append.3853.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 scripts/ci-merge/sg0-pr-body-append.3853.txt diff --git a/scripts/ci-merge/sg0-pr-body-append.3853.txt b/scripts/ci-merge/sg0-pr-body-append.3853.txt new file mode 100644 index 00000000000..819858feb91 --- /dev/null +++ b/scripts/ci-merge/sg0-pr-body-append.3853.txt @@ -0,0 +1,3 @@ +SG-0 hand-path delta: +3 + +SG-0 pairing: (c) Net +3 on `EXPECTED_HAND_AUTHORED_NON_TEST` for T-24 host-transport shims (`detect_ci_affected_components.rs`, `v4_ci_component_affected.rs`, `v4_ci_runner_pool.rs`) with matching INVARIANTS §P5(b) rows. Dissolves when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; gunbc#3853). From dc831ce2fcc55c959269665162649117d35671d8 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:18:46 +0000 Subject: [PATCH 10/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/v4-m1-rust-emit-probe.sh | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/scripts/v4-m1-rust-emit-probe.sh b/scripts/v4-m1-rust-emit-probe.sh index 27fa42a26b9..cad8b3042b5 100755 --- a/scripts/v4-m1-rust-emit-probe.sh +++ b/scripts/v4-m1-rust-emit-probe.sh @@ -15,12 +15,8 @@ # V4_M1_RUSTC_LOG — cargo check log (default: ${OUT}.rustc.log) # V4_M1_RUST_EMIT_PROBE_STRICT — if 1, exit non-zero when compile or rustc fails # V4_M1_RUSTC_TIMEOUT_SECS — optional timeout for cargo check (CI: 600) -<<<<<<< HEAD -# V4_M1_CARGO_CHECK_JOBS — parallelism cap for cargo check (default: modeled -# m1_probe_cargo_check_jobs in src/v4/workflow/ci.dag) -======= -# V4_M1_CARGO_CHECK_JOBS — parallelism cap for cargo check (default: 4) ->>>>>>> origin/main +# V4_M1_CARGO_CHECK_JOBS — parallelism cap for cargo check (default: 4; modeled +# as m1_probe_cargo_check_jobs in src/v4/workflow/ci.dag) set -euo pipefail @@ -120,12 +116,8 @@ if [[ "$compile_status" -eq 0 && -f "$out/Cargo.toml" ]]; then fi # Cap parallelism: many concurrent CI runs each fan out rustc workers through # ctrl-build wrappers; without a cap the aggregate process count can reach swap -<<<<<<< HEAD - # on shared self-hosted runners (incident 2026-05-28). Default comes from - # v4.workflow.ci `m1_probe_cargo_check_jobs` (srv1/srv2 pool model). -======= - # on shared self-hosted runners (incident 2026-05-28). ->>>>>>> origin/main + # on shared self-hosted runners (incident 2026-05-28). CI sets + # V4_M1_CARGO_CHECK_JOBS from v4.workflow.ci `m1_probe_cargo_check_jobs` (srv1/srv2 pool). cargo_check_jobs="${V4_M1_CARGO_CHECK_JOBS:-4}" set +e if [[ -n "$rustc_timeout" ]]; then From 6cb45e762c5d3d6d7b8351fab15f5a421d06eea8 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:30:24 +0000 Subject: [PATCH 11/56] fix(ci): SG-0 pairing (c) must include dispatch word for PR #3853 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit CI failed on sg0-pr-body-append.3853.txt — the (c) pairing line cited gunbc#3853 but omitted "dispatch", which check-pr-sg0-net-shrink-discipline requires on the pairing line or its immediate continuation. Co-authored-by: Cursor --- scripts/ci-merge/sg0-pr-body-append.3853.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci-merge/sg0-pr-body-append.3853.txt b/scripts/ci-merge/sg0-pr-body-append.3853.txt index 819858feb91..b0ae6c67daa 100644 --- a/scripts/ci-merge/sg0-pr-body-append.3853.txt +++ b/scripts/ci-merge/sg0-pr-body-append.3853.txt @@ -1,3 +1,3 @@ SG-0 hand-path delta: +3 -SG-0 pairing: (c) Net +3 on `EXPECTED_HAND_AUTHORED_NON_TEST` for T-24 host-transport shims (`detect_ci_affected_components.rs`, `v4_ci_component_affected.rs`, `v4_ci_runner_pool.rs`) with matching INVARIANTS §P5(b) rows. Dissolves when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; gunbc#3853). +SG-0 pairing: (c) Net +3 on `EXPECTED_HAND_AUTHORED_NON_TEST` for T-24 host-transport shims (`detect_ci_affected_components.rs`, `v4_ci_component_affected.rs`, `v4_ci_runner_pool.rs`) with matching INVARIANTS §P5(b) rows. Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). From 8b892571785d42f2b5a99220e4de962fd9f855a2 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:31:22 +0000 Subject: [PATCH 12/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- dsl/gunbc/ci_github_actions_workflow.dag | 29 ++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/dsl/gunbc/ci_github_actions_workflow.dag b/dsl/gunbc/ci_github_actions_workflow.dag index db98857872f..89cf6c027c3 100644 --- a/dsl/gunbc/ci_github_actions_workflow.dag +++ b/dsl/gunbc/ci_github_actions_workflow.dag @@ -101,6 +101,16 @@ data gunbc_ci_github_actions_workflow: Workflow = { name: none, runner: SelfHosted { labels: ["self-hosted", "linux", "arm64"] }, steps: [RunStep { + name: Some { value: "Isolate toolchain dirs (srv1/srv2 shared-$HOME concurrent-rustup race)" }, + id: none, + run: "echo \"CARGO_HOME=$RUNNER_TEMP/cargo\" >> \"$GITHUB_ENV\"\necho \"RUSTUP_HOME=$RUNNER_TEMP/rustup\" >> \"$GITHUB_ENV\"\n", + shell: Bash, + env: none, + working_directory: none, + if_condition: none, + continue_on_error: false, + timeout_minutes: none + }, RunStep { name: Some { value: "Clear inherited GitHub auth header (shared runner HOME)" }, id: none, run: "git config --global --unset-all http.https://github.com/.extraheader || true", @@ -119,6 +129,25 @@ data gunbc_ci_github_actions_workflow: Workflow = { if_condition: none, continue_on_error: false, timeout_minutes: none + }, UsesStep { + name: Some { value: "Setup Rust" }, + id: none, + uses: { owner: "actions-rust-lang", repo: "setup-rust-toolchain", ref: "v1.16.0" }, + with: { "cache": "false", "rustflags": "" }, + env: none, + if_condition: none, + continue_on_error: false, + timeout_minutes: none + }, RunStep { + name: Some { value: "Pin global rustup default (isolated RUSTUP_HOME has no default toolchain)" }, + id: none, + run: "rustup default \"$(rustup show active-toolchain | awk '{print $1; exit}')\"", + shell: Bash, + env: none, + working_directory: none, + if_condition: none, + continue_on_error: false, + timeout_minutes: none }, RunStep { name: Some { value: "Fetch main for diff base" }, id: none, From 1a3804b0af6e1c9612238f4ac82fe375b36abd8a Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:51:38 +0000 Subject: [PATCH 13/56] fix(T-24): replace unsupported ReadFailClosed rest pattern in ci.dag The Lens-CI v4 compile step failed because `ReadFailClosed { .. }` uses rest syntax the parser does not accept. Bind the Diagnostic payload with an explicit wildcard field instead. Co-authored-by: Cursor --- src/v4/workflow/ci.dag | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index d9f30386ca9..1c3dfb36ca2 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -731,7 +731,7 @@ fn ci_component_affected_from_git_diff(git_diff: GitDiffNameOnly) -> CiComponent fn ci_component_affected_from_git_diff_read(outcome: CiGitDiffReadOutcome) -> CiComponentAffected { match outcome { ReadOk { git_diff } => ci_component_affected_from_git_diff(git_diff: git_diff) - ReadFailClosed { .. } => ci_component_affected_fail_closed() + ReadFailClosed { diagnostic: _ } => ci_component_affected_fail_closed() } } From 2d7de19a71625200b00125b2edfccd4fc9bb4e7f Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 00:58:18 +0000 Subject: [PATCH 14/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v4_workflow_ci_runner_dag_smoke_test.rs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 3da800d3b22..7e6111d6f5c 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -27,6 +27,18 @@ const M1_BINDING_TEST_FILTER: &str = const CLAIM_DAG: &str = include_str!("../../../../v4/test/claim/workflow/affected_set_ci_runner.dag"); const CLAIM_PATH: &str = "src/v4/test/claim/workflow/affected_set_ci_runner.dag"; +const V4_CI_COMPONENT_AFFECTED_RS: &str = include_str!("../../src/v4_ci_component_affected.rs"); + +/// Single-authority workflow_policy path buckets (`ci.dag` predicates ↔ Rust host mirror). +const CI_WORKFLOW_POLICY_PREFIXES: &[&str] = &[ + ".github/workflows/", + "src/v4/workflow/ci", + "src/v3/compiler/src/v4_ci_component_affected", + "src/v3/compiler/src/v4_ci_runner_pool", + "src/v3/compiler/src/bin/detect_ci_affected_components", + "scripts/check-workflow-path-regex-inventory", + "scripts/workflow-path-regex-forbidden-substrings", +]; fn parse_module(source: &str, path: &str) -> v3_compiler::parse_surface::SurfaceModule { let tokens = @@ -233,6 +245,20 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { ); } +#[test] +fn v4_workflow_ci_workflow_policy_prefixes_align_rust_mirror() { + for prefix in CI_WORKFLOW_POLICY_PREFIXES { + assert!( + CI_DAG.contains(&format!("prefix: \"{prefix}\"")), + "{CI_DAG_PATH}: workflow_policy authority must declare prefix `{prefix}`" + ); + assert!( + V4_CI_COMPONENT_AFFECTED_RS.contains(&format!("\"{prefix}\"")), + "v4_ci_component_affected.rs mirror must declare prefix `{prefix}`" + ); + } +} + #[test] fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { let module = parse_module(CI_DAG, CI_DAG_PATH); From dc4e020b4a09caf5b2e174939c0719efb6535c3c Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 01:09:56 +0000 Subject: [PATCH 15/56] fix(T-24): keep != on one line in ci.dag runner-pool witness v4 compile rejects a line-leading `!=` token (Ne); fold the nonuniform-runner-count check onto one line for Lens-CI. Co-authored-by: Cursor --- src/v4/workflow/ci.dag | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 1c3dfb36ca2..a7912b811b3 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -751,8 +751,7 @@ fn ci_runner_pool_is_nonempty(pools: List) -> Bool { fn ci_runner_pool_has_nonuniform_runner_counts(pools: List) -> Bool { - ci_runner_pool_max_runner_count(pools: pools) - != ci_runner_pool_min_runner_count(pools: pools) + ci_runner_pool_max_runner_count(pools: pools) != ci_runner_pool_min_runner_count(pools: pools) } From e233966f16a9058d1f6d624971ebc4ccdda6fe19 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 01:17:54 +0000 Subject: [PATCH 16/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/workflow/ci.dag | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index a7912b811b3..54b017798ff 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -827,9 +827,7 @@ fn ci_m1_probe_cargo_fanout_slots(pools: List) -> Int { let max_runners = ci_runner_pool_max_runner_count(pools: pools) let total_runners = ci_runner_pool_total_runner_count(pools: pools) let hosts = ci_runner_pool_host_count(pools: pools) - (total_runners - min_runners) - * hosts - / ci_runner_pool_runner_spread(max_runners: max_runners, min_runners: min_runners) + (total_runners - min_runners) * hosts / ci_runner_pool_runner_spread(max_runners: max_runners, min_runners: min_runners) } From 371f2906d80f9b051d32a889eea97c7563988cde Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 01:21:03 +0000 Subject: [PATCH 17/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/workflow/ci.dag | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 54b017798ff..c65c1b74ae0 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -832,8 +832,7 @@ fn ci_m1_probe_cargo_fanout_slots(pools: List) -> Int { fn ci_m1_probe_cargo_check_jobs_from_pools(pools: List) -> Int { - ci_runner_pool_min_jobserver_token_cap(pools: pools) - / ci_int_at_least_one(n: ci_m1_probe_cargo_fanout_slots(pools: pools)) + ci_runner_pool_min_jobserver_token_cap(pools: pools) / ci_int_at_least_one(n: ci_m1_probe_cargo_fanout_slots(pools: pools)) } From b06f7665b754cd76656a9b3155252e4d6170f953 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 01:30:09 +0000 Subject: [PATCH 18/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v3/compiler/src/v4_ci_runner_pool.rs | 17 ++++ .../v4_workflow_ci_runner_dag_smoke_test.rs | 59 ++++++++++--- src/v4/workflow/ci.dag | 87 +++++++++++++------ 3 files changed, 125 insertions(+), 38 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index 04aa21916ef..88d380698f7 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -35,6 +35,9 @@ pub const CI_SRV2_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { pub const CI_SELF_HOSTED_RUNNER_POOLS: [SelfHostedRunnerPool; 2] = [CI_SRV1_POOL, CI_SRV2_POOL]; pub fn ci_runner_pool_min_jobserver_token_cap(pools: &[SelfHostedRunnerPool]) -> u32 { + if pools.is_empty() { + return 0; + } pools .iter() .map(|p| p.jobserver_token_cap) @@ -43,10 +46,16 @@ pub fn ci_runner_pool_min_jobserver_token_cap(pools: &[SelfHostedRunnerPool]) -> } pub fn ci_runner_pool_max_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { + if pools.is_empty() { + return 0; + } pools.iter().map(|p| p.runner_count).max().unwrap_or(0) } pub fn ci_runner_pool_min_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { + if pools.is_empty() { + return 0; + } pools.iter().map(|p| p.runner_count).min().unwrap_or(0) } @@ -122,4 +131,12 @@ mod tests { fn runner_spread_fail_closed_when_max_equals_min() { assert_eq!(ci_runner_pool_runner_spread(20, 20), 1); } + + #[test] + fn min_folds_return_zero_for_empty_pool_list() { + let empty: &[SelfHostedRunnerPool] = &[]; + assert_eq!(ci_runner_pool_min_jobserver_token_cap(empty), 0); + assert_eq!(ci_runner_pool_min_runner_count(empty), 0); + assert_eq!(ci_runner_pool_max_runner_count(empty), 0); + } } diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 7e6111d6f5c..6c1f3d9357a 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -40,6 +40,45 @@ const CI_WORKFLOW_POLICY_PREFIXES: &[&str] = &[ "scripts/workflow-path-regex-forbidden-substrings", ]; +const CI_V2_PREFIXES: &[&str] = &["src/v2/"]; +const CI_V2_EXACT_PATHS: &[&str] = &["Cargo.toml", "Cargo.lock"]; +const CI_V3_PREFIXES: &[&str] = &["src/v3/", "dsl/"]; +const CI_V4_PREFIXES: &[&str] = &[ + "src/v4/", + "fixtures/v4-mvp1/", + "scripts/v4-mvp1", + "scripts/v4-m1", + "scripts/v4-testclaim-", + "dsl/std/", +]; +const CI_V4_EXACT_PATHS: &[&str] = &["Cargo.toml", "Cargo.lock"]; + +fn assert_ci_dag_rust_prefix_parity(prefixes: &[&str]) { + for prefix in prefixes { + assert!( + CI_DAG.contains(&format!("prefix: \"{prefix}\"")), + "{CI_DAG_PATH}: authority must declare prefix `{prefix}`" + ); + assert!( + V4_CI_COMPONENT_AFFECTED_RS.contains(&format!("\"{prefix}\"")), + "v4_ci_component_affected.rs mirror must declare prefix `{prefix}`" + ); + } +} + +fn assert_ci_dag_rust_exact_path_parity(paths: &[&str]) { + for path in paths { + assert!( + CI_DAG.contains(&format!("changed == \"{path}\"")), + "{CI_DAG_PATH}: authority must declare exact path `{path}`" + ); + assert!( + V4_CI_COMPONENT_AFFECTED_RS.contains(&format!("\"{path}\"")), + "v4_ci_component_affected.rs mirror must declare exact path `{path}`" + ); + } +} + fn parse_module(source: &str, path: &str) -> v3_compiler::parse_surface::SurfaceModule { let tokens = tokenize_for_test(source, path).unwrap_or_else(|e| panic!("{path}: tokenize: {e:?}")); @@ -247,16 +286,16 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { #[test] fn v4_workflow_ci_workflow_policy_prefixes_align_rust_mirror() { - for prefix in CI_WORKFLOW_POLICY_PREFIXES { - assert!( - CI_DAG.contains(&format!("prefix: \"{prefix}\"")), - "{CI_DAG_PATH}: workflow_policy authority must declare prefix `{prefix}`" - ); - assert!( - V4_CI_COMPONENT_AFFECTED_RS.contains(&format!("\"{prefix}\"")), - "v4_ci_component_affected.rs mirror must declare prefix `{prefix}`" - ); - } + assert_ci_dag_rust_prefix_parity(CI_WORKFLOW_POLICY_PREFIXES); +} + +#[test] +fn v4_workflow_ci_component_bucket_prefixes_align_rust_mirror() { + assert_ci_dag_rust_prefix_parity(CI_V2_PREFIXES); + assert_ci_dag_rust_prefix_parity(CI_V3_PREFIXES); + assert_ci_dag_rust_prefix_parity(CI_V4_PREFIXES); + assert_ci_dag_rust_exact_path_parity(CI_V2_EXACT_PATHS); + assert_ci_dag_rust_exact_path_parity(CI_V4_EXACT_PATHS); } #[test] diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index c65c1b74ae0..975892ee55f 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -49,7 +49,8 @@ import v4.std.node { import v4.std.algebra { fold_list } import v4.std.collection { List } import v4.std.text { Char, String } -import v4.std.diagnostic {Correction, Diagnostic, Extent, Locus, NoCorrectionReason, Outcome, Accepted, None, diagnostics_singleton} +import v4.std.diagnostic {Correction, Diagnostic, Extent, Locus, NoCorrectionReason, Outcome, Accepted, Rejected, None, diagnostics_singleton} +import v4.std.integer { int_mul, int_div } import v4.std.algebra { count_equal, count_where, @@ -112,10 +113,9 @@ type CiComponentAffected { // RULING-1: 🟢 pretty-much-done — host `git diff --name-only` read outcome (T-24 / INVARIANTS P3). // `ReadFailClosed` selects the superset `ci_component_affected_fail_closed` (all flags true). -type CiGitDiffReadOutcome { - ReadOk: GitDiffNameOnly - ReadFailClosed: Diagnostic -} +type CiGitDiffReadOutcome + = ReadOk { git_diff: GitDiffNameOnly } + | ReadFailClosed { diagnostic: Diagnostic } data ci_git_diff_read_fail_closed_reason: Symbol = ci_git_diff_read_fail_closed_reason @@ -123,6 +123,7 @@ data ci_git_diff_read_fail_closed_reason: Symbol = ci_git_diff_read_fail_closed_ // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. type RunnerArch = Arm64 + | RunnerArchUnknown type SelfHostedRunnerPool { host: Symbol @@ -259,6 +260,18 @@ data ci_dangling_reference: Symbol = ci_dangling_reference data ci_dependency_cycle: Symbol = ci_dependency_cycle data ci_bootstrap_authority_violation: Symbol = ci_bootstrap_authority_violation data ci_workflow_file: Symbol = ci_workflow_file +data ci_int_min_fold_sentinel: Int = 999999999 + +fn ci_int_div_totalizing(a: Int, b: Int) -> Int { + match int_div( + a: a, + b: b, + at: Textual { file: ci_workflow_file, extent: WholeFile } + ) { + Accepted { value: quotient, diagnostics: _ } => quotient + Rejected { diagnostics: _ } => 1 + } +} fn ci_diagnostic(reason: Symbol) -> Diagnostic { Diagnostic { @@ -767,35 +780,47 @@ data ci_runner_pool_m1_probe_witness: Bool = ci_runner_pool_m1_probe_witness_hol fn ci_runner_pool_min_jobserver_token_cap(pools: List) -> Int { - fold(pools, init: ci_srv2_pool.jobserver_token_cap, f: fn(acc, pool) { - if pool.jobserver_token_cap < acc { - pool.jobserver_token_cap - } else { - acc - } - }) + if length(xs: pools) == 0 { + 0 + } else { + fold(pools, init: ci_int_min_fold_sentinel, f: fn(acc, pool) { + if pool.jobserver_token_cap < acc { + pool.jobserver_token_cap + } else { + acc + } + }) + } } fn ci_runner_pool_max_runner_count(pools: List) -> Int { - fold(pools, init: 0, f: fn(acc, pool) { - if pool.runner_count > acc { - pool.runner_count - } else { - acc - } - }) + if length(xs: pools) == 0 { + 0 + } else { + fold(pools, init: 0, f: fn(acc, pool) { + if pool.runner_count > acc { + pool.runner_count + } else { + acc + } + }) + } } fn ci_runner_pool_min_runner_count(pools: List) -> Int { - fold(pools, init: ci_srv1_pool.runner_count, f: fn(acc, pool) { - if pool.runner_count < acc { - pool.runner_count - } else { - acc - } - }) + if length(xs: pools) == 0 { + 0 + } else { + fold(pools, init: ci_int_min_fold_sentinel, f: fn(acc, pool) { + if pool.runner_count < acc { + pool.runner_count + } else { + acc + } + }) + } } @@ -827,12 +852,18 @@ fn ci_m1_probe_cargo_fanout_slots(pools: List) -> Int { let max_runners = ci_runner_pool_max_runner_count(pools: pools) let total_runners = ci_runner_pool_total_runner_count(pools: pools) let hosts = ci_runner_pool_host_count(pools: pools) - (total_runners - min_runners) * hosts / ci_runner_pool_runner_spread(max_runners: max_runners, min_runners: min_runners) + ci_int_div_totalizing( + a: int_mul(a: total_runners - min_runners, b: hosts), + b: ci_runner_pool_runner_spread(max_runners: max_runners, min_runners: min_runners) + ) } fn ci_m1_probe_cargo_check_jobs_from_pools(pools: List) -> Int { - ci_runner_pool_min_jobserver_token_cap(pools: pools) / ci_int_at_least_one(n: ci_m1_probe_cargo_fanout_slots(pools: pools)) + ci_int_div_totalizing( + a: ci_runner_pool_min_jobserver_token_cap(pools: pools), + b: ci_int_at_least_one(n: ci_m1_probe_cargo_fanout_slots(pools: pools)) + ) } From 248fd6f3f2647d987e191bb3f6ac50601af748d5 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 01:49:44 +0000 Subject: [PATCH 19/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../compiler/src/v4_ci_component_affected.rs | 32 +++++++------------ 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index 67ed1774409..d8db6dcc7b5 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -113,26 +113,18 @@ mod tests { #[test] fn workflow_policy_paths_match_ci_dag_authority() { - assert_eq!( - ci_changed_path_affects_workflow_policy("src/v4/workflow/ci.dag"), - true - ); - assert_eq!( - ci_changed_path_affects_workflow_policy("src/v3/compiler/src/v4_ci_runner_pool.rs"), - true - ); - assert_eq!( - ci_changed_path_affects_workflow_policy( - "src/v3/compiler/src/v4_ci_component_affected.rs" - ), - true - ); - assert_eq!( - ci_changed_path_affects_workflow_policy( - "src/v3/compiler/src/bin/detect_ci_affected_components.rs" - ), - true - ); + assert!(ci_changed_path_affects_workflow_policy( + "src/v4/workflow/ci.dag" + )); + assert!(ci_changed_path_affects_workflow_policy( + "src/v3/compiler/src/v4_ci_runner_pool.rs" + )); + assert!(ci_changed_path_affects_workflow_policy( + "src/v3/compiler/src/v4_ci_component_affected.rs" + )); + assert!(ci_changed_path_affects_workflow_policy( + "src/v3/compiler/src/bin/detect_ci_affected_components.rs" + )); } #[test] From f45a3b95e360a3a6b8c65638d74c4a93b9c0a15e Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 01:58:37 +0000 Subject: [PATCH 20/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/workflow/ci.dag | 36 ++++++++---------------------------- 1 file changed, 8 insertions(+), 28 deletions(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 975892ee55f..ba572adfb0c 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -52,12 +52,14 @@ import v4.std.text { Char, String } import v4.std.diagnostic {Correction, Diagnostic, Extent, Locus, NoCorrectionReason, Outcome, Accepted, Rejected, None, diagnostics_singleton} import v4.std.integer { int_mul, int_div } import v4.std.algebra { + any, count_equal, count_where, filter, for_all, is_prefix_of, length, + non_empty, unique } import v4.std.verification { @@ -701,14 +703,6 @@ fn ci_changed_path_affects_workflow_policy(changed: RepoPath) -> Bool { } -fn ci_any_changed_path_matches( - changed_paths: List, - predicate: fn(RepoPath) -> Bool -) -> Bool { - count_where(xs: changed_paths, predicate: predicate) != 0 -} - - fn ci_component_affected_fail_closed() -> CiComponentAffected { CiComponentAffected { v2: true @@ -721,20 +715,11 @@ fn ci_component_affected_fail_closed() -> CiComponentAffected { fn ci_component_affected_from_git_diff(git_diff: GitDiffNameOnly) -> CiComponentAffected { CiComponentAffected { - v2: ci_any_changed_path_matches( - changed_paths: git_diff.changed_paths, - predicate: ci_changed_path_affects_v2 - ), - v3: ci_any_changed_path_matches( - changed_paths: git_diff.changed_paths, - predicate: ci_changed_path_affects_v3 - ), - v4: ci_any_changed_path_matches( - changed_paths: git_diff.changed_paths, - predicate: ci_changed_path_affects_v4 - ), - workflow_policy: ci_any_changed_path_matches( - changed_paths: git_diff.changed_paths, + v2: any(xs: git_diff.changed_paths, predicate: ci_changed_path_affects_v2), + v3: any(xs: git_diff.changed_paths, predicate: ci_changed_path_affects_v3), + v4: any(xs: git_diff.changed_paths, predicate: ci_changed_path_affects_v4), + workflow_policy: any( + xs: git_diff.changed_paths, predicate: ci_changed_path_affects_workflow_policy ) } @@ -758,18 +743,13 @@ fn ci_int_at_least_one(n: Int) -> Int { } -fn ci_runner_pool_is_nonempty(pools: List) -> Bool { - length(xs: pools) != 0 -} - - fn ci_runner_pool_has_nonuniform_runner_counts(pools: List) -> Bool { ci_runner_pool_max_runner_count(pools: pools) != ci_runner_pool_min_runner_count(pools: pools) } fn ci_runner_pool_m1_probe_witness_holds(pools: List) -> Bool { - ci_runner_pool_is_nonempty(pools: pools) + non_empty(xs: pools) && ci_runner_pool_has_nonuniform_runner_counts(pools: pools) } From 820e6da8deccf79abdf84ccb004fd4b370c6d529 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 02:00:05 +0000 Subject: [PATCH 21/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v4_workflow_ci_runner_dag_smoke_test.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 6c1f3d9357a..de5df4848ff 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -274,6 +274,22 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { import_includes_name(&module, &["v4", "std", "algebra"], "filter"), "{CI_DAG_PATH}: must import filter from std.algebra" ); + assert!( + import_includes_name(&module, &["v4", "std", "algebra"], "any"), + "{CI_DAG_PATH}: must import any from std.algebra for path-bucket existence" + ); + assert!( + import_includes_name(&module, &["v4", "std", "algebra"], "non_empty"), + "{CI_DAG_PATH}: must import non_empty from std.algebra for runner-pool witness" + ); + assert!( + CI_DAG.contains("any(xs: git_diff.changed_paths, predicate: ci_changed_path_affects_v2)"), + "{CI_DAG_PATH}: component affected-set must use std.algebra any" + ); + assert!( + CI_DAG.contains("non_empty(xs: pools)"), + "{CI_DAG_PATH}: M1 probe witness must use std.algebra non_empty" + ); assert!( CI_DAG.contains("RerunNodeSetFailClosed { evidence: _ } => roster"), "{CI_DAG_PATH}: fail-closed must return full roster on RerunNodeSetFailClosed (AI-16/R1-7)" From da99b934413a570a0f2df2be9d5bae270e9a1f22 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 02:04:21 +0000 Subject: [PATCH 22/56] fix(ci): complete Wasm/Swift law-key handlers in strict_deprose_dag.py Main landed incomplete WasmModelCoreLawKey/SwiftModelCoreLawKey return blocks (unclosed '('); GitHub PR merge replayed that blob and broke test_strict_deprose_dag.py. Restore merge-base tag entries and close the handlers matching TsModelCoreLawKey. Co-authored-by: Cursor --- scripts/strict_deprose_dag.py | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/scripts/strict_deprose_dag.py b/scripts/strict_deprose_dag.py index 2434319a669..51f2ac2b227 100644 --- a/scripts/strict_deprose_dag.py +++ b/scripts/strict_deprose_dag.py @@ -295,6 +295,8 @@ def coproduct_tag_from_merge_base(rel: str) -> dict[str, tuple[str, str]]: "SwiftConcreteSyntaxToken", ): out[nm] = ("🟢", "CP-3229-GREEN-TERMINAL") + # T-4 Wave 2b law-kind coproduct (absent at merge-base; scaffold:T-4-wave-2b). + out["SwiftModelCoreLawKey"] = ("🟡", "SL-T4-WAVE2B-SWIFT-LAW-KEY") if rel == "src/v4/extdeps/languages/wasm.dag": # New T-4/T-11 language slice (absent at merge-base). for nm in ( @@ -304,6 +306,8 @@ def coproduct_tag_from_merge_base(rel: str) -> dict[str, tuple[str, str]]: "WasmConcreteSyntaxToken", ): out[nm] = ("🟢", "CP-3229-GREEN-TERMINAL") + # T-4 Wave 2b law-kind coproduct (absent at merge-base; scaffold:T-4-wave-2b). + out["WasmModelCoreLawKey"] = ("🟡", "SL-T4-WAVE2B-WASM-LAW-KEY") if rel == "src/v4/std/integer.dag": # T-3A shared-fact vocabulary for T-4 language primitive fact-bundles # (absent at merge-base). @@ -438,6 +442,24 @@ def format_coproduct_tag(emoji: str, ref: str, type_name: str | None = None) -> "dissolve-on-arrival: std/algebra exports typed law/equation Nodes replacing " "kind atoms (same gate as model_core ModelCoreWave1BoolLawKey)." ) + if type_name == "WasmModelCoreLawKey": + return ( + "// 🟡 coproduct dissolution — SL-T4-WAVE2B-WASM-LAW-KEY — " + "feature:model-core-law-expression-carrier — " + "scaffold:T-4-wave-2b · law-kind coproduct for wasm_model_core_law_node kind edge — " + "owner:T-4 wasm language model lane — " + "dissolve-on-arrival: std/algebra exports typed law/equation Nodes replacing " + "kind atoms (same gate as model_core ModelCoreWave1BoolLawKey)." + ) + if type_name == "SwiftModelCoreLawKey": + return ( + "// 🟡 coproduct dissolution — SL-T4-WAVE2B-SWIFT-LAW-KEY — " + "feature:model-core-law-expression-carrier — " + "scaffold:T-4-wave-2b · law-kind coproduct for swift_model_core_law_node kind edge — " + "owner:T-4 swift language model lane — " + "dissolve-on-arrival: std/algebra exports typed law/equation Nodes replacing " + "kind atoms (same gate as model_core ModelCoreWave1BoolLawKey)." + ) return f"// {emoji} coproduct dissolution · {ref}." From 1096ee4513dd9936e5198f5e354da04ecd6f0cd9 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 02:24:13 +0000 Subject: [PATCH 23/56] fix(p5): cite T-PB-A for T-24 non-test hand-Rust receipts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EXPECTED_HAND_AUTHORED_NON_TEST paths must name pb_hand_rust_at_shim_floor (T-PB-A), not pb_rust_tests_outside_residual_zero (T-PB-B test subset). Align INVARIANTS §P5(b) rows and sg0-pr-body-append.3853.txt with emit_rust_bin_shim.rs peer pattern (claude RC 20162). Co-authored-by: Cursor --- INVARIANTS.md | 6 +++--- scripts/ci-merge/sg0-pr-body-append.3853.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/INVARIANTS.md b/INVARIANTS.md index 631f30ddf36..324afdfdd05 100644 --- a/INVARIANTS.md +++ b/INVARIANTS.md @@ -495,7 +495,7 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED |------|---------| | `src/v3/compiler/benches/tier3_mirror_perf.rs` | **ROADMAP:** `ROADMAP.md` — **Tier-3 perf-budget Phase-1** / T-Tier3-Dissolution (`docs/briefs/r3-pb-tier3-perf-budget-worker.md`; parent brief #1331). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when Tier3 host mirrors dissolve per `docs/r3-structure.md` §Acceptance (Criterion harness no longer targets hot Rust substrate entrypoints). **Interim ratchet:** frozen `tier3_baseline.json` + bench stays `--locked` clean under CI. | | `src/v3/compiler/build.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor`; **authority:** `dsl/gunbc/compiler.dag` **stage0** (`stage0.hand_maintained_src` / regen edges surfaced to Cargo). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** `build.rs` mirror retires when stage ordering + copy/hash contracts are enforced only via `.dag` emit programs (`SELF_HOSTING.md` §2). **Interim ratchet:** bootstrap snapshot + fmt/ci gates keep `build.rs` aligned with `compiler.dag`. | -| `src/v3/compiler/src/bin/detect_ci_affected_components.rs` | **TASKS.md** T-24 — host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (dissolves `scripts/detect-affected-components.sh`; path buckets single-authority in `src/v4/workflow/ci.dag`). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR as the bin. **Dissolution:** delete when affected-component projection runs from `.dag` eval / generated CI runner without this hand `main`. **Interim ratchet:** `v4_ci_component_affected` unit tests + `v4_workflow_ci_runner_dag_smoke_test` alignment with `ci.dag`. | +| `src/v3/compiler/src/bin/detect_ci_affected_components.rs` | **TASKS.md** T-24 — host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (dissolves `scripts/detect-affected-components.sh`; path buckets single-authority in `src/v4/workflow/ci.dag`). **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR as the bin. **Dissolution:** delete when affected-component projection runs from `.dag` eval / generated CI runner without this hand `main`. **Interim ratchet:** `v4_ci_component_affected` unit tests + `v4_workflow_ci_runner_dag_smoke_test` alignment with `ci.dag`. | | `src/v3/compiler/src/bin/gunbc_ci.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** + **T-Workflow-As-Data** — `bin/gunbc_ci` host shim for modeled CI (`dsl/gunbc/ci.dag`). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when CI selection + receipts are emitted/invoked without a hand `main` (`SELF_HOSTING.md` §2.2). **Interim ratchet:** `gunbc_ci` integration tests + SG-0 census. | | `src/v3/compiler/src/bin/r1c_e_emit_gates.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / R1C-E emit gates (`docs/r3-program-plan.md` T-Emit `.dag` `TestClaim` lane). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit-gate checks are invoked only from generated/bootstrap harness without this bin. **Interim ratchet:** `r1c_e_gates.rs` shared checks + integration harness. | | `src/v3/compiler/src/bin/regen_bootstrap.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — regen **bootstrap** stage host entry (`dsl/gunbc/regen*.dag` family). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when bootstrap regen is a single declared pipeline command with no parallel Rust `main`. **Interim ratchet:** `regen_bootstrap_emit.rs` + bootstrap snapshot CI. | @@ -524,8 +524,8 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED | `src/v3/compiler/src/emit_rust_bin_shim.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | | `src/v3/compiler/src/emit_rust_roundtrip_fixtures.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | | `src/v3/compiler/src/enforced_lens_application.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **Plan:** `docs/r3-program-plan.md` §1.8 gate **#95** `opt_in_iteration_parallelism_via_lens_application_demonstrated` — parallelism iteration LAS consumer routes violation decisions through authored `parallelism_enforcement_violates` in `src/v3/lenses/parallelism.dag` via `apply_lens_declaration` in `src/v3/compiler/src/lens_declaration_apply.rs` (single substrate authority); Rust maps only `loop_iteration_parallel_emission_indicator` → observed `ParallelismMode`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Co-receipt (same PR, P5 single surface):** gate **#95** SG-0 census net **+1** on `EXPECTED_HAND_AUTHORED_TEST` + pairing `(c)` text are prepended via `scripts/ci-merge/sg0-pr-body-append.3131.txt`; that append is the **single** checkable PR-body bundle listing every gate **#95** co-touched non-test path (`enforced_lens_application.rs`, `dag.rs`, `lib.rs`, `lower.rs` — roles spelled out in the prepend) alongside this amended row. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/v4_ci_component_affected.rs` | **TASKS.md** T-24 — Rust mirror of `ci_component_affected_from_git_diff` path buckets (`src/v4/workflow/ci.dag` is authority; must stay aligned per `ci.dag` workflow_policy predicates). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when `detect-ci-affected-components` invokes `.dag` eval over `ci.dag` predicates with no parallel Rust path logic. **Interim ratchet:** `workflow_policy_paths_match_ci_dag_authority` unit test + integration smoke. | -| `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_derived_as_four` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | +| `src/v3/compiler/src/v4_ci_component_affected.rs` | **TASKS.md** T-24 — Rust mirror of `ci_component_affected_from_git_diff` path buckets (`src/v4/workflow/ci.dag` is authority; must stay aligned per `ci.dag` workflow_policy predicates). **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when `detect-ci-affected-components` invokes `.dag` eval over `ci.dag` predicates with no parallel Rust path logic. **Interim ratchet:** `workflow_policy_paths_match_ci_dag_authority` unit test + integration smoke. | +| `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_derived_as_four` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | | `src/v3/compiler/src/gunbc_ci.rs` | **ROADMAP:** `ROADMAP.md` § **Forward-Tracked Lane: T-Workflow-As-Data** (≈L57–L63; substrate lane feeding program gate **#103** `ci_uses_affected_set_selection` per `docs/r3-program-plan.md` + `docs/briefs/r3-wave1-s6-slice7-affected-set-impl-worker.md`). **Additional ROADMAP receipt:** `ROADMAP.md` § **Lane acceptance** row **T-TestGen** / `testgen_manual_claim_is_first_class` (first-class `TestClaim` execution) + row **T-PB-B** / `pb_rust_tests_outside_residual_zero` (tests-as-data) carry the Lens-CI `MechanicalReverification` host bridge for `v4.lens.subsumption.DissolutionSubsumption` rows while the `.dag` TestClaim runner is staged. **Dissolution:** remove when `CIWorkflowDag` affected-gate dispatch is owned by `.dag` programs / generated `TestClaim` receipts (or the dag compiler emits selection) with **no** parallel Rust mirror over the `dsl/gunbc/ci.dag` carrier; also remove the `MechanicalReverification` host bridge when the v4 `.dag` TestClaim runner consumes `MechanicalReverification { test_claim }` rows and reports the same `Verified` / `NotVerified` / `Unverifiable` verdict as substrate data. **Interim ratchet:** `select_affected_gates` + in-module hermetic tests pin symmetric edge-expansion semantics consistent with `CIGateEdge { from, to }` in `dsl/gunbc/ci.dag`; `mechanical_reverification_verdict` + in-module hermetic tests pin fail-closed subsumption verdicts with nominal `DiffId`, `TestClaimId`, and `ProducerStageId` mirrors. | | `src/v3/compiler/src/infer.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | | `src/v3/compiler/src/int_literal_ranges.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | diff --git a/scripts/ci-merge/sg0-pr-body-append.3853.txt b/scripts/ci-merge/sg0-pr-body-append.3853.txt index b0ae6c67daa..981ca9e5a7a 100644 --- a/scripts/ci-merge/sg0-pr-body-append.3853.txt +++ b/scripts/ci-merge/sg0-pr-body-append.3853.txt @@ -1,3 +1,3 @@ SG-0 hand-path delta: +3 -SG-0 pairing: (c) Net +3 on `EXPECTED_HAND_AUTHORED_NON_TEST` for T-24 host-transport shims (`detect_ci_affected_components.rs`, `v4_ci_component_affected.rs`, `v4_ci_runner_pool.rs`) with matching INVARIANTS §P5(b) rows. Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). +SG-0 pairing: (c) Net +3 on `EXPECTED_HAND_AUTHORED_NON_TEST` (T-PB-A / `pb_hand_rust_at_shim_floor` non-test census per `ROADMAP.md:179`) for T-24 host-transport shims (`detect_ci_affected_components.rs`, `v4_ci_component_affected.rs`, `v4_ci_runner_pool.rs`) with matching INVARIANTS §P5(b) rows. Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). From c02b9c80860275c80818e0ed12506e7f6ed37468 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 02:54:36 +0000 Subject: [PATCH 24/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/workflow/ci.dag | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index ba572adfb0c..0c768b2877c 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -114,13 +114,8 @@ type CiComponentAffected { } // RULING-1: 🟢 pretty-much-done — host `git diff --name-only` read outcome (T-24 / INVARIANTS P3). -// `ReadFailClosed` selects the superset `ci_component_affected_fail_closed` (all flags true). -type CiGitDiffReadOutcome - = ReadOk { git_diff: GitDiffNameOnly } - | ReadFailClosed { diagnostic: Diagnostic } - -data ci_git_diff_read_fail_closed_reason: Symbol = ci_git_diff_read_fail_closed_reason - +// `Rejected` selects the superset `ci_component_affected_fail_closed` (all flags true). +// Uses canonical `Outcome` from std.diagnostic (Practice 10 — no parallel read carrier). // RULING-1: 🟢 pretty-much-done — self-hosted fleet substrate (operator 2026-05-28: srv1/srv2 Ampere Altra). // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. type RunnerArch @@ -262,18 +257,7 @@ data ci_dangling_reference: Symbol = ci_dangling_reference data ci_dependency_cycle: Symbol = ci_dependency_cycle data ci_bootstrap_authority_violation: Symbol = ci_bootstrap_authority_violation data ci_workflow_file: Symbol = ci_workflow_file -data ci_int_min_fold_sentinel: Int = 999999999 - -fn ci_int_div_totalizing(a: Int, b: Int) -> Int { - match int_div( - a: a, - b: b, - at: Textual { file: ci_workflow_file, extent: WholeFile } - ) { - Accepted { value: quotient, diagnostics: _ } => quotient - Rejected { diagnostics: _ } => 1 - } -} +data ci_runner_pool_m1_witness_violation: Symbol = ci_runner_pool_m1_witness_violation fn ci_diagnostic(reason: Symbol) -> Diagnostic { Diagnostic { From e99b157056bbf73363ea1b7a326650a358f7e3bb Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 02:56:17 +0000 Subject: [PATCH 25/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v3/compiler/src/v4_ci_runner_pool.rs | 93 +++++------ .../v4_workflow_ci_runner_dag_smoke_test.rs | 24 +++ .../claim/workflow/runner_pool_m1_probe.dag | 15 +- src/v4/workflow/ci.dag | 152 +++++++++--------- 4 files changed, 151 insertions(+), 133 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index 88d380698f7..c26f057afb8 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -34,29 +34,24 @@ pub const CI_SRV2_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { pub const CI_SELF_HOSTED_RUNNER_POOLS: [SelfHostedRunnerPool; 2] = [CI_SRV1_POOL, CI_SRV2_POOL]; -pub fn ci_runner_pool_min_jobserver_token_cap(pools: &[SelfHostedRunnerPool]) -> u32 { - if pools.is_empty() { - return 0; - } - pools +pub fn ci_fleet_min_jobserver_token_cap() -> u32 { + CI_SELF_HOSTED_RUNNER_POOLS .iter() - .map(|p| p.jobserver_token_cap) - .min() - .unwrap_or(0) + .fold(CI_SRV1_POOL.jobserver_token_cap, |acc, pool| { + acc.min(pool.jobserver_token_cap) + }) } -pub fn ci_runner_pool_max_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { - if pools.is_empty() { - return 0; - } - pools.iter().map(|p| p.runner_count).max().unwrap_or(0) +pub fn ci_fleet_max_runner_count() -> u32 { + CI_SELF_HOSTED_RUNNER_POOLS + .iter() + .fold(CI_SRV1_POOL.runner_count, |acc, pool| acc.max(pool.runner_count)) } -pub fn ci_runner_pool_min_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { - if pools.is_empty() { - return 0; - } - pools.iter().map(|p| p.runner_count).min().unwrap_or(0) +pub fn ci_fleet_min_runner_count() -> u32 { + CI_SELF_HOSTED_RUNNER_POOLS + .iter() + .fold(CI_SRV1_POOL.runner_count, |acc, pool| acc.min(pool.runner_count)) } pub fn ci_runner_pool_total_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { @@ -71,39 +66,37 @@ pub fn ci_int_at_least_one(n: u32) -> u32 { n.max(1) } -pub fn ci_runner_pool_has_nonuniform_runner_counts(pools: &[SelfHostedRunnerPool]) -> bool { - ci_runner_pool_max_runner_count(pools) != ci_runner_pool_min_runner_count(pools) -} - pub fn ci_runner_pool_m1_probe_witness_holds(pools: &[SelfHostedRunnerPool]) -> bool { - !pools.is_empty() && ci_runner_pool_has_nonuniform_runner_counts(pools) + !pools.is_empty() && ci_fleet_max_runner_count() != ci_fleet_min_runner_count() } -pub fn ci_runner_pool_runner_spread(max_runners: u32, min_runners: u32) -> u32 { - if max_runners == min_runners { - 1 - } else { - max_runners - min_runners +pub fn ci_m1_probe_cargo_fanout_slots_from_fleet() -> Option { + if !ci_runner_pool_m1_probe_witness_holds(&CI_SELF_HOSTED_RUNNER_POOLS) { + return None; } + let min_runners = ci_fleet_min_runner_count(); + let max_runners = ci_fleet_max_runner_count(); + let spread = max_runners - min_runners; + if spread == 0 { + return None; + } + let total_runners = ci_runner_pool_total_runner_count(&CI_SELF_HOSTED_RUNNER_POOLS); + let hosts = ci_runner_pool_host_count(&CI_SELF_HOSTED_RUNNER_POOLS); + Some((total_runners - min_runners) * hosts / spread) } -pub fn ci_m1_probe_cargo_fanout_slots(pools: &[SelfHostedRunnerPool]) -> u32 { - let min_runners = ci_runner_pool_min_runner_count(pools); - let max_runners = ci_runner_pool_max_runner_count(pools); - let total_runners = ci_runner_pool_total_runner_count(pools); - let hosts = ci_runner_pool_host_count(pools); - let spread = ci_runner_pool_runner_spread(max_runners, min_runners); - (total_runners - min_runners) * hosts / spread -} - -pub fn ci_m1_probe_cargo_check_jobs_from_pools(pools: &[SelfHostedRunnerPool]) -> u32 { - let fanout = ci_int_at_least_one(ci_m1_probe_cargo_fanout_slots(pools)); - ci_runner_pool_min_jobserver_token_cap(pools) / fanout +pub fn ci_m1_probe_cargo_check_jobs_from_fleet() -> Option { + let fanout = ci_m1_probe_cargo_fanout_slots_from_fleet()?; + let fanout = ci_int_at_least_one(fanout); + if fanout == 0 { + return None; + } + Some(ci_fleet_min_jobserver_token_cap() / fanout) } /// Modeled authority for `data m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. pub fn m1_probe_cargo_check_jobs() -> u32 { - ci_m1_probe_cargo_check_jobs_from_pools(&CI_SELF_HOSTED_RUNNER_POOLS) + ci_m1_probe_cargo_check_jobs_from_fleet().unwrap_or(0) } #[cfg(test)] @@ -120,23 +113,13 @@ mod tests { #[test] fn m1_probe_cargo_check_jobs_derived_as_four() { - assert_eq!( - ci_m1_probe_cargo_fanout_slots(&CI_SELF_HOSTED_RUNNER_POOLS), - 6 - ); + assert_eq!(ci_m1_probe_cargo_fanout_slots_from_fleet(), Some(6)); + assert_eq!(ci_m1_probe_cargo_check_jobs_from_fleet(), Some(4)); assert_eq!(m1_probe_cargo_check_jobs(), 4); } #[test] - fn runner_spread_fail_closed_when_max_equals_min() { - assert_eq!(ci_runner_pool_runner_spread(20, 20), 1); - } - - #[test] - fn min_folds_return_zero_for_empty_pool_list() { - let empty: &[SelfHostedRunnerPool] = &[]; - assert_eq!(ci_runner_pool_min_jobserver_token_cap(empty), 0); - assert_eq!(ci_runner_pool_min_runner_count(empty), 0); - assert_eq!(ci_runner_pool_max_runner_count(empty), 0); + fn witness_required_for_fleet_m1_derivation() { + assert!(ci_runner_pool_m1_probe_witness_holds(&CI_SELF_HOSTED_RUNNER_POOLS)); } } diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index de5df4848ff..ec2bf7f0637 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -290,6 +290,30 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { CI_DAG.contains("non_empty(xs: pools)"), "{CI_DAG_PATH}: M1 probe witness must use std.algebra non_empty" ); + assert!( + !CI_DAG.contains("CiGitDiffReadOutcome"), + "{CI_DAG_PATH}: git diff read must use canonical Outcome, not a parallel coproduct" + ); + assert!( + CI_DAG.contains("ci_component_affected_from_git_diff_read(outcome: Outcome)"), + "{CI_DAG_PATH}: git diff read boundary must project through std.diagnostic Outcome" + ); + assert!( + !CI_DAG.contains("ci_int_div_totalizing"), + "{CI_DAG_PATH}: runner-pool arithmetic must not fabricate int_div Rejected into a plausible quotient" + ); + assert!( + !CI_DAG.contains("ci_int_min_fold_sentinel"), + "{CI_DAG_PATH}: fleet min folds must seed from ci_srv1_pool rows, not a magic sentinel" + ); + assert!( + CI_DAG.contains("init: ci_srv1_pool.runner_count"), + "{CI_DAG_PATH}: fleet min/max folds must seed from modeled srv1 pool row" + ); + assert!( + CI_DAG.contains("ci_m1_probe_cargo_fanout_slots_from_fleet()"), + "{CI_DAG_PATH}: M1 fanout must derive through witness-gated Outcome fleet API" + ); assert!( CI_DAG.contains("RerunNodeSetFailClosed { evidence: _ } => roster"), "{CI_DAG_PATH}: fail-closed must return full roster on RerunNodeSetFailClosed (AI-16/R1-7)" diff --git a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag index c1ac33cc683..c21649228a5 100644 --- a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag +++ b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag @@ -4,11 +4,12 @@ module v4.test.claim.workflow.runner_pool_m1_probe import v4.std.collection { List } +import v4.std.diagnostic { Accepted, Outcome, Rejected } import v4.std.logic { Bool } import v4.workflow.ci { SelfHostedRunnerPool, - ci_m1_probe_cargo_check_jobs_from_pools, - ci_m1_probe_cargo_fanout_slots, + ci_m1_probe_cargo_check_jobs_from_fleet, + ci_m1_probe_cargo_fanout_slots_from_fleet, ci_self_hosted_runner_pools, ci_srv1_pool, ci_srv2_pool, @@ -24,12 +25,18 @@ fn runner_pool_srv2_jobserver_cap_holds() -> Bool { } fn runner_pool_m1_fanout_slots_holds() -> Bool { - ci_m1_probe_cargo_fanout_slots(pools: ci_self_hosted_runner_pools) == 6 + match ci_m1_probe_cargo_fanout_slots_from_fleet() { + Accepted { value: fanout, diagnostics: _ } => fanout == 6 + Rejected { diagnostics: _ } => false + } } fn runner_pool_m1_cargo_jobs_holds() -> Bool { (m1_probe_cargo_check_jobs == 4) - && (ci_m1_probe_cargo_check_jobs_from_pools(pools: ci_self_hosted_runner_pools) == 4) + && match ci_m1_probe_cargo_check_jobs_from_fleet() { + Accepted { value: jobs, diagnostics: _ } => jobs == 4 + Rejected { diagnostics: _ } => false + } } data runner_pool_srv1_claim_passes: Bool = runner_pool_srv1_runner_count_holds() diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 0c768b2877c..0a171b3bfac 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -710,10 +710,11 @@ fn ci_component_affected_from_git_diff(git_diff: GitDiffNameOnly) -> CiComponent } -fn ci_component_affected_from_git_diff_read(outcome: CiGitDiffReadOutcome) -> CiComponentAffected { +fn ci_component_affected_from_git_diff_read(outcome: Outcome) -> CiComponentAffected { match outcome { - ReadOk { git_diff } => ci_component_affected_from_git_diff(git_diff: git_diff) - ReadFailClosed { diagnostic: _ } => ci_component_affected_fail_closed() + Accepted { value: git_diff, diagnostics: _ } => + ci_component_affected_from_git_diff(git_diff: git_diff) + Rejected { diagnostics: _ } => ci_component_affected_fail_closed() } } @@ -727,110 +728,113 @@ fn ci_int_at_least_one(n: Int) -> Int { } -fn ci_runner_pool_has_nonuniform_runner_counts(pools: List) -> Bool { - ci_runner_pool_max_runner_count(pools: pools) != ci_runner_pool_min_runner_count(pools: pools) +fn ci_runner_pool_total_runner_count(pools: List) -> Int { + fold(pools, init: 0, f: fn(acc, pool) { + acc + pool.runner_count + }) } -fn ci_runner_pool_m1_probe_witness_holds(pools: List) -> Bool { - non_empty(xs: pools) - && ci_runner_pool_has_nonuniform_runner_counts(pools: pools) +fn ci_runner_pool_host_count(pools: List) -> Int { + length(xs: pools) } -data ci_runner_pool_m1_probe_witness: Bool = ci_runner_pool_m1_probe_witness_holds( - pools: ci_self_hosted_runner_pools -) +fn ci_fleet_min_runner_count() -> Int { + fold(ci_self_hosted_runner_pools, init: ci_srv1_pool.runner_count, f: fn(acc, pool) { + if pool.runner_count < acc { + pool.runner_count + } else { + acc + } + }) +} -fn ci_runner_pool_min_jobserver_token_cap(pools: List) -> Int { - if length(xs: pools) == 0 { - 0 - } else { - fold(pools, init: ci_int_min_fold_sentinel, f: fn(acc, pool) { - if pool.jobserver_token_cap < acc { - pool.jobserver_token_cap - } else { - acc - } - }) - } +fn ci_fleet_max_runner_count() -> Int { + fold(ci_self_hosted_runner_pools, init: ci_srv1_pool.runner_count, f: fn(acc, pool) { + if pool.runner_count > acc { + pool.runner_count + } else { + acc + } + }) } -fn ci_runner_pool_max_runner_count(pools: List) -> Int { - if length(xs: pools) == 0 { - 0 - } else { - fold(pools, init: 0, f: fn(acc, pool) { - if pool.runner_count > acc { - pool.runner_count +fn ci_fleet_min_jobserver_token_cap() -> Int { + fold( + ci_self_hosted_runner_pools, + init: ci_srv1_pool.jobserver_token_cap, + f: fn(acc, pool) { + if pool.jobserver_token_cap < acc { + pool.jobserver_token_cap } else { acc } - }) - } + } + ) } -fn ci_runner_pool_min_runner_count(pools: List) -> Int { - if length(xs: pools) == 0 { - 0 - } else { - fold(pools, init: ci_int_min_fold_sentinel, f: fn(acc, pool) { - if pool.runner_count < acc { - pool.runner_count - } else { - acc - } - }) - } +fn ci_runner_pool_has_nonuniform_runner_counts_on_fleet() -> Bool { + ci_fleet_max_runner_count() != ci_fleet_min_runner_count() } -fn ci_runner_pool_total_runner_count(pools: List) -> Int { - fold(pools, init: 0, f: fn(acc, pool) { - acc + pool.runner_count - }) +fn ci_runner_pool_m1_probe_witness_holds(pools: List) -> Bool { + non_empty(xs: pools) + && ci_runner_pool_has_nonuniform_runner_counts_on_fleet() } -fn ci_runner_pool_host_count(pools: List) -> Int { - length(xs: pools) -} +data ci_runner_pool_m1_probe_witness: Bool = ci_runner_pool_m1_probe_witness_holds( + pools: ci_self_hosted_runner_pools +) -fn ci_runner_pool_runner_spread(max_runners: Int, min_runners: Int) -> Int { - if max_runners == min_runners { - 1 +fn ci_m1_probe_cargo_fanout_slots_from_fleet() -> Outcome { + if ci_runner_pool_m1_probe_witness { + let min_runners = ci_fleet_min_runner_count() + let max_runners = ci_fleet_max_runner_count() + let spread = max_runners - min_runners + int_div( + a: int_mul( + a: ci_runner_pool_total_runner_count(pools: ci_self_hosted_runner_pools) - min_runners, + b: ci_runner_pool_host_count(pools: ci_self_hosted_runner_pools) + ), + b: spread, + at: Textual { file: ci_workflow_file, extent: WholeFile } + ) } else { - max_runners - min_runners + Rejected { + diagnostics: diagnostics_singleton( + d: ci_diagnostic(reason: ci_runner_pool_m1_witness_violation) + ) + } } } -// Modeled concurrent M1 cargo-check fanout across the fleet: spread peer slots across -// hosts so one probe does not claim more than min(jobserver_token_cap) / fanout_slots. -fn ci_m1_probe_cargo_fanout_slots(pools: List) -> Int { - let min_runners = ci_runner_pool_min_runner_count(pools: pools) - let max_runners = ci_runner_pool_max_runner_count(pools: pools) - let total_runners = ci_runner_pool_total_runner_count(pools: pools) - let hosts = ci_runner_pool_host_count(pools: pools) - ci_int_div_totalizing( - a: int_mul(a: total_runners - min_runners, b: hosts), - b: ci_runner_pool_runner_spread(max_runners: max_runners, min_runners: min_runners) - ) +fn ci_m1_probe_cargo_check_jobs_from_fleet() -> Outcome { + match ci_m1_probe_cargo_fanout_slots_from_fleet() { + Accepted { value: fanout_slots, diagnostics: _ } => + int_div( + a: ci_fleet_min_jobserver_token_cap(), + b: ci_int_at_least_one(n: fanout_slots), + at: Textual { file: ci_workflow_file, extent: WholeFile } + ) + Rejected { diagnostics: r } => Rejected { diagnostics: r } + } } -fn ci_m1_probe_cargo_check_jobs_from_pools(pools: List) -> Int { - ci_int_div_totalizing( - a: ci_runner_pool_min_jobserver_token_cap(pools: pools), - b: ci_int_at_least_one(n: ci_m1_probe_cargo_fanout_slots(pools: pools)) - ) +fn ci_m1_probe_cargo_check_jobs_fleet_int() -> Int { + match ci_m1_probe_cargo_check_jobs_from_fleet() { + Accepted { value: jobs, diagnostics: _ } => jobs + Rejected { diagnostics: _ } => 0 + } } -data m1_probe_cargo_check_jobs: Int = ci_m1_probe_cargo_check_jobs_from_pools( - pools: ci_self_hosted_runner_pools -) +data m1_probe_cargo_check_jobs: Int = ci_m1_probe_cargo_check_jobs_fleet_int() From b90bd9d14144a4230efe1dbbfc534e134138ea6f Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 03:00:18 +0000 Subject: [PATCH 26/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- INVARIANTS.md | 124 ------------------------------------ _internal/INVARIANTS_OPS.md | 3 + 2 files changed, 3 insertions(+), 124 deletions(-) diff --git a/INVARIANTS.md b/INVARIANTS.md index aaf8764599f..1506e047f45 100644 --- a/INVARIANTS.md +++ b/INVARIANTS.md @@ -437,130 +437,6 @@ A scaffold (hand-maintained generated file, interim API surface, staged declarat - **DB-4: Clean-Emission Behavior Is A Declared Contract With Real Consumers** — same by-construction framing as E-5 - **Engineering Standards** — long-form receipts -<<<<<<< HEAD -### SG-0 hand-authored integration test receipts - -Per **Dispatch-Discipline Mechanisms (b)** above, each **new** path added to `EXPECTED_HAND_AUTHORED_TEST` in `src/v3/compiler/tests/integration/sg0_census_test.rs` must register **exactly one** checkable receipt here **in the same PR** as the census line (planning artifact home-of-record for P5). - -| Path | Receipt | -|------|---------| -| `src/v3/compiler/tests/boundary/l5_cross_target_consistency.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#15** `l5_cross_target_consistency` (T-Verification-L5-Corpus — Rust / Python / Go `ForAllTargets` certification corpus + stdout Int parity). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the harness. **Dissolution:** remove when every L5 corpus obligation is expressed and evaluated as `.dag` `TestClaim` rows (or a generated harness) without this host `rustc` / `python3` / `go` round-trip driver. **Interim ratchet:** `l5_certification_corpus_sources_match_authority_files` pins `TestClaim.source` bytes to `tests/fixtures/r3_l5_corpus/*.v3`; `l5_cross_target_consistency_gate_claim_predicate_shape` pins `ForAllTargets` + toolchain `requires`; `l5_cross_target_consistency_suite_passes_all_corpus_rows` runs suite `l5_cross_target_consistency` (documented gate command: `cargo test --release -p v3-compiler --test integration l5_`). | -| `src/v3/compiler/tests/integration/anthropic_tool_result_wire_demo_test.rs` | **ROADMAP:** `ROADMAP.md` § **PR #901 (merged)** — third bullet (`anthropic_tool_result_full_content_surface`, PR #2711 nested tool-result wire) **and** § **LLM service flattening** (`rest_request_wire_serde_alignment`, nested Anthropic tool-result contracts). **Dissolution:** remove this file when Messages tool-result nested serde is emitted **only** from `dsl/extdeps/llm/anthropic.dag` `CoproductWireContract` authorities (no hand-maintained `Serialize` mirror). **Interim ratchet:** `tool_result_wire_demo_projection_is_locked_to_modeled_dag_surface` pins demo field/variant shapes to `generated_full_bootstrap_dag()`. **Residual:** `structural_coverage_gap_anthropic_tool_result_nested_block_wire_payloads` in `dsl/extdeps/llm/anthropic.dag`. | -| `src/v3/compiler/tests/integration/cementing/cost_lens_symbolic_consumer_test.rs` | **ROADMAP:** `ROADMAP.md` § **R3 gate #78 — unary-bind `SymbolicCost` iterate alias collapse post-pass** (`per_call_pattern_at` / host-wrapper alias-collapse residual, `e_p_sub_value_relation_per_call_landed`). **Dissolution:** remove this file when the cost-lens `symbolic_cost_of` host wrapper no longer owns the alias-collapse post-pass and the `per_call_pattern_at` unary-countdown assertion is carried by the modeled lens substrate / `.dag` receipt instead of hand Rust. **Interim ratchet:** `e_p_sub_value_relation_per_call_landed_cost_lens_routes_through_per_call_pattern_query` pins the remaining consumer to the shared substrate query. **Retired role:** gate #87 Band-C `cost_symbolic` COMPLETE cementing moved to `src/v3/compiler/tests/dag/t_r3_gate_87_cementing_regen_cost_symbolic.dag` and must not be counted against this hand-Rust receipt. | -| `src/v3/compiler/tests/integration/cementing/e_p_per_call_descent_lens_consumer_cementing.rs` | **ROADMAP:** `ROADMAP.md` § **Substrate carrier port program** → **Lane E-P — per-call descent-evidence provenance (M)** (`Remaining acceptance for the broader lane: cost lens consumption and same-source v2/v3 cementing beyond the already-wired complexity recurrence consumer`). **Plan:** `docs/r3-program-plan.md` §1.8 gate **#76** `e_p_per_call_descent_evidence_full_coverage` (T-E-P-Producer-Broadening Phase-3 lens-consumer-path cementing — CONSUMER_LANDED retained, NOT PASSING). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the cementing file. **Named lane / dissolution trigger:** lens-consumer match-arm walker substrate extension under R3 Substrate Mgr standing authority (`docs/design-complexity-lens-behavioral-completeness.md` §272/§282) — `src/v3/lenses/complexity.dag` + `src/v3/lenses/cost.dag` currently fold only `Branch` behavior (`branch_summary` at `complexity.dag:330`), leaving `compose_many_inputs` unreached on match-arm result ports for ADT-typed recursive functions; producer surface is correct per `m2_substrate_inhabitance_test.rs` receipts (`StrictSubValue` + `ChildAccessorCall` projection). **Dissolution:** remove this file (or migrate the same 4 fixtures to `.dag` `TestClaim` rows) when the lens-consumer match-arm walker lands and the 4 `#[ignore]`'d ratchets can drop their `#[ignore]` markers in the same PR (Hot-fix #2723 / Pattern-A `#[ignore]`'d-scaffold precedent). **Interim ratchet:** 4 `#[ignore]`'d tests pinning frozen v2-projection shapes for `complexity_of` + `symbolic_cost_of` on match-payload + multi-arg per-arg vector fixtures (named blocker per `LENS_CONSUMER_MATCH_ARM_WALKER_BLOCKER` constant + module doc); 1 always-on `lens_consumer_match_arm_walker_blocker_constant_is_present` grep-anchor keeps the blocker constant grep-discoverable on green CI. | -| `src/v3/compiler/tests/integration/cementing/effect_enumeration_lens_behavioral_completion.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#82** `effect_enumeration_lens_behaviorally_complete` (T-Lens-Behavioral-Parity / Cluster F). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the Band-C receipt. **Dissolution:** remove when operation-row read/write/breaking effect-enumeration carrier assertions are expressible and run as `.dag` `TestClaim` rows or a generated harness without host Rust. **Interim ratchet:** `effect_enumeration_lens_behaviorally_complete_classifies_operation_reads`, `effect_enumeration_lens_behaviorally_complete_classifies_operation_writes`, and `effect_enumeration_lens_behaviorally_complete_classifies_breaking_operations_as_writes` pin generated `operation_structural_effect_shape(Operation)` consuming canonical `std.effects::operation_effect_shape`. | -| `src/v3/compiler/tests/integration/common/symbolic_cost_verification_fixture.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 — T-CostLens-Composition gates **#40** (`symbolic_cost_expr_equals_executable`) + **#70** (`cost_lens_demonstration`) integration receipts (`m1_5_verification_test.rs` / `lens_cost_target_realization_test.rs`). **Dissolution:** remove when `TestClaim` fixtures can declare expected `SymbolicCost` values for dynamic `PortId`-anchored oracles without a host-side serializer (testgen or substrate-reflected literal emission aligned with `test_runner::field_value_to_symbolic_cost_eq_pattern`). **Interim ratchet:** `symbolic_cost_as_v3_data_initializer` + `escape_v3_string_literal_content` stay aligned with the runner’s structural decode rules; unit tests in-module pin `SumCost`/`LinearCost` surface spellings. | -| `src/v3/compiler/tests/integration/cementing/cementing_provenance_origin_integration_test.rs` | **ROADMAP:** `ROADMAP.md` — Post-merge debt bullet **v3 lens capability honesty pass** (cementing-test discipline per `regen.dag`; see `docs/v3-lens-capability-register.md`). **Dissolution:** remove when `origin_of` provenance seam checks for gate-#87 regen harnesses live as `.dag` `TestClaim` obligations alongside `tests/dag/cementing_dispatch.dag` (no Rust mirror of the dispatch projection from `std.verification`'s `lens_capability_register_rows`). **Interim ratchet:** narrow slice split from the retired `cementing_lens_registry_dispatch_test.rs` monolith. | -| `src/v3/compiler/tests/integration/common/wiring_scanner_test.rs` | **ROADMAP:** same **v3 lens capability honesty pass** bullet — Band-C `tests/integration.rs` `#[path]` wiring is enforced by `integration_rs_wiring_scan.rs` + `cementing_dispatch.rs`. **Dissolution:** remove when `integration.rs` wiring can be validated structurally for cementing modules without line scanners. **Interim ratchet:** unit tests for helpers promoted from the retired `cementing_lens_registry_dispatch_test.rs` monolith. | -| `src/v3/compiler/tests/integration/ctrl_pr_digests_dag_smoke_test.rs` | **Project plan:** `docs/r4-ctrl-dag-migration-project-plan.md` §3 — catalog **#8** `dsl/ctrl/pr_digests.dag` (Wave-1 ctrl → `.dag` subsystem modeling). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke test. **Dissolution:** remove when `compile_to_dag` (or a single generated harness) validates `module … service …` ctrl carrier files end-to-end without a parallel Rust string/lexer ratchet, or when the contract migrates to `.dag` `TestClaim` coverage. **Interim ratchet:** `ctrl_pr_digests_dag_tokenizes_and_matches_expected_surface` requires clean tokenization plus presence of `module ctrl.pr_digests`, `import extdeps.github.pulls { PullRequest, PullReview, ReviewComment }`, `extdeps.github.errors` / `std.types` imports, the four Practice-4 sum/record carriers (with `🟡 STAGED` / `🟢 TERMINAL` markers per `dsl/ctrl/README.md`), `ReviewCommentBody` + `review_line_comments` wiring, and `service ctrl.PrDigests` / the four `operation` blocks / `readonly`. | -| `src/v3/compiler/tests/integration/dissolution_subsumption_carrier_test.rs` | **Design contract:** `docs/design-dissolution-lens.md` §11.2 (`DissolutionSubsumption` carrier with `subsumed_fixes: Set` set semantics + `SubsumptionVerification` coproduct). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the parse-level carrier ratchet. **Dissolution:** remove when `src/v4/lens/subsumption.dag` is exercised by `.dag` `TestClaim` rows or a generated harness that mechanically reads the carrier and first subsumption row without this host parser check. **Interim ratchet:** `dissolution_subsumption_carrier_shape_locked` parses `src/v4/lens/subsumption.dag` and asserts the `DiffId` / `TestClaimId` / `ProducerStageId` handles, the `MechanicalReverification | ProducerStageDerivation` verification coproduct, and the `DissolutionSubsumption { root_fix: DiffId, subsumed_fixes: Set, verification: SubsumptionVerification }` carrier shape (with the legacy non-empty `SubsumedFixes` / `ProducerStageDerivationPath` wrappers explicitly absent). `dissolution_subsumption_first_row_is_mechanical_reverification` asserts the first data row pins `affected_set_irt1_frontier_root_fix`, references the named `affected_set_irt1_subsumed_fixes` Set binding, and uses `MechanicalReverification` against `affected_set_irt1_leaf_claim_suite`. `affected_set_irt1_subsumed_fixes_membership_predicate_enumerates_six_leaves` asserts the `fn affected_set_irt1_subsumed_fixes_value() -> Set` helper that backs the named `affected_set_irt1_subsumed_fixes` data row references the six `affected_set_*_leaf_fix` `Symbol` handles in its `Set { member: fn(d) { … } }` predicate. `affected_set_irt1_leaf_claim_suite_authored_for_mechanical_reverification` parses `irt1_leaf_claim_suite.dag` and asserts the aggregate `TestClaim` row for the `affected_set_irt1_leaf_claim_suite` handle. | -| `src/v3/compiler/tests/integration/extdeps_sql_transport_test.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** row `T-PB-B` / `pb_rust_tests_outside_residual_zero`; this Rust integration receipt keeps HTTP/SQL/audit extdeps compiled by the existing v3 parser before downstream emission-target consumers rely on them. **Dissolution:** remove when extdeps transport and Phase 3 emission-target files are covered by a `.dag`-native parse/authority suite or generated test harness rather than per-file Rust `compile_to_dag` probes. **Interim ratchet:** `rest_transport_dag_compiles_cleanly` and `sql_transport_dag_compiles_cleanly` pin `dsl/extdeps/transports/rest.dag` and `dsl/extdeps/transports/sql.dag`; `http_server_extdep_dag_compiles_cleanly`, `sql_migration_extdep_dag_compiles_cleanly`, and `audit_cloudevents_extdep_dag_compiles_cleanly` pin `dsl/extdeps/http/server.dag`, `dsl/extdeps/sql/migration.dag`, and `dsl/extdeps/audit/cloudevents.dag` as parseable staged emission-target substrate. The field-sensitive companions (`http_server_target_fields_are_authoritative_substrate_edges`, `sql_migration_target_fields_bound_raw_sql_scaffold`, `audit_cloudevents_target_fields_preserve_core_names`) consume the new target-contract fields directly so they fail on raw `String`/`Int` regressions, missing SQL scaffold bounds, or CloudEvents alias drift while the first real projection consumer is still staged; the audit ratchet also locks CloudEvents core fields to branded carriers and `std.types.Timestamp` rather than raw strings. | -| `src/v3/compiler/tests/integration/v4_extdeps_coordination_dag_smoke_test.rs` | **TASKS.md** T-4.8 (`src/v4/extdeps/coordination.dag` — multi-program coordination as effect-typed Bind composition; PR #3207 decomposed shape with `WireContractFacts` carrying `ExchangePattern` / parameterized `SettlementGuarantee` / `ConsistencyGuarantee`, `CoordinationBind` carrying the tracked `CoordinationEffectKind` bridge, and WIRECONTRACT-OBLIGATION-TABLE-T4.8 per-effect obligation rows routed through the same guarantee discriminants with `Required*Bound` payload types rather than fabricated concrete bounds). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness; SG-0 census net +1 pairing `(c)` is mechanically prepended via `scripts/ci-merge/sg0-pr-body-append.3590.txt` in CI. **Dissolution:** remove when `src/v4/extdeps/coordination.dag` is exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust parse ratchet. **Interim ratchet:** `v4_extdeps_coordination_dag_parses`; `v4_extdeps_coordination_wire_contract_uses_decomposed_facts`; `v4_extdeps_coordination_effect_kind_has_obligation_table` tokenize/parse the pinned `include_str!` source and assert the decomposed `WireContractFacts` fields, `WireContract { facts, bind }`, tracked `CoordinationEffectKind` arms, parameterized `CoordinationEffectObligation` field types, all four obligation table entries and exchange mappings, list-literal table surface, and the `coordination_effect_obligation` / `wire_contract_obligation_table_t4_8` function surfaces. | -| `src/v3/compiler/tests/integration/v4_extdeps_react_dag_smoke_test.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; **TASKS.md** T-4.7 (`src/v4/extdeps/frameworks/react.dag`, React 19.2.0–pinned framework substrate). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when `src/v4/extdeps/frameworks/react.dag` (or the v4 extdeps fixture set it belongs to) is exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust `compile_to_dag` probe. **Interim ratchet:** `v4_extdeps_react_dag_compiles` asserts `compile_to_dag` succeeds with empty `dag.diagnostics()` for the pinned `include_str!` source. | -| `src/v3/compiler/tests/integration/v4_extdeps_file_system_dag_smoke_test.rs` | **TASKS.md** T-4.5 / Wave-2-C2 (`src/v4/extdeps/file_system.dag` — external file-system resource + modeled read/write effects; Practice 11 companion: no `import v4.std.node`, no `NodeFileBinding`; POSIX substrate exports retained for `posix.dag` / `testgen.dag`). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when `file_system.dag` is exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust probe. **Interim ratchet:** `v4_extdeps_file_system_dag_tokenizes_and_parses` plus Practice-11 companion tests (parse-surface import/type bans, POSIX-grounded `FilePath`, per-operation receipt record shapes, Wave-2 `ModeledFileEffects.file_read`/`file_write` arrow signatures + legacy `FileSystemOperations` / request-carrier coexistence). | -| `src/v3/compiler/tests/integration/v4_p9_llvm_instruction_cost_single_owner_test.rs` | **P9 single-owner (R2-1):** replaces dissolved `v4_lens_cost_dag_smoke_test.rs` ratchet — `fn llvm_instruction_cost` must appear exactly once under `src/v4/`, in `src/v4/lens/cost.dag` (whole-tree parse does **not** substitute; see `docs/v4-close-interrogation.md` §P5(b) / `feature:p9-llvm-instruction-cost-single-owner`). Complements `.dag` TestClaim `src/v4/test/claim/lens_cost/p9_llvm_instruction_cost_registry_owner.dag` (registry exclusivity). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the harness. **Dissolution:** remove when M2 reflection or generated harness executes the `.dag` claim over the full v4 corpus without this host file-walk ratchet. **Interim ratchet:** `v4_p9_llvm_instruction_cost_defined_only_in_lens_cost_dag` walks `src/v4/**/*.dag` for `fn llvm_instruction_cost`; `v4_p9_llvm_instruction_cost_absent_from_llvm_ir_dag` asserts `llvm_ir.dag` does not re-author the cost table. | -| `src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs` | **TASKS.md** T-21 + T-24 Wave-0 (`src/v4/workflow/ci.dag` — `ci_select_from_*` under canonical `v4.workflow.ci`; `affected_set_rerun_nodes` → `List`; narrow = identity-aware subtree frontier in `verification.dag`; fail-closed = full roster; `src/v4/test/claim/workflow/affected_set_ci_runner.dag` structural receipts). **Tracked substrate bridge:** `verification.dag` `test_claim_ci_selection_fail_closed` carries 🟡 gated Practice-10 predicate-dissolution mark (dissolve when `ci_select` consumes `TestClaimCacheKey` from `05_eval`). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when Node-level TestClaim CI selection is exercised only by `.dag` `TestClaim` rows / generated harness / host runner without this parse probe (full wire: edit-locus + `TestClaimExerciseSurface` + `ci.yml` — follow-on A/B/C). **Interim ratchet:** `v4_workflow_ci_dag_tokenizes_and_parses`; `v4_workflow_ci_test_claim_selection_entrypoints`; `v4_workflow_affected_set_ci_runner_claim_*` — tokenize+parse + import/entrypoint wiring receipts; fail-closed roster contract substring receipts on `RerunNodeSetFailClosed => roster` and `test_claim_ci_selection_fail_closed`. | -| `src/v3/compiler/tests/integration/v4_test_bootstrap_infra_closeout_test.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; **TASKS.md** **T-19** (`src/v4/lens/testgen.dag`) + **T-20** (`src/v4/workflow/bootstrap.dag`) + **T-22** (`src/v4/compiler/05_eval.dag` DiagnosticAssert execution / `eval_rejected_assert_kind_deferred` dissolution; witnesses in `src/v4/test/claim/manual/diagnostic_assert_eval.dag`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the closeout ratchet; T-22 expansion in its PR updates this row; T-19 AlgebraLaw Nat corpus expansion (this PR) further updates this row (same path — no new census line); T-19 deferral lane: TASKS.md §T-19 `algebra_law_conformance.dag` corpus, ROADMAP.md § Nine lanes row T-PB-B. **Dissolution:** remove when the T-19/T-20/T-22 closeout checks are expressed as `.dag` `TestClaim` rows or generated harness coverage without this host parse-surface ratchet. **Interim ratchet:** `testgen_concept_surface_stays_closed_and_classified` checks the closed testgen scheduling arms and the `Generator` claim kind / anchor / classification / slot field set; `language_behavior_equivalence_generated_claims_parse` / `language_behavior_equivalence_run_test_claim_receipts_present` pin the LBE generator slice; `idempotent_operation_generated_claims_parse_and_pin_emission` pins the idempotent-operation generator slice (`src/v4/std/effects.dag` canonical `IdempotentShape`/`EffectShape` witnesses + `idempotent_operation_witness_node`; outside the six-way `TestgenConcept` coproduct; label-only skip); `manual_manifest_matches_claim_anchor_discriminants` checks manual claim anchors join to the manifest by `ManualAnchorKey`; `claim_corpus_has_no_direct_manual_anchor_assignments` scans `src/v4/test/claim/**/*.dag` so `TestClaim.anchor` literals cannot bypass `manual_claim_anchor(...)` after the `ClaimAnchorKey` split; `coproduct_exhaustiveness_generated_claim_parse_and_witnesses_present` checks the generated coproduct-exhaustiveness corpus parses, derives the invalid `Node` and generated claim anchor from one `GeneratedCoproductExhaustiveness` source, uses canonical `node_locus`, and schedules the generated `DiagnosticExhaustiveness` claim under `GeneratedClaimAnchor`; `t20_bootstrap_plan_keeps_self_hosting_chain_as_data` checks the seed/self0/self1/fixpt bootstrap chain is encoded as `CompileStage` / `BootstrapPlan` data; `t22_diagnostic_assert_eval_witnesses_parse` checks `diagnostic_assert_eval.dag` parses; `t22_eval_diagnostic_assert_not_deferred_in_substrate` checks `05_eval.dag` no longer contains `eval_rejected_assert_kind_deferred`, executes `DiagnosticAssert`, and routes `run_test_claim` through `aggregate_verdicts`; `t19_algebra_law_generated_claims_parse_and_use_testgen_emit` checks `algebra_law_conformance.dag` parses and asserts the testgen emit helpers + tautological-sides guard in `lens/testgen.dag`. | -| `src/v3/compiler/tests/integration/coverage_defect_acceptance_dag_test.rs` | **Coverage-defect acceptance keys:** `src/v4/lens/coverage.dag` carries the canonical coverage-key set for `docs/design-dissolution-lens.md` §5.1; the old emit-template key is retired into `TemplateHole`, and the old string-escape key is split into `TemplateHole` plus `CanonicalCarrier`. **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the parse-level ratchet. **Dissolution:** remove when the v4 coverage lens runs as `.dag` / generated coverage and can assert the same acceptance rows without this host parser check. **Interim ratchet:** `coverage_defect_acceptance_keys_match_declared_rows` tokenizes/parses `src/v4/lens/coverage.dag` and asserts the exact parsed `(coverage_defect_* data row, CoverageDefectKey variant)` set matches the expected acceptance-key table while rejecting retired emit-template / string-escape names. | -| `src/v3/compiler/tests/integration/v4_bin_main_dag_smoke_test.rs` | **T-15** (`src/v4/bin/main.dag` — trampoline **`String`** authority + B1 digest **placeholder** `Node`s; closed-tree invariant #2 / pure-bootstrap zero-floor per `docs/design-pure-bootstrap-zero.md`). **Grounded-indicator authoring on `main.dag` is HOLD** pending hub-relayed canonical spec (operator-direct format under-spec; neat-hawk-87 cascade 2026-05-19). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when `main.dag` is exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust probe. **Interim ratchet:** `v4_bin_main_dag_tokenizes_and_parses_with_trampoline_source_anchor` runs `tokenize_for_test` + `parse_for_test` on the pinned `include_str!` source and asserts the trampoline / stub `data` identifiers plus the escaped `include!` spelling remain present in source text (full `compile_to_dag` on `main.dag` alone is deferred: `import v4.std.node` is not linked in the single-file harness). | -| `src/v3/compiler/tests/integration/v4_compiler_emit_translate_smoke_test.rs` | **TASKS.md** T-10 / Wave-3-B (`src/v4/compiler/06_translate.dag` — `fold_node` translate + `coercion_fold` wrapper, `TargetSelectionPolicy` from target-model bundle; `src/v4/compiler/05_emit.dag` — `serialize_target ∘ translate`, grammar-as-bidir serialize via bundle `emitted`/`source` keys; `src/v4/test/claim/manual/mvp1_rust_add_translate.dag` structural TestClaim anchors). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **This PR (+0 paths):** replaces fixed `translate_default_serialize_fuel` with structural `Outcome` serialize measures in `06_translate.dag`; expands the existing harness (no new census path) to ratchet parsed-surface declarations for `target_translation_rules_budget`, `translate_serialize_measure`, `target_serialize_source_from_model`, `bind_outcome` import, and absence of `translate_default_serialize_fuel` data — semantic fail-closed behavior is exercised by `run_mvp1_serialize_rejects_missing_translation_rules` in `mvp1_rust_add_translate.dag` (not host `str::contains` probes). **PR #3778 same-path expansion (+0 SG-0 paths):** adds `v4_wasm_wat_lex_boundary_uses_trivia_and_numeric_literal_authority` to pin the T-4.17 WAT lex/grammar dissolution receipt: stale whitespace-bearing wasm fixture tokens stay deleted, atomic keyword/trivia/numeric-literal authorities are present, and typed numeric-literal grammar productions exist for `i32`/`i64`/`f32`/`f64` const operands. **This PR same-path expansion (+0 SG-0 paths):** adds `v4_python_language_model_declares_wave2b_algebra_inhabitance` to pin T-4.17 Python Wave 2b type-deepening: `python.dag` consumes `AlgebraInhabitanceDecl` plus grounded `std.algebra` Node constructors (`ordered_ring_node`, `approximate_field_node`, `boolean_algebra_node`) and declares int/float/bool witness + inhabitance rows feeding `python_model_core_wave1`; the ratchet also asserts zero complex/singleton algebra witness/inhabitance helper declarations, so complex and singleton facts remain mechanically outside faithful algebra inhabitance until the relevant carrier exists. The Python T-11 grammar ratchet now additionally requires canonical `FormalProduction` with a flat formal-symbol RHS, requires the shared `std.grammar` `formal_production_to_node` projection, rejects legacy `GrammarExpr`/`Sequence`/`Terminal` imports in `python.dag`, and asserts zero Python-owned formal-production projection helpers. **This PR same-path expansion (+0 SG-0 paths):** adds `v4_wasm_language_model_declares_wave2b_algebra_inhabitance` to pin T-4.17 Wasm Wave 2b type-deepening: `wasm.dag` consumes `AlgebraInhabitanceDecl` plus grounded `std.algebra` type-node constructors (`commutative_semiring_type_node`, `approximate_field_type_node`) and declares integer/float witness + inhabitance rows feeding `wasm_model_core_wave2b`; the ratchet pins wave-2b entrypoints without adding a new SG-0 census path. **PR #3840 same-path expansion (+0 SG-0 paths):** adds `v4_mvp1_python_add_claim_tokenizes_and_parses`, `v4_mvp1_go_add_claim_tokenizes_and_parses`, `v4_mvp1_cpp_add_claim_tokenizes_and_parses`, `v4_mvp1_typescript_add_claim_tokenizes_and_parses`, and `v4_mvp1_shape_a_add_claims_import_compile_inferred` to ratchet T-11 grammar-inverse compile-inferred TestClaim parse/import receipts for python/go/cpp/typescript Shape-A MVP-1 add-fn fixtures (`mvp1_*_add_translate.dag`); dissolves `feature:T-11-grammar-inverse-serializer-remaining-targets` status mark in `06_translate.dag`. This is explicitly deferred under **ROADMAP** § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; dissolve these same-path Rust ratchets when the language boundary facts are asserted by `.dag` `TestClaim` rows, T-22 execution, or a generated harness instead of host `SurfaceExpr` traversal. Prior T-11 ratchet rows remain: `v4_emit_dag_tokenizes_and_parses`, `v4_emit_dag_module_path_is_compiler_emit`, `v4_emit_dag_imports_translate_stage`, `v4_emit_dag_declares_emit_entrypoint`, `v4_emit_dag_does_not_import_find_witness`, `v4_mvp1_rust_add_claim_imports_translate_and_emit`, `v4_translate_dag_dispatches_token_sequence_items`, and the language-model T-11 rows. **PR #3833 same-path expansion (+0 SG-0 paths):** extends the existing `v4_wasm_wat_lex_boundary_uses_trivia_and_numeric_literal_authority` ratchet in this harness (no new `EXPECTED_HAND_AUTHORED_TEST` census line) to require parsed-surface `wasm_token_u32_literal` and split `wasm_production_localidx_numeric` / `wasm_production_localidx_named` (replacing monolithic `wasm_production_localidx` in the required-symbol list).. **Dissolution:** remove when translate/emit/MVP-1 surfaces are exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust probe (full `compile_to_dag` over v4 compiler modules deferred until multi-module load). | -| `src/v3/compiler/tests/integration/v4_compiler_emit_translate_smoke_test.rs` | **TASKS.md** T-10 / Wave-3-B (`src/v4/compiler/06_translate.dag` — `fold_node` translate + `coercion_fold` wrapper, `TargetSelectionPolicy` from target-model bundle; `src/v4/compiler/05_emit.dag` — `serialize_target ∘ translate`, grammar-as-bidir serialize via bundle `emitted`/`source` keys; `src/v4/test/claim/manual/mvp1_rust_add_translate.dag` structural TestClaim anchors). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **This PR (+0 paths):** replaces fixed `translate_default_serialize_fuel` with structural `Outcome` serialize measures in `06_translate.dag`; expands the existing harness (no new census path) to ratchet parsed-surface declarations for `target_translation_rules_budget`, `translate_serialize_measure`, `target_serialize_source_from_model`, `bind_outcome` import, and absence of `translate_default_serialize_fuel` data — semantic fail-closed behavior is exercised by `run_mvp1_serialize_rejects_missing_translation_rules` in `mvp1_rust_add_translate.dag` (not host `str::contains` probes). **PR #3778 same-path expansion (+0 SG-0 paths):** adds `v4_wasm_wat_lex_boundary_uses_trivia_and_numeric_literal_authority` to pin the T-4.17 WAT lex/grammar dissolution receipt: stale whitespace-bearing wasm fixture tokens stay deleted, atomic keyword/trivia/numeric-literal authorities are present, and typed numeric-literal grammar productions exist for `i32`/`i64`/`f32`/`f64` const operands. **This PR same-path expansion (+0 SG-0 paths):** adds `v4_python_language_model_declares_wave2b_algebra_inhabitance` to pin T-4.17 Python Wave 2b type-deepening: `python.dag` consumes `AlgebraInhabitanceDecl` plus grounded `std.algebra` Node constructors (`ordered_ring_node`, `approximate_field_node`, `boolean_algebra_node`) and declares int/float/bool witness + inhabitance rows feeding `python_model_core_wave1`; the ratchet also asserts zero complex/singleton algebra witness/inhabitance helper declarations, so complex and singleton facts remain mechanically outside faithful algebra inhabitance until the relevant carrier exists. The Python T-11 grammar ratchet now additionally requires canonical `FormalProduction` with a flat formal-symbol RHS, requires the shared `std.grammar` `formal_production_to_node` projection, rejects legacy `GrammarExpr`/`Sequence`/`Terminal` imports in `python.dag`, and asserts zero Python-owned formal-production projection helpers. **PR #3840 same-path expansion (+0 SG-0 paths):** adds `v4_mvp1_python_add_claim_tokenizes_and_parses`, `v4_mvp1_go_add_claim_tokenizes_and_parses`, `v4_mvp1_cpp_add_claim_tokenizes_and_parses`, `v4_mvp1_typescript_add_claim_tokenizes_and_parses`, and `v4_mvp1_shape_a_add_claims_import_compile_inferred` to ratchet T-11 grammar-inverse compile-inferred TestClaim parse/import receipts for python/go/cpp/typescript Shape-A MVP-1 add-fn fixtures (`mvp1_*_add_translate.dag`); dissolves `feature:T-11-grammar-inverse-serializer-remaining-targets` status mark in `06_translate.dag`. **PR #3830 same-path expansion (+0 SG-0 paths):** adds `v4_kotlin_language_model_declares_wave2b_algebra_inhabitance` to pin T-4.17 Kotlin Wave 2b type-deepening: `kotlin.dag` consumes `AlgebraInhabitanceDecl` plus grounded `std.algebra` Node constructors (`ordered_ring_node`, `approximate_field_node`, `boolean_algebra_node`), declares int/long/float/bool witness + inhabitance rows feeding `kotlin_model_core_wave1`, and uses distinct `KotlinOrderedRingIntegerFacts` / `KotlinOrderedRingIntWidth` carriers so Byte/Short cannot be passed to `kotlin_integer_algebra_inhabitance` (stdlib arithmetic widens sub-`Int` built-ins to `Int`); the ratchet also asserts zero char/string/unit/nothing algebra witness/inhabitance helper declarations. This is explicitly deferred under **ROADMAP** § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; dissolve these same-path Rust ratchets when the language boundary facts are asserted by `.dag` `TestClaim` rows, T-22 execution, or a generated harness instead of host `SurfaceExpr` traversal. Prior T-11 ratchet rows remain: `v4_emit_dag_tokenizes_and_parses`, `v4_emit_dag_module_path_is_compiler_emit`, `v4_emit_dag_imports_translate_stage`, `v4_emit_dag_declares_emit_entrypoint`, `v4_emit_dag_does_not_import_find_witness`, `v4_mvp1_rust_add_claim_imports_translate_and_emit`, `v4_translate_dag_dispatches_token_sequence_items`, and the language-model T-11 rows. **Dissolution:** remove when translate/emit/MVP-1 surfaces are exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust probe (full `compile_to_dag` over v4 compiler modules deferred until multi-module load). | -| `src/v3/compiler/tests/integration/v4_compiler_emit_translate_smoke_test.rs` | **TASKS.md** T-10 / Wave-3-B (`src/v4/compiler/06_translate.dag` — `fold_node` translate + `coercion_fold` wrapper, `TargetSelectionPolicy` from target-model bundle; `src/v4/compiler/05_emit.dag` — `serialize_target ∘ translate`, grammar-as-bidir serialize via bundle `emitted`/`source` keys; `src/v4/test/claim/manual/mvp1_rust_add_translate.dag` structural TestClaim anchors). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **This PR (+0 paths):** replaces fixed `translate_default_serialize_fuel` with structural `Outcome` serialize measures in `06_translate.dag`; expands the existing harness (no new census path) to ratchet parsed-surface declarations for `target_translation_rules_budget`, `translate_serialize_measure`, `target_serialize_source_from_model`, `bind_outcome` import, and absence of `translate_default_serialize_fuel` data — semantic fail-closed behavior is exercised by `run_mvp1_serialize_rejects_missing_translation_rules` in `mvp1_rust_add_translate.dag` (not host `str::contains` probes). **PR #3778 same-path expansion (+0 SG-0 paths):** adds `v4_wasm_wat_lex_boundary_uses_trivia_and_numeric_literal_authority` to pin the T-4.17 WAT lex/grammar dissolution receipt: stale whitespace-bearing wasm fixture tokens stay deleted, atomic keyword/trivia/numeric-literal authorities are present, and typed numeric-literal grammar productions exist for `i32`/`i64`/`f32`/`f64` const operands. **PR #3798 T-4.17 python wave-2a same-path expansion (+0 SG-0 paths):** extends existing `v4_python_language_model_declares_t11_translation_rules` to assert `PythonLanguageModel`, `python_language_model_wave1`, `python_wave1_grammar`, canonical `FormalProduction` flat-rhs authority, shared `formal_production_to_node`, and `python_formal_productions_to_grammar_expr` operational shim on `src/v4/extdeps/languages/python.dag` (post-#3807 `v4.std.lexing` + `v4.std.grammar`; no extdeps→compiler imports). **PR #3798 wave-2b same-path expansion (+0 SG-0 paths):** adds `v4_python_language_model_declares_wave2b_algebra_inhabitance` (merged with main #3805) for int/float/bool algebra inhabitance rows. **PR #3840 same-path expansion (+0 SG-0 paths):** adds `v4_mvp1_python_add_claim_tokenizes_and_parses`, `v4_mvp1_go_add_claim_tokenizes_and_parses`, `v4_mvp1_cpp_add_claim_tokenizes_and_parses`, `v4_mvp1_typescript_add_claim_tokenizes_and_parses`, and `v4_mvp1_shape_a_add_claims_import_compile_inferred` to ratchet T-11 grammar-inverse compile-inferred TestClaim parse/import receipts for python/go/cpp/typescript Shape-A MVP-1 add-fn fixtures (`mvp1_*_add_translate.dag`); dissolves `feature:T-11-grammar-inverse-serializer-remaining-targets` status mark in `06_translate.dag`. Explicitly deferred under **ROADMAP** § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; dissolve when python boundary facts are asserted by `.dag` `TestClaim` rows, T-22 execution, or a generated harness instead of host `SurfaceExpr` traversal. Prior T-11 ratchet rows remain: `v4_emit_dag_tokenizes_and_parses`, `v4_emit_dag_module_path_is_compiler_emit`, `v4_emit_dag_imports_translate_stage`, `v4_emit_dag_declares_emit_entrypoint`, `v4_emit_dag_does_not_import_find_witness`, `v4_mvp1_rust_add_claim_imports_translate_and_emit`, `v4_translate_dag_dispatches_token_sequence_items`, and the language-model T-11 rows. **Dissolution:** remove when translate/emit/MVP-1 surfaces are exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust probe (full `compile_to_dag` over v4 compiler modules deferred until multi-module load). | -| `src/v3/compiler/tests/integration/v4_compiler_compile_public_terminal_smoke_test.rs` | **Wave-5-A / P3 commitment 6** (`src/v4/compiler/00_compile.dag` — `validate_then_compile` public terminal, `Validated` carrier, `infer` → required-lens gates on `InferredTree` → `compile_inferred`; `src/v4/compiler/07_target_carriers.dag` — acyclic `TargetModel`/`TargetSource` authority; `src/v4/test/claim/manual/validate_then_compile_public_terminal.dag` manual TestClaim anchors). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when `validate_then_compile` / compile-core surfaces are exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust probe (full `compile_to_dag` over v4 compiler modules deferred until multi-module load). **Interim ratchet:** `v4_compile_dag_tokenizes_and_parses` / `v4_compile_dag_module_path_is_compiler_compile` / `v4_compile_dag_declares_public_validate_then_compile` / `v4_compile_dag_declares_ratified_compile_core` / `v4_compile_dag_imports_target_carriers_not_emit_cycle` / `v4_compile_dag_does_not_import_specific_lens_modules` / `v4_emit_dag_does_not_import_compile_module` / `v4_validate_then_compile_claim_tokenizes_and_parses` / `v4_validate_then_compile_claim_imports_public_terminal_helpers` — tokenize+parse + import-row receipts for `compile_lens_gate_rejected_diagnostic`, `TranslateTo`, `validate_then_compile`. | -| `src/v3/compiler/tests/integration/v4_compiler_parse_table_dag_smoke_test.rs` | **TASKS.md** **T-7** (`src/v4/compiler/02_parse.dag` — memoized `ParseTable` / `build_parse_table` / `parse_production`; `src/v4/test/claim/parse/grammar_validation.dag` — `claim_right_recursive_parse_succeeds` + `validation_right_recursive_parse_fixture`; `src/v4/std/algebra.dag` — fail-closed `ListTailResult` tail projection). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness; SG-0 census net +1 pairing `(c)` is mechanically prepended via `scripts/ci-merge/sg0-pr-body-append.3661.txt` in CI (`.github/workflows/ci.yml`). **This PR (+0 SG-0 paths):** expands the existing harness to pin `token_position_indices` against the duplicate-final-index regression in `src/v4/compiler/02_parse.dag`; this same-path hand-Rust expansion stays under the same **T-PB-B** / `pb_rust_tests_outside_residual_zero` deferral lane until `.dag` `TestClaim` execution or generated harness coverage can assert token-position tables without host Rust. **Dissolution:** remove when parse-table acceptance and T-7 entrypoints are exercised only by `.dag` `TestClaim` rows / T-22 eval runner / generated harness without this host `parse_for_test` structural ratchet. **Interim ratchet:** `v4_compiler_parse_table_dag_tokenizes_and_parses` — tokenize+parse `02_parse.dag`, `grammar_validation.dag`, and `algebra.dag`; `v4_compiler_parse_table_entrypoints_and_claim_wiring` — asserts `build_parse_table`, `parse_production`, `parse_table_empty`, `token_position_indices`, absence of the extra final `length(xs: tokens)` append, `ListTailResult`, `claim_right_recursive_parse_succeeds`, and `validation_right_recursive_parse_fixture` wiring to `parse_production(`. | -| `src/v3/compiler/tests/integration/v4_lens_edit_locus_dag_smoke_test.rs` | **TASKS.md** T-21 (`src/v4/lens/edit_locus.dag` — `GitDiffNameOnly` → `resolve_edit_locus` → `affected_set` edit_locus via `EditLocusRead` path-regex injection; claims in `src/v4/test/claim/lens_affected_set/edit_locus_resolver.dag`). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when git-diff → edit-locus resolution is exercised only by `.dag` `TestClaim` rows / BinaryShim host without this parse probe (full wire: `TestClaimExerciseSurface` + `ci_runner.dag` — parent cool-hawk-221). **Interim ratchet:** `v4_lens_edit_locus_dag_tokenizes_and_parses`; `v4_lens_edit_locus_module_authority_and_entrypoints`; `v4_lens_edit_locus_claim_wiring`. | -| `src/v3/compiler/tests/integration/v4_lens_affected_set_dag_smoke_test.rs` | **TASKS.md** T-21 IRT-1 (`src/v4/lens/affected_set.dag` — `re_exec_frontier_from_diff: (Dag, Diff) -> Witness` changed-subgraph frontier fold; purity-aware boundary prune via injectable `AffectedSetRead`; fail-closed whole-DAG gate; six focused leaf `.dag` TestClaims plus aggregate `irt1_leaf_claim_suite.dag` TestClaim under `src/v4/test/claim/lens_affected_set/` with matching six-leaf `affected_set_irt1_subsumed_fixes` DiffIds and `affected_set_irt1_leaf_claim_suite` MechanicalReverification handle in `affected_set_irt1_subsumption` (`src/v4/lens/subsumption.dag`)). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when IRT-1 frontier fold + leaf receipt behaviors are exercised only by `.dag` `TestClaim` rows / generated harness without this parse probe. **Interim ratchet:** `v4_lens_affected_set_dag_tokenizes_and_parses`; `v4_lens_affected_set_module_authority_and_entrypoints`; `v4_lens_affected_set_irt1_leaf_claim_wiring`; `v4_lens_affected_set_irt1_leaf_claim_suite_wiring`. | -| `src/v3/compiler/tests/integration/v4_lens_application_dag_smoke_test.rs` | **TASKS.md** T-23 (`src/v4/lens/application.dag` — `SectionRef`, `EnforcedApplication`, `IntrospectApplication`, `LensApplicationConfig`, `apply_lens`, `apply_advisory_lens`, D1 `subterm_at` / `apply_diff`; minimal `src/v4/std/report.dag` advisory carriers) + **T-17** (`src/v4/lens/synthesis.dag` — `LowerBoundTechnique`, `synthesis_lens` / `synthesis_lens_diagnostics`; `src/v4/test/claim/lens_synthesis/synthesis_gap_polynomial.dag` worked claim wiring). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **This PR (+0 SG-0 paths):** expands the existing harness to parse `synthesis.dag`, pin `ReportReason` / `report_reason_to_diagnostic_reason` on `std/report.dag`, and assert `synthesis_gap_polynomial.dag` imports `synthesis_lens` + `DecisionTree`; prior expansion parses `apply_lens_introspect_rejection_is_advisory` and asserts `CompileLensIntrospect` + `Violates`. Same-path hand-Rust expansion stays under **T-PB-B** / `pb_rust_tests_outside_residual_zero` until `.dag` `TestClaim` execution or generated harness coverage replaces host parse probes. **Dissolution:** remove when lens-application + C7 synthesis surfaces are exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust parse probe (full `DeclarationId` / `NodeId` section projection deferred — see 🟡 `section_subject` in `application.dag`). **Interim ratchet:** `v4_lens_application_dag_tokenizes_and_parses`; `v4_lens_synthesis_dag_module_authority_and_entrypoints`; `v4_std_report_dag_advisory_carrier_shape`; `v4_lens_synthesis_gap_polynomial_claim_tokenizes_and_parses`; `v4_lens_application_introspect_advisory_claim_tokenizes_and_parses`; `v4_lens_application_module_authority_and_entrypoints`. | -| `src/v3/compiler/tests/integration/v4_lens_registry_dag_smoke_test.rs` | **Operator pin** `docs/briefs/r4-lane-a-lens-interface-freeze-pin.md` §3 / **PREFIX T-23 v0** (`src/v4/lens/registry.dag` — **`LensIdV0`** closed sum + **`LensModulePathV0`**) plus Lens-CI activation (`src/v4/workflow/ci.dag` consumes registry-backed `LensIdV0` rows). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **P2 / Practice 5:** this host harness is a **parse-surface structural ratchet** for `src/v4/lens/registry.dag` + its `src/v4/workflow/ci.dag` consumer + the live `.github/workflows/ci.yml` Lens-CI signal binding, while preserving the staged T-23/P9 registry parse-cleanliness receipts; the semantic interface is checked in CI by `gunbc compile` over a temporary `ci.dag` entry root plus `src/v4` dependency root (not `--target dag`, which is blocked by the known DAG-artifact hang). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness / CI pairing. **Dissolution:** remove when `registry.dag` and Lens-CI workflow wiring are exercised only by `.dag` `TestClaim` rows / a generated harness that mechanically reads registry rows and workflow commands without this per-file Rust parse ratchet. **Interim ratchet:** `v4_lens_registry_dag_tokenizes_and_parses` tokenizes/parses the pinned registry source and asserts module path, `LensIdV0`/`LensModulePathV0`, `lens_registry_v0`, `lens_registry_ids_resolve`, `lens_registry_row_count`, and `lens_registry_bound_row_count`; `v4_lens_registry_t23_closed_lens_ids_present` pins the eight-arm closed set; `v4_lens_registry_structural_resolution_bound_to_module` pins `StructuralResolution` → `Bound { path: "v4.lens.structural_resolution" }`; `v4_lens_registry_p9_owned_fn_surface_present` pins the P9 `LensOwnedFnV0` / `lens_owned_fn_registry_v0` substrate rows; `v4_ci_workflow_consumes_lens_registry_for_lens_ci_signal` tokenizes/parses `ci.dag`, asserts the `lens_registry_ids_resolve` import, `LensCiCommand.required_lenses: List`, the six required `LensIdV0` policy rows, `lens_ci_registry_signal` gate data, `lens_ci_registry_execution.needs == [v2_compile_src_v4]`, and `lens_ci_live_workflow_signal` as the modeled live-step binding without re-authoring the `ci_pipeline` signal/job/policy facts. It then parses `.github/workflows/ci.yml` and checks those modeled step names execute the registry smoke plus rust-target semantic compile. **Paired CI semantic gate:** `Lens-CI registry semantic v4 compile (rust target)` copies `src/v4/workflow/ci.dag` into a temporary entry root, copies `src/v4` into a dependency root with `workflow/ci.dag` removed, and runs `target/release/gunbc compile --source-root "$entry_root" --source-root "$deps_root" --output-dir "$RUNNER_TEMP/v4-lens-ci-rust" --target rust` so lowering/inference of `ci_command_authority_ok -> lens_registry_ids_resolve` is checked through the workflow consumer and its transitive v4 imports without making unrelated v4 extdeps entry modules for this Lens-CI signal. | -| `src/v3/compiler/tests/integration/v4_lens_testgen_dag_smoke_test.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; **`src/v4/TASKS.md` § T-19** (`lens/testgen.dag` — producer of `TestClaim` corpus from substrate; Wave-0 bootstrap / manual claim lookup remains keyed by **`ManualAnchorKey`**; **`Generator.anchor`** now reuses the same **`ClaimAnchorKey`** carrier as **`TestClaim.anchor`**, with manual rows wrapped by **`ManualClaimAnchor`** after **`Outcome`** rejects **`ManualAnchorAbsent`** on lookup and generated rows partitioned under **`GeneratedClaimAnchor`** (**Practice 5** single-anchor schema; **LB-P4-3212** ratchet — cite PR #3212 / review thread). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when `src/v4/lens/testgen.dag` is exercised only by `.dag` `TestClaim` rows / a generated harness / merged M2 multi-module lowering without this host `parse_for_test` structural ratchet (isolated `compile_to_dag` does not resolve `import v4.std.*` peers under M1(2.7); see harness module comment). **Interim ratchet:** focused `#[test]` slices in `v4_lens_testgen_dag_smoke_test.rs` (**openai-pro** review **#14812** / **TESTING.md** discipline): `v4_lens_testgen_wave0_modules_tokenize_and_parse`; `v4_lens_testgen_wave0_verification_manual_anchor_key_only`; `v4_lens_testgen_wave0_function_inventory_matches_wave0`; `v4_lens_testgen_wave0_nat_symbol_import_authority`; `v4_lens_testgen_wave0_outcome_return_surfaces`; `v4_lens_testgen_wave0_generator_anchor_field_is_claim_anchor_key`; `v4_lens_testgen_wave0_concept_projection_matches_claim_anchor`; `v4_lens_testgen_wave0_generator_carries_claim_classification_and_anchor`; `v4_lens_testgen_wave0_bootstrap_threads_claim_anchor_into_generator`; `v4_lens_testgen_nat_law_manual_claims_use_compiles_stub`; `v4_lens_testgen_nat_substrate_carries_algebra_law_subject_symbols`; `v4_lens_testgen_testgen_carries_six_nat_algebra_law_scheduling_arms` — collectively tokenize/parse `src/v4/lens/testgen.dag` + `src/v4/std/verification.dag`, assert Wave-0 function inventory + `Outcome` return surfaces + `Generator.anchor: ClaimAnchorKey` carrier, substring wiring receipts on bootstrap join, `nat_law_anchors.dag` per-claim `kind: Compiles` on identical stub `input`/`expected` (law-bearing `Node` + `Equals` deferred to T-22; codex #14833), three `AlgebraLawSubject` `Symbol` rows in `src/v4/std/nat.dag`, and six `value: AlgebraLaw {` constructor sites in testgen (file-wide count); plus the **T-19 witness-validity generator-category guard** (PR #3565 same-file expansion, **+0 census paths**, P5 Mechanism (b) same-path ratchet): `v4_lens_testgen_witness_validity_modules_tokenize_and_parse`, `v4_lens_testgen_witness_validity_helper_returns_outcome_testclaim`, `v4_lens_testgen_witness_validity_module_imports_helper_from_lens_testgen`, `v4_lens_testgen_witness_validity_module_pins_four_row_corpus_via_helper`, `v4_lens_testgen_witness_validity_module_authors_no_testclaim_literals` — pin both `src/v4/lens/testgen.dag` + `src/v4/test/claim/generated/witness_validity.dag` parse, `testgen_emit_witness_validity_claim` return type `Outcome`, helper-routing import, exact 4-row corpus (1 positive + 3 negative arms), and the no-`TestClaim`-literal tautology-skip discipline on the generated module. Parse-only structural ratchet; `Generator` carries `kind`, `anchor`, `classification`, and `slot` per TASKS T-19. plus the **T-19 anchor-strip + AlgebraLaw subject helper guard** (PR #3636 same-file expansion, **+0 census paths**, P5 Mechanism (b) same-path ratchet): `v4_lens_testgen_wave0_generator_anchor_field_is_claim_anchor_key` asserts `Generator.kind: TestClaimCoproductVariant` and `Generator.anchor: ClaimAnchorKey`; `v4_lens_testgen_wave0_concept_projection_matches_claim_anchor` asserts match on `test_claim_anchor(c: claim)`; `v4_lens_testgen_wave0_generator_carries_claim_classification_and_anchor` adds `kind: test_claim_coproduct_variant(c: claim)` substring check; `assert_six_algebra_law_subject_paths_in_testgen` asserts `algebra_law_subject_for_manual_anchor` helper exists, match dispatch in `testgen_concept_for_manual_claim`, single `value: AlgebraLaw {` constructor site, all six `ManualNat*` anchor names (`ManualNatAddLeftIdentity`, `ManualNatAddRightIdentity`, `ManualNatAddAssociativity`, `ManualNatMulLeftIdentity`, `ManualNatMulAnnihilator`, `ManualNatMulAssociativity`) in helper body, and six `value: AlgebraLawSubject {` projection arms; `assert_nat_algebra_law_subject_symbols_in_substrate` adds six forbidden `nat_algebra_law_subject_symbol_*` substring checks (nat substrate must not re-export mirror operation/value symbols); `generator_field_ty` (parametric field-name lookup) and `between<'a>` helper added. | -| `src/v3/compiler/tests/integration/v4_std_model_core_dag_smoke_test.rs` | **TASKS.md** **T-33** (`src/v4/std/model_core.dag` — Ratified Q1 `ModelCore` shared substrate: primitive fact bundles, `AlgebraInhabitanceDecl`, `AlgebraLawObligation` over modeled inhabitance + law `Node`, T-33-Q10 `EffectSignature` / `ResourceAccess`, and effect/partiality scaffolds). **ROADMAP:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness; SG-0 census net +1 pairing `(c)` is mechanically prepended via `scripts/ci-merge/sg0-pr-body-append.3474.txt` in CI (`.github/workflows/ci.yml`). **Dissolution:** remove when `model_core.dag` is exercised only by `.dag` `TestClaim` rows / a generated harness / merged M2 multi-module lowering without this host `parse_for_test` structural ratchet (isolated `compile_to_dag` does not resolve `import v4.std.*` peers under M1(2.7); see harness module comment). **Interim ratchet:** `v4_std_model_core_dag_tokenizes_and_parses`; `v4_std_model_core_declares_ratified_q1_carriers`; `v4_std_model_core_bundles_five_facets`; `v4_std_model_core_algebra_law_obligation_structural`; `v4_std_model_core_effect_partiality_ops_use_node_authority`; `v4_std_model_core_effect_signature_resource_access_shape`; `v4_std_model_core_wave1_void_constructor_present` — tokenize/parse the pinned `include_str!` source, assert `v4.std.model_core` module path, closed carrier inventory (`ModelCore`, `PrimitiveFactBundle`, `AlgebraInhabitanceDecl`, `AlgebraLawObligation`, `EffectSignature`, `ResourceAccess`, `EffectSemanticsDecl`, `PartialitySemanticsDecl`), five-facet `ModelCore` field bundle, `AlgebraLawObligation { inhabitance_witness: Node, law: Node }` (joins canonical `ModelCore.inhabitance` rows by witness; no embedded duplicate decl or Symbol labels), `PrimitiveOperationRef.operation` / `PartialOperationDecl.operation` `Node` authority, `PrimitiveOperationRef.effect_signature: EffectSignature`, `EffectSignature { signature: Node }` with resource authority kept on `BoundaryAllowance.resource`, `ResourceAccess { resource: Node }`, and `wave1_void` scaffold constructor (🟡 `feature:model-core-wave1-void-scaffold`, dissolve-on T-4/T-34 non-empty `ModelCore`). | -| `src/v3/compiler/tests/integration/file_attachment_substrate_carrier_test.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#62** `substrate_gap_file_ingestion_closed` (T-Workflow-As-Data substrate-gap class; worker brief `docs/briefs/r3-substrate-gate-62-file-attachment-carrier-worker.md`). **Dissolution:** remove when a `.dag` `TestClaim` / PB-B-1 runner receipt can assert `FileAttachment` field names + cross-module nominal wiring against `generated_full_bootstrap_dag()` without this hand-Rust structural ratchet (same dissolution posture as `timing_lens_substrate_carrier_test.rs` for gate #55). **Interim ratchet:** `file_attachment_shape_locked` + `file_attachment_field_types_locked` + `file_attachment_field_count_is_five` pin the ratified Refined-B-1 five-field subset of `WorkflowObservationAnchor` (`NodeId`, `ContentHash`, `WorkflowProducerId`, `WorkflowRunId`, `Nanoseconds`) exactly as declared in `src/v3/std/timing_lens.dag`; existence proof carrier construction stays in-module as `gate_62_file_attachment_demo_record`. | -| `src/v3/compiler/tests/integration/lens_application_substrate_carrier_test.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#89** `section_ref_substrate_landed` (T-Lens-Application-Surface — `SectionRef` disjoint sum over `DeclarationScope` and `NodeScope` in `src/v3/std/lens_application.dag`; design authority `docs/design-lens-application-surface.md` §1.2–§2). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the harness. **Dissolution:** remove when a `.dag` `TestClaim` / PB-B-1 runner receipt can assert `SectionRef` variant labels, field names, and `DeclarationId` / `NodeId` nominal wiring against `generated_full_bootstrap_dag()` without this hand-Rust structural ratchet (same dissolution posture as gate **#62** `file_attachment_substrate_carrier_test.rs`). **Interim ratchet:** `gate_89_section_ref_is_disjoint_sum_from_lens_application_authority` pins variant order (`DeclarationScope` then `NodeScope`) and payload fields to `lens_application.dag`. | -| `src/v3/compiler/tests/integration/workflow_substrate_carriers_test.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#53** `workflow_substrate_carriers_landed` (T-Workflow-As-Data Slice 1; worker brief `docs/briefs/r3-substrate-t-workflow-as-data-slice-1-worker.md`). **Dissolution:** remove when a `.dag` `TestClaim` / PB-B-1 runner receipt can assert `WorkflowSecret`, `SecretScope`, `CronSchedule`, and `CronField` structural shape against `generated_full_bootstrap_dag()` without this hand-Rust ratchet. **Interim ratchet:** `workflow_secret_shape_locked` + `secret_scope_variants_locked` + `cron_schedule_shape_locked` + `cron_field_variants_locked` pin the Slice 1 β-ratified carriers (STOP+PING discipline on `CronSchedule` field-count drift >5 per brief). | -| `src/v3/compiler/tests/integration/m2_substrate_inhabitance_test.rs` | **ROADMAP:** `ROADMAP.md` — **Tier-3 perf-budget Phase-1 hand-Rust mirror benches** / T-Tier3-Dissolution paired-dispatch (`docs/briefs/r3-pb-t-tier3-consumer-slice-worker.md`). **Plan:** `docs/r3-program-plan.md` §1.8 gate **#2** `tier3_computation_mirror_dissolved` (state-check; **CONSUMER_LANDED** = §1.7 executable-consumer sense, not INVARIANTS §P2 generated-consumer — see plan §1.7 “State-check …” paragraph). **Dissolution:** retire remaining Tier3 host mirrors per `docs/r3-structure.md` §Acceptance as Evaluator-backed std bodies land. **Interim ratchet (P5 Mechanism (b)):** `tier3_computation_mirror_trivial_constructors_dissolved` (PR #2789 narrow slice) + `tier3_computation_mirror_kernel_algebra_profile_substrate_authority` with brace-bounded `dag.rs` scan asserting `type_iteration_dimension` delegates through `BOOTSTRAPPED_DAG.kernel_algebra_profile` (forbid parallel hand-maintained type→profile tables); sibling Tier3 rows in this file carry the same lane receipts. | -| `src/v3/compiler/tests/integration/no_coercion_cost_dimension_ratchet_test.rs` | **ROADMAP:** `ROADMAP.md` → `### Nine lanes` → **T-PB-B** / `pb_rust_tests_outside_residual_zero` (SG-0 `EXPECTED_HAND_AUTHORED_TEST` hand-authored integration census; same “Hand-Rust census” partition narrative as `ROADMAP.md` §Nine lanes / T-PB-B row in the lanes table). **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#39** `no_coercion_cost_dimension` (T-CostLens-Composition — host walk over `src/v3/{std,lenses,spec}/**/*.dag` forbidding standalone `CoercionCost` outside `//` comments). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` literal land in the same PR as the ratchet. **Dissolution:** remove when the same structural claim is carried by `.dag` `TestClaim` / generated harness without this host file walk. **Interim ratchet:** `no_coercion_cost_dimension_substrate_dag_has_no_coercion_cost_carrier_token` + `standalone_needle_tests` pin identifier-boundary matching. | -| `src/v3/compiler/tests/integration/r3_gate_60_phase2_width_nat_parser_test.rs` | **ROADMAP:** `ROADMAP.md` — **`substrate_gap_parser_grammar_closed`** / R3 gate **#60** (Phase 2.1 parser slice: angle-only width nat in `<…>`, `TypeAngleArg` substrate split, `Compose>` lowering with literal phantom width). **Dissolution:** remove when gate #60 parse/lower/routing receipts are carried by `.dag` `TestClaim` / generated harness without this hand-authored `compile_to_dag` + `parse_for_test` module (per `docs/audit/r3-gate-60-decomposition.md` follow-on slices). **Interim ratchet:** `gate_60_phase2_parse_accepts_algebra_angle_width_nat`, `gate_60_phase2_int_64_lowers_to_compose_int_machine_width_literal`, `gate_60_phase2_nat_8_lowers_via_uint_slot`, `gate_60_integer_routing_witness_accepts_literal_nat_machine_width`, `gate_60_bare_numeric_type_is_parse_rejected`, `gate_60_int_disallowed_width_fails_closed_without_malformed_template_args`. | -| `src/v3/compiler/tests/integration/r3_sg0_non_test_zero_test.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#8** `sg0_non_test_zero` (T-LensProducer-Retirement / SG-0 T-PB-A non-test closure). **ROADMAP deferral for the new Rust test path:** `ROADMAP.md` → `### Nine lanes` row **T-PB-B** / `pb_rust_tests_outside_residual_zero` and § **Lane acceptance — .dag gates** hand-Rust census split; this host driver is part of the T-PB-B test subset debt while it exists. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the host receipt. **Dissolution:** remove when `EXPECTED_HAND_AUTHORED_NON_TEST` and `EXPECTED_HAND_AUTHORED_FRAGMENTS` reach zero and the gate can be represented by the `.dag` suite / generic `TestRunner` path without this Rust driver. **Interim ratchet:** `r3_gate_8_sg0_non_test_zero_claims_execute_against_live_census` compiles `tests/fixtures/r3_sg0_non_test_zero.dag`, runs `r3_sg0_non_test_zero_suite`, and asserts both live `CensusBoundCheck` claims execute against the intended SG-0 census constants without freezing residual counts in the Rust receipt. | -| `src/v3/compiler/tests/integration/r3_gate_62_file_ingestion_negative_bridge_audit_test.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#62** `substrate_gap_file_ingestion_closed` supporting evidence (T-Workflow-As-Data substrate-gap class). **NOT a §Acceptance receipt**: §1.4/§4.3 require a positive `.dag` ingestion-via-`FileAttachment` demonstration, not absence-of-bridge evidence (operator BLOCKING 2026-05-14T19:13:37Z, THESIS/P1 modeling faithfulness). This row is a CI-visible negative-bridge audit only — it ratchets that no `.dag`/`.v3` program body under `dsl/` re-introduces `include_str!` while the workflow-substrate file-ingestion path is built out; program bodies are scanned with `//` line comments, `/* … */` block comments, and `"…"` / `` `…` `` string literals stripped so a doc-comment or label mentioning the bridge name does not trip the audit (`feedback_no_textual_enforcement_bridges`). **ROADMAP:** `ROADMAP.md` → `### Nine lanes` → **T-PB-B** / `pb_rust_tests_outside_residual_zero` — hand-Rust integration test held under the T-PB-B deferral lane until a `.dag` `TestClaim` / PB-B-1 runner can carry the predicate. **Dissolution:** remove when (a) a `.dag` `TestClaim` / PB-B-1 runner receipt asserts the same file-tree audit fail-closed without a host-side filesystem walker, OR (b) the gate flips PASSING via a positive ingestion-via-`FileAttachment` `.dag` program and the carrier-reachability ratchets alone carry the audit. **Interim ratchet:** `r3_gate_62_no_include_str_in_dsl` walks every `.dag`/`.v3` file under `dsl/` and fails with the offending paths if any reintroduce `include_str!` in a program body. | -| `src/v3/compiler/tests/integration/r3_path_b_brief3_char_in_class_execution_test.rs` | **ROADMAP:** `ROADMAP.md` → **Post-merge debt** subsection **`char_in_class` interpreter parity (tokenizer bridge finish, PR #693)** (`0..=127` **`byte_matches` vs evaluable `char_in_class`** receipt) plus neighbor bullet **Character-level under-consumption in tokenize + syntax authorities** (`tokenizer_char_class_membership` / codegen mirror scaffolding). **Deferral lane:** `ROADMAP.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero` (`EXPECTED_HAND_AUTHORED_TEST`). **PR receipt (P5 Mechanism (b)):** matching `EXPECTED_HAND_AUTHORED_TEST` line + this INVARIANTS row land in the same PR as the harness. **Dissolution:** remove when (a) parity + authority assertions are `.dag` `TestClaim` rows / generated runner without Rust `evaluate_body` scaffolding, and (b) `regen_tokenize` emits class predicates strictly from lowered `tokenize.dag` (**`tokenizer_char_class_membership`** / **`char_in_class`**), deleting `ascii_scan_class_predicate` (**Character-level under-consumption** §step (3); Class-5 Gap 3 close). **Interim ratchet:** `path_b_brief3_char_in_class_matches_codegen_byte_matches_on_ascii` + sibling authority/evaluator tests in the same module. | -| `src/v3/compiler/tests/integration/r3_gate_90_lens_enforcement_carrier_landed_test.rs` | **ROADMAP:** `ROADMAP.md` → `### Nine lanes` → **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **Plan:** `docs/r3-program-plan.md` §1.8 gate **#90** `lens_enforcement_carrier_landed` (T-Lens-Application-Surface Slice B — canonical `LensEnforcement` / `EnforceableLens` **data** rows co-located with complexity (`complexity.dag`), symbolic cost (`cost.dag`), and timing (`timing_lens.dag`); Stage 2e parallelism LAS enforcement deferral honest under gates **#81/#95** / Cluster F sequencing). **Design:** `docs/design-lens-application-surface.md` (parametric carriers in `src/v3/std/lens_application.dag`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` literal land in the same PR as the harness. **Dissolution:** remove when the same structural obligations (field labels on each bundled enforcement / enforceable pair + authority file co-location) are carried only by `.dag` `TestClaim` / generated runner receipts without this Rust integration harness. **Interim ratchet:** `r3_gate_90_timing_lens_enforcement_carrier_bundle_locked`, `r3_gate_90_complexity_lens_enforcement_carrier_bundle_locked`, and `r3_gate_90_cost_lens_enforcement_carrier_bundle_locked` pin `project`/`violates` on each `*_enforcement` and `lens`/`enforcement` on each `*_enforceable` (one lens authority per test); timing via `generated_full_bootstrap_dag()`, complexity/cost via `cached_compile_to_dag` because `src/v3/lenses/*.dag` stays outside the std bootstrap concat. **Co-receipt:** `scripts/ci-merge/sg0-pr-body-append.3129.txt` prepended in CI for SG-0 net-shrink +1 pairing on this census line. | -| `src/v3/compiler/tests/integration/symbolic_cost_expr_equals_executable_ratchet_test.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#40** `symbolic_cost_expr_equals_executable` (T-CostLens-Composition). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the ratchet. **Dissolution:** remove when the `SymbolicCostExprEquals` executable-wiring invariant is asserted by a `.dag` `TestClaim` / generated harness over `src/v3/compiler/src/test_runner.rs` (or its modeled successor) without this hand-Rust `TestRunner`-driven ratchet — same dissolution posture as adjacent T-CostLens hand-Rust receipts (`m1_5_verification_test.rs` / `lens_cost_target_realization_test.rs` / `common/symbolic_cost_verification_fixture.rs`). **Interim ratchet:** behavior-driven via the `TestRunner` interface — `symbolic_cost_expr_equals_well_shaped_claim_passes_and_never_returns_not_yet_implemented` compiles a minimal `SymbolicCostExprEquals` `TestClaim`, runs it through `TestRunner::run_suite`, and asserts `ClaimResult::Pass` (forbidding both `NotYetImplemented(_)` — the dispatch-fallthrough shell gate #40 ratchets away from — and `Fail(_)` on the well-shaped path). Robust to dispatch reshaping, helper renames, and message-text edits (per codex `TESTING.md` behavior-first guidance). Typed-shape rejection / fail-closed coverage for the dedicated evaluator is covered separately by `m1_5_verification_test.rs::symbolic_cost_expr_equals_fail_closed_*` — not duplicated here. Wider pass + fail-closed receipts for the predicate stay anchored in `m1_5_verification_test.rs::symbolic_cost_expr_equals_{smoke_suite,countdown_demo_suite}_passes` + `symbolic_cost_expr_equals_fail_closed_*`. | -| `src/v3/compiler/tests/integration/t_ci_workflow_as_data_demo_test.rs` | **ROADMAP:** `ROADMAP.md` → `### Nine lanes` → **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **Plan:** `docs/r3-program-plan.md` §1.8 gate **#57** `lens_self_application_demonstrated` — lane **T-Lens-Self-Application** (linked `gunbc.ci` compile receipt over `dsl/gunbc/ci_github_actions_workflow.dag` + `dsl/gunbc/ci.dag`: `ci_workflow_dag` authority lowering, `gunbc-ci` pipeline identity, carrier-derived prerequisite fan-out / affected-gate ordering, absence of a parallel lane-2 `WorkflowEffect` mirror, paired symbolic-cost + E7 complexity `DimensionOk` on the CI lane-2 subject, and timing-lens carrier topology preservation). **Dissolution:** remove when equivalent `.dag` `TestClaim` / generated-runner receipts can assert the same linked CI workflow authority and lens-self-application facts without this hand-Rust integration harness. **Interim ratchet:** `lens_self_application_demonstrated*` tests plus the PB-1 bootstrap timing companion `ci_workflow_as_data_demo_timing_dimension_report_on_bootstrap_shell`. | -| `src/v3/compiler/tests/integration/t_gate_106_show_correct_code_diagnostic_coverage_test.rs` | **ROADMAP:** `ROADMAP.md` → `### Nine lanes` → **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **Plan:** `docs/r3-program-plan.md` §1.8 gate **#106** `show_correct_code_diagnostic_coverage` — lanes **T-Tests-As-Data-Completeness** + Substrate canvas (`Correction` sum + mandatory substrate `Diagnostic.correction` at `src/v3/std/diagnostics.dag`; consumer locks over `generated_full_bootstrap_dag()` plus one typed live-correction roundtrip via `compile_to_dag` / `apply_correction_and_reparse`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` literal land in the same PR as the harness. **Dissolution:** remove when §1.8 row #106 close obligations (substrate carrier checks + diagnostic-class roundtrip audit + zero-`DeferredCorrection` corpus tally per plan) are discharged via `.dag` `TestClaim` / generated harness without this Rust anchor. **Interim ratchet:** `gate_106_correction_*` / `gate_106_diagnostic_record_carries_mandatory_correction_field` / variant payload locks + `gate_106_type_mismatch_live_correction_roundtrip_recompiles_cleanly`. | -| `src/v3/compiler/tests/integration/t_gate_58_apply_lens_self_application_test.rs` | **ROADMAP:** `ROADMAP.md` → `### Nine lanes` → **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **Plan:** `docs/r3-program-plan.md` §1.8 gate **#58** `apply_lens_self_application_demonstrated` — lane **T-Lens-Self-Application** (`EnforcedApplication` bootstrap receipt over `gate_58_apply_lens_self_application_pass` + typed witness `gate_58_modeled_ci_timing_measurement` (`gate_58_ci_workflow_timing_row` with `workflow: modeled_gunbc_ci_workflow`) in `src/v3/std/t_ci_workflow_as_data_demo.dag`). **Dissolution:** remove when a `.dag` `TestClaim` / runner receipt asserts the same `generated_full_bootstrap_dag()` facts (empty bootstrap diagnostics + witness declarations) without this Rust harness. **Interim ratchet:** `apply_lens_self_application_demonstrated_bootstrap_receipt` + `gate_58_modeled_ci_timing_measurement` presence checks. **Co-receipt (same PR, P5 single surface):** expanded `src/v3/compiler/src/enforced_lens_application.rs` timing consumer + `src/v3/compiler/build.rs` default-rank std `STAGED_FILES` ordering from parsed `import v3.std.*` edges (Kahn topo among co-ranked files; single authority with module imports) are documented in `scripts/ci-merge/sg0-pr-body-append.2827.txt` (prepended to the PR body in CI) with explicit ROADMAP rows + dissolution triggers per INVARIANTS §P5 Mechanism **(b)**. | -| `src/v3/compiler/tests/integration/t_lens_application_carrier_test.rs` | **R3 program plan:** `docs/r3-program-plan.md` §1.8 gate **#88** `lens_application_carrier_landed` (**T-Lens-Application-Surface** Slice A; design lock `docs/design-lens-application-surface.md` §2; substrate `src/v3/std/lens_application.dag`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the harness; SG-0 census net +1 pairing is mechanically prepended via `scripts/ci-merge/sg0-pr-body-append.3125.txt` in CI (`.github/workflows/ci.yml`). **Dissolution:** remove when a `.dag` `TestClaim` / PB-B-1 runner receipt can assert `EnforcedApplication` / `IntrospectApplication` template arity and conj field sets on `generated_full_bootstrap_dag()` without this hand-Rust structural ratchet (same dissolution posture as `file_attachment_substrate_carrier_test.rs` / `timing_lens_substrate_carrier_test.rs`). **Interim ratchet:** `r3_gate_88_enforced_application_carrier_shape_locked` + `r3_gate_88_introspect_application_carrier_shape_locked`. | -| `src/v3/compiler/tests/integration/t_las_parallelism_iteration_gate95_demo_test.rs` | **ROADMAP:** `ROADMAP.md` → `### Nine lanes` → **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **Plan:** `docs/r3-program-plan.md` §1.8 gate **#95** `opt_in_iteration_parallelism_via_lens_application_demonstrated` — **T-Lens-Application-Surface** iteration-opt-in parallelism (`parallelism_enforceable`, Lane‑2 `loop_iteration_parallel_emission_indicator`, exported `parallelism_iteration_opt_in_enforcement_violates`; design lock `docs/design-lens-application-surface.md` §4.4; substrate `src/v3/lenses/parallelism.dag`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + the matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the harness; SG-0 census net +1 pairing `(c)` is mechanically prepended via `scripts/ci-merge/sg0-pr-body-append.3131.txt` in CI (same PR as the census line — complements the gate **#95** non-test bundle in that prepend, including sibling co-touches on `dag.rs` / `lib.rs` / `lower.rs`, not a substitute). **Dissolution:** remove when a `.dag` `TestClaim` / PB-B-1 runner receipt asserts the same staged Lane‑2 indicator ↔ substrate-backed violates predicate facts without this Rust harness (same split posture as gate **#58**: integration bootstrap witness vs deferred executable LAS authoring). **Interim ratchet:** `gate_95_fixture_pins_parallelism_enforceable_carrier` + `gate_95_opt_in_iteration_parallelism_via_lens_application_demonstrated_indicator_bridge`. | - -### SG-0 hand-authored compiler non-test paths (`EXPECTED_HAND_AUTHORED_NON_TEST`) - -Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED_NON_TEST` inside `src/v3/compiler/tests/integration/sg0_census_test.rs` must carry a matching dissolution-bearing receipt **in the same PR** as the census line. The table below is the planning home-of-record for **every** listed non-test hand-Rust path (crate sources, `build.rs`, regen `bin/` entrypoints, and bench harnesses), not only Band-C gate #87 seams. - -| Path | Receipt | -|------|---------| -| `src/v3/compiler/benches/tier3_mirror_perf.rs` | **ROADMAP:** `ROADMAP.md` — **Tier-3 perf-budget Phase-1** / T-Tier3-Dissolution (`docs/briefs/r3-pb-tier3-perf-budget-worker.md`; parent brief #1331). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when Tier3 host mirrors dissolve per `docs/r3-structure.md` §Acceptance (Criterion harness no longer targets hot Rust substrate entrypoints). **Interim ratchet:** frozen `tier3_baseline.json` + bench stays `--locked` clean under CI. | -| `src/v3/compiler/build.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor`; **authority:** `dsl/gunbc/compiler.dag` **stage0** (`stage0.hand_maintained_src` / regen edges surfaced to Cargo). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** `build.rs` mirror retires when stage ordering + copy/hash contracts are enforced only via `.dag` emit programs (`SELF_HOSTING.md` §2). **Interim ratchet:** bootstrap snapshot + fmt/ci gates keep `build.rs` aligned with `compiler.dag`. | -| `src/v3/compiler/src/bin/detect_ci_affected_components.rs` | **TASKS.md** T-24 — host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (dissolves `scripts/detect-affected-components.sh`; path buckets single-authority in `src/v4/workflow/ci.dag`). **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR as the bin. **Dissolution:** delete when affected-component projection runs from `.dag` eval / generated CI runner without this hand `main`. **Interim ratchet:** `v4_ci_component_affected` unit tests + `v4_workflow_ci_runner_dag_smoke_test` alignment with `ci.dag`. | -| `src/v3/compiler/src/bin/gunbc_ci.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** + **T-Workflow-As-Data** — `bin/gunbc_ci` host shim for modeled CI (`dsl/gunbc/ci.dag`). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when CI selection + receipts are emitted/invoked without a hand `main` (`SELF_HOSTING.md` §2.2). **Interim ratchet:** `gunbc_ci` integration tests + SG-0 census. | -| `src/v3/compiler/src/bin/r1c_e_emit_gates.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / R1C-E emit gates (`docs/r3-program-plan.md` T-Emit `.dag` `TestClaim` lane). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit-gate checks are invoked only from generated/bootstrap harness without this bin. **Interim ratchet:** `r1c_e_gates.rs` shared checks + integration harness. | -| `src/v3/compiler/src/bin/regen_bootstrap.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — regen **bootstrap** stage host entry (`dsl/gunbc/regen*.dag` family). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when bootstrap regen is a single declared pipeline command with no parallel Rust `main`. **Interim ratchet:** `regen_bootstrap_emit.rs` + bootstrap snapshot CI. | -| `src/v3/compiler/src/bin/regen_parse.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — regen **parse** stage host entry. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when parse regen is pipeline-only. **Interim ratchet:** `regen_parse_emit.rs` + parse regen tests. | -| `src/v3/compiler/src/bin/regen_parse_tables.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — regen **parse tables** stage host entry. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when parse-tables regen is pipeline-only. **Interim ratchet:** `regen_parse_tables_emit.rs` + tables regen tests. | -| `src/v3/compiler/src/bin/regen_tokenize.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — regen **tokenize** stage host entry. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when tokenize regen is pipeline-only. **Interim ratchet:** `src/v3/compiler/src/regen_tokenize.rs` + tokenizer tests. | -| `src/v3/compiler/src/bin/regen_v3.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — regen **v3** umbrella host entry. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when full v3 regen is pipeline-only. **Interim ratchet:** fmt/ci bootstrap gates. | -| `src/v3/compiler/src/bin/self_host_fixed_point.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / `pb_self_compile_fixed_point` — self-host fixed-point trend reader bin. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when fixed-point receipts are `.dag`/generated consumers only. **Interim ratchet:** `self_host_receipt_p0.rs` JSON field stability tests. | -| `src/v3/compiler/src/bootstrap.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / compiler bootstrap (`generated_full_bootstrap_dag` host seam). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when bootstrap construction is generated-only without hand orchestration. **Interim ratchet:** bootstrap integration tests + snapshot ratchet. | -| `src/v3/compiler/src/bootstrap_regen_fresh.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — bootstrap regen freshness / copy discipline host module. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when freshness checks live in pipeline `.dag` programs only. **Interim ratchet:** `compiler.dag` stage0 + CI `--verify` gate. | -| `src/v3/compiler/src/cementing_dispatch.rs` | **ROADMAP:** `ROADMAP.md` — **v3 lens capability honesty pass** (same posture as `wiring_scanner_test.rs`). **Dissolution (host scan):** reflected wiring facts at the runner edge so dispatch does not read `tests/integration.rs` from disk. **Dissolution (receipt expansion):** move the `expected_cementing_receipt_triples` projection bridge out of Rust into structural `.dag` data keyed from the register ∩ `regen.dag` projection (single roster authority). **Interim ratchet:** `CementingDispatchMatchesProjection` + closed `CementingBandCReceiptKind` in `tests/dag/cementing_dispatch.dag`. | -| `src/v3/compiler/src/complexity_lattice.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/cost_basis_declaration.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/dag.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/dag/builder.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/dag/cardinality_payload.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/dag/effects.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/dag/ports.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/diagnostics.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/dimension.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/emit.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/emit/collection_ops_method_contract.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/emit/python_target.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/emit/rust_target.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/emit_rust.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/emit_rust_bin_shim.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/emit_rust_roundtrip_fixtures.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/enforced_lens_application.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **Plan:** `docs/r3-program-plan.md` §1.8 gate **#95** `opt_in_iteration_parallelism_via_lens_application_demonstrated` — parallelism iteration LAS consumer routes violation decisions through authored `parallelism_enforcement_violates` in `src/v3/lenses/parallelism.dag` via `apply_lens_declaration` in `src/v3/compiler/src/lens_declaration_apply.rs` (single substrate authority); Rust maps only `loop_iteration_parallel_emission_indicator` → observed `ParallelismMode`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Co-receipt (same PR, P5 single surface):** gate **#95** SG-0 census net **+1** on `EXPECTED_HAND_AUTHORED_TEST` + pairing `(c)` text are prepended via `scripts/ci-merge/sg0-pr-body-append.3131.txt`; that append is the **single** checkable PR-body bundle listing every gate **#95** co-touched non-test path (`enforced_lens_application.rs`, `dag.rs`, `lib.rs`, `lower.rs` — roles spelled out in the prepend) alongside this amended row. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/v4_ci_component_affected.rs` | **TASKS.md** T-24 — Rust mirror of `ci_component_affected_from_git_diff` path buckets (`src/v4/workflow/ci.dag` is authority; must stay aligned per `ci.dag` workflow_policy predicates). **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when `detect-ci-affected-components` invokes `.dag` eval over `ci.dag` predicates with no parallel Rust path logic. **Interim ratchet:** `workflow_policy_paths_match_ci_dag_authority` unit test + integration smoke. | -| `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_derived_as_four` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | -| `src/v3/compiler/src/gunbc_ci.rs` | **ROADMAP:** `ROADMAP.md` § **Forward-Tracked Lane: T-Workflow-As-Data** (≈L57–L63; substrate lane feeding program gate **#103** `ci_uses_affected_set_selection` per `docs/r3-program-plan.md` + `docs/briefs/r3-wave1-s6-slice7-affected-set-impl-worker.md`). **Additional ROADMAP receipt:** `ROADMAP.md` § **Lane acceptance** row **T-TestGen** / `testgen_manual_claim_is_first_class` (first-class `TestClaim` execution) + row **T-PB-B** / `pb_rust_tests_outside_residual_zero` (tests-as-data) carry the Lens-CI `MechanicalReverification` host bridge for `v4.lens.subsumption.DissolutionSubsumption` rows while the `.dag` TestClaim runner is staged. **Dissolution:** remove when `CIWorkflowDag` affected-gate dispatch is owned by `.dag` programs / generated `TestClaim` receipts (or the dag compiler emits selection) with **no** parallel Rust mirror over the `dsl/gunbc/ci.dag` carrier; also remove the `MechanicalReverification` host bridge when the v4 `.dag` TestClaim runner consumes `MechanicalReverification { test_claim }` rows and reports the same `Verified` / `NotVerified` / `Unverifiable` verdict as substrate data. **Interim ratchet:** `select_affected_gates` + in-module hermetic tests pin symmetric edge-expansion semantics consistent with `CIGateEdge { from, to }` in `dsl/gunbc/ci.dag`; `mechanical_reverification_verdict` + in-module hermetic tests pin fail-closed subsumption verdicts with nominal `DiffId`, `TestClaimId`, and `ProducerStageId` mirrors. | -| `src/v3/compiler/src/infer.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/int_literal_ranges.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/integration_rs_wiring_scan.rs` | **ROADMAP:** same **v3 lens capability honesty pass** bullet as `wiring_scanner_test.rs`. **Dissolution:** remove when `tests/integration.rs` cementing `#[path]` / `mod` wiring can be validated structurally (no line scanner). **Interim ratchet:** `Err` (not panic) on raw/byte string openers in **Code** so `CementingDispatchMatchesProjection` surfaces `ClaimResult::Fail`. | -| `src/v3/compiler/src/lens_declaration_apply.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/lens_t_las_carrier.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/lib.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR; PR #3120 additionally receipts the `lens_effect_enumeration::operation_structural_effect_shape` host adapter through `scripts/ci-merge/sg0-pr-body-append.3120.txt` while generated Rust cannot yet import the canonical `std.effects::operation_effect_shape` carrier without a lib.rs bridge. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority); delete the gate #82 adapter receipt when the generated effect-enumeration Rust can consume the canonical Operation classifier directly with no host helper. **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/lower.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/memory_peak_cost.rs` | **ROADMAP:** `ROADMAP.md` / `docs/r3-program-plan.md` §1.8 — **R3 gate #94** cost-lens memory-peak compose + enforcement (`dominant` / max_path). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when memory-peak enforcement is substrate-owned without this hand module. **Interim ratchet:** cost-lens integration + cementing tests referencing gate #94. | -| `src/v3/compiler/src/omni_shape_b_openapi.rs` | **ROADMAP:** `ROADMAP.md` — **T-Omni-Shape-B** transitional surface (`docs/briefs/` brief #1 / PR #2251). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when Shape B `.dag` program owns OpenAPI projection end-to-end. **Interim ratchet:** omni emit boundary tests. | -| `src/v3/compiler/src/pb_method_template_projection.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / R3 row 85 — `MethodTemplateContract` read surface (`docs/decisions/r3-row85-method-template-read-surface.md`). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when projection is generated from `.dag` authority only. **Interim ratchet:** method-template contract tests. | -| `src/v3/compiler/src/pipeline_authority.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/post_emit_verifier.rs` | **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when this file's contract is carried only by `.dag` substrate + pipeline-emitted Rust per `SELF_HOSTING.md` §2 (no hand-maintained parallel authority). **Interim ratchet:** `cargo fmt` / `ci` / `v3` + SG-0 census tests keep the path stable. | -| `src/v3/compiler/src/process_exit.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — PB-1 host mirror of `dsl/std/process.dag` `ProcessExit` for emitted bin shims. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when process exit typing is emitted, not hand-mirrored. **Interim ratchet:** emit shim tests. | -| `src/v3/compiler/src/r1c_e_gates.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / R1C-E — shared `check_*` API for emit-gate `.dag` `TestClaim` wrappers + `r1c_e_emit_gates` bin. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when gates are generated-only. **Interim ratchet:** R1C-E integration harness. | -| `src/v3/compiler/src/r3_fc_lane2_loop_witness.rs` | **ROADMAP:** `ROADMAP.md` — **R3 T-Free-Consequences** / db18 divergence (`docs/design-db18-workflow-effect-carrier.md`); directive scanner until lowering owns `lane2_workflow`. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete per ROADMAP row when lowering attaches loop workflow effects. **Interim ratchet:** auto-loop lens claims in `r3_fc_*` tests. | -| `src/v3/compiler/src/r3_gate_87_cementing_regen_runner_suites.rs` | **ROADMAP:** same **v3 lens capability honesty pass** / gate #87 closure. **Dissolution:** PB-B-1 gate-#87 harness inventory is generated or reflected as substrate facts (no hand-maintained `R3_GATE_87_CEMENTING_REGEN_SUITES` table); `t_pb_b_1_dag_runner_test`, `cementing_dispatch`, and `r3_gate_87_lens_cementing_regen_receipts_test` consume that single authority. **Interim ratchet:** one merge-visible table shared across those consumers (INVARIANTS P2 single authority). | -| `src/v3/compiler/src/regen_bootstrap_emit.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — bootstrap regen emit host module. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit output is pipeline-only. **Interim ratchet:** regen bootstrap integration tests. | -| `src/v3/compiler/src/regen_lens_driver.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — regen **lens** stage library (`regen.dag` / `LensRegistryEntry` walk; R3 gate #7 retired `src/bin/regen_lens.rs` from SG-0). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when lens regen is pipeline-only / emitted from `.dag`. **Interim ratchet:** `regen_lens` bin + lens regen integration tests. | -| `src/v3/compiler/src/regen_lens_entry.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — thin Cargo `[[bin]] regen_lens` host entry (R3 gate #7 `regen_lens_dot_rs_retired`). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when PB-1 emits bin `main` from `.dag` `BinShim` without hand Rust. **Interim ratchet:** `regen_lens` CLI smoke + integration tests. | -| `src/v3/compiler/src/regen_parse_emit.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — parse regen emit host module. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit output is pipeline-only. **Interim ratchet:** parse regen tests. | -| `src/v3/compiler/src/regen_parse_tables_emit.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — parse-tables regen emit host module. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit output is pipeline-only. **Interim ratchet:** parse-tables regen tests. | -| `src/v3/compiler/src/regen_tokenize.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — tokenizer regen emit host module. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit output is pipeline-only. **Interim ratchet:** tokenizer regen tests. | -| `src/v3/compiler/src/self_host_receipt_p0.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / T-FixedPoint P0 — stable JSON receipt keys for `self_host_fixed_point` trends (DB-8 hand receipt). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when receipt schema is `.dag`/generated-owned. **Interim ratchet:** field-name unit tests in-module. | -| `src/v3/compiler/src/test_runner.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** / **T-PB-B** — integration test runner host (`ExecuteCommand` / claim evaluation seam). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when runner is generated or substrate-owned without hand orchestration. **Interim ratchet:** integration + cementing suites. | -| `src/v3/compiler/src/v4_hollow_alias_gate.rs` | **TASKS.md** **T-30** (`src/v4/TASKS.md`); **Spec:** `docs/modeling-discipline.md` **Practice 8** — *Interim floor: the hollow-alias discriminator* (Practice 8 *Interim floor* on `main` post-#3226 `77b9e7d72` + Practice 9 #3234 `125fc88c8`; diff `main` if §8/§9 drift). **ROADMAP:** `ROADMAP.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when T-30's structural `Node → Outcome` gate is generated from v4 `.dag` authority (no handwritten Practice-8 mirror). **Interim ratchet:** hermetic unit tests in-module pin the three-part hollow predicate + kernel-ambient exemption; paired **P2-staging** `.dag` nominal witness at `src/v4/std/fact_density.dag` (`SourceSpecReadFact` — **not** a landed substrate primitive per INVARIANTS §P2 until a generated consumer reads it; dissolution to `Node` payload when the v4-isolated bootstrap path lands; see file header + **PR review** (no maintained manifest). **T-30 enforcement mechanism (operator-ratified 2026-05-25):** structural `fact_density_hollow_alias_gate: Node -> Outcome>` is wired from `src/v4/lens/fact_density.dag` into the temporary compile-local `InferredTree -> Outcome>` adapter `fact_density_hollow_alias_compile_gate` and `CompileLens` row `fact_density_lens` in `src/v4/compiler/00_compile.dag`, and `validate_then_compile` applies required gates with `run_required_lens_gates_on_subtree` across the inferred root and every child node (compiles via v4 bootstrap gate; P2 consumer-gated); six `.dag` TestClaims in `src/v4/test/claim/lens_fact_density/` — `hollow_alias_compile_lens_rejects`, `fact_bundle_compile_lens_passes`, `hollow_alias_blocked_in_run_gates`, `hollow_alias_blocked_via_always_required_lenses`, `hollow_alias_vtc_empty_lenses_rejected`, `hollow_alias_nested_rejected` — scaffold the gate through `apply_compile_lens` / `run_required_lens_gates` / `always_required_lenses()` / `validate_then_compile` with empty caller-lenses and nested hollow-alias rejection (compile-only until T-22 execution). | -| `src/v3/compiler/src/wall_clock_ratchet_manifest.rs` | **ROADMAP:** `ROADMAP.md` § **T-PB-A** — wall-clock warn manifest for CI/binary shims (timing discipline). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when timing manifest is `.dag` data consumed by codegen. **Interim ratchet:** modeled CI workflow tests. | ---- - -======= ->>>>>>> origin/main ## Appendix: ID index Every numbered ID (C-N, E-N, L-N, DB-N) descends from one principle. The prose-name invariants are indexed under their principle above; this appendix exists so PR-history references like "violates C-8" or "see E-9" resolve quickly. diff --git a/_internal/INVARIANTS_OPS.md b/_internal/INVARIANTS_OPS.md index 61d35274944..31e94f8d6ec 100644 --- a/_internal/INVARIANTS_OPS.md +++ b/_internal/INVARIANTS_OPS.md @@ -79,6 +79,7 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED |------|---------| | `src/v3/compiler/benches/tier3_mirror_perf.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` — **Tier-3 perf-budget Phase-1** / T-Tier3-Dissolution (`docs/briefs/r3-pb-tier3-perf-budget-worker.md`; parent brief #1331). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when Tier3 host mirrors dissolve per `docs/r3-structure.md` §Acceptance (Criterion harness no longer targets hot Rust substrate entrypoints). **Interim ratchet:** frozen `tier3_baseline.json` + bench stays `--locked` clean under CI. | | `src/v3/compiler/build.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor`; **authority:** `dsl/gunbc/compiler.dag` **stage0** (`stage0.hand_maintained_src` / regen edges surfaced to Cargo). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** `build.rs` mirror retires when stage ordering + copy/hash contracts are enforced only via `.dag` emit programs (`SELF_HOSTING.md` §2). **Interim ratchet:** bootstrap snapshot + fmt/ci gates keep `build.rs` aligned with `compiler.dag`. | +| `src/v3/compiler/src/bin/detect_ci_affected_components.rs` | **TASKS.md** T-24 — host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (dissolves `scripts/detect-affected-components.sh`; path buckets single-authority in `src/v4/workflow/ci.dag`). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR as the bin. **Dissolution:** delete when affected-component projection runs from `.dag` eval / generated CI runner without this hand `main`. **Interim ratchet:** `v4_ci_component_affected` unit tests + `v4_workflow_ci_runner_dag_smoke_test` alignment with `ci.dag`. | | `src/v3/compiler/src/bin/gunbc_ci.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** + **T-Workflow-As-Data** — `bin/gunbc_ci` host shim for modeled CI (`dsl/gunbc/ci.dag`). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when CI selection + receipts are emitted/invoked without a hand `main` (`SELF_HOSTING.md` §2.2). **Interim ratchet:** `gunbc_ci` integration tests + SG-0 census. | | `src/v3/compiler/src/bin/r1c_e_emit_gates.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / R1C-E emit gates (`docs/r3-program-plan.md` T-Emit `.dag` `TestClaim` lane). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit-gate checks are invoked only from generated/bootstrap harness without this bin. **Interim ratchet:** `r1c_e_gates.rs` shared checks + integration harness. | | `src/v3/compiler/src/bin/regen_bootstrap.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — regen **bootstrap** stage host entry (`dsl/gunbc/regen*.dag` family). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when bootstrap regen is a single declared pipeline command with no parallel Rust `main`. **Interim ratchet:** `regen_bootstrap_emit.rs` + bootstrap snapshot CI. | @@ -132,6 +133,8 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED | `src/v3/compiler/src/regen_tokenize.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — tokenizer regen emit host module. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit output is pipeline-only. **Interim ratchet:** tokenizer regen tests. | | `src/v3/compiler/src/self_host_receipt_p0.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / T-FixedPoint P0 — stable JSON receipt keys for `self_host_fixed_point` trends (DB-8 hand receipt). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when receipt schema is `.dag`/generated-owned. **Interim ratchet:** field-name unit tests in-module. | | `src/v3/compiler/src/test_runner.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / **T-PB-B** — integration test runner host (`ExecuteCommand` / claim evaluation seam). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when runner is generated or substrate-owned without hand orchestration. **Interim ratchet:** integration + cementing suites. | +| `src/v3/compiler/src/v4_ci_component_affected.rs` | **TASKS.md** T-24 — Rust mirror of `ci_component_affected_from_git_diff` path buckets (`src/v4/workflow/ci.dag` is authority; must stay aligned per `ci.dag` workflow_policy predicates). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when `detect-ci-affected-components` invokes `.dag` eval over `ci.dag` predicates with no parallel Rust path logic. **Interim ratchet:** `workflow_policy_paths_match_ci_dag_authority` unit test + integration smoke. | +| `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_derived_as_four` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | | `src/v3/compiler/src/v4_hollow_alias_gate.rs` | **TASKS.md** **T-30** (`src/v4/TASKS.md`); **Spec:** `docs/modeling-discipline.md` **Practice 8** — *Interim floor: the hollow-alias discriminator* (Practice 8 *Interim floor* on `main` post-#3226 `77b9e7d72` + Practice 9 #3234 `125fc88c8`; diff `main` if §8/§9 drift). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when T-30's structural `Node → Outcome` gate is generated from v4 `.dag` authority (no handwritten Practice-8 mirror). **Interim ratchet:** hermetic unit tests in-module pin the three-part hollow predicate + kernel-ambient exemption; paired **P2-staging** `.dag` nominal witness at `src/v4/std/fact_density.dag` (`SourceSpecReadFact` — **not** a landed substrate primitive per INVARIANTS §P2 until a generated consumer reads it; dissolution to `Node` payload when the v4-isolated bootstrap path lands; see file header + **PR review** (no maintained manifest). **T-30 enforcement mechanism:** structural `fact_density_hollow_alias_gate: Node -> Outcome>` is wired from `src/v4/lens/fact_density.dag` into the temporary compile-local `InferredTree -> Outcome>` adapter `fact_density_hollow_alias_compile_gate` and `CompileLens` row `fact_density_lens` in `src/v4/compiler/00_compile.dag`, and `validate_then_compile` applies required gates with `run_required_lens_gates_on_subtree` across the inferred root and every child node (compiles via v4 bootstrap gate; P2 consumer-gated); six `.dag` TestClaims in `src/v4/test/claim/lens_fact_density/` — `hollow_alias_compile_lens_rejects`, `fact_bundle_compile_lens_passes`, `hollow_alias_blocked_in_run_gates`, `hollow_alias_blocked_via_always_required_lenses`, `hollow_alias_vtc_empty_lenses_rejected`, `hollow_alias_nested_rejected` — scaffold the gate through `apply_compile_lens` / `run_required_lens_gates` / `always_required_lenses()` / `validate_then_compile` with empty caller-lenses and nested hollow-alias rejection (compile-only until T-22 execution). | | `src/v3/compiler/src/wall_clock_ratchet_manifest.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — wall-clock warn manifest for CI/binary shims (timing discipline). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when timing manifest is `.dag` data consumed by codegen. **Interim ratchet:** modeled CI workflow tests. | --- From 052badd22a80b06714f24fbab429531b070ff3c6 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 03:10:41 +0000 Subject: [PATCH 27/56] chore: apply cargo fmt (CI fmt gate on b90bd9d) Co-authored-by: Cursor --- src/v3/compiler/src/v4_ci_runner_pool.rs | 12 +++++++++--- .../v4_workflow_ci_runner_dag_smoke_test.rs | 4 +++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index c26f057afb8..3c4d6c095aa 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -45,13 +45,17 @@ pub fn ci_fleet_min_jobserver_token_cap() -> u32 { pub fn ci_fleet_max_runner_count() -> u32 { CI_SELF_HOSTED_RUNNER_POOLS .iter() - .fold(CI_SRV1_POOL.runner_count, |acc, pool| acc.max(pool.runner_count)) + .fold(CI_SRV1_POOL.runner_count, |acc, pool| { + acc.max(pool.runner_count) + }) } pub fn ci_fleet_min_runner_count() -> u32 { CI_SELF_HOSTED_RUNNER_POOLS .iter() - .fold(CI_SRV1_POOL.runner_count, |acc, pool| acc.min(pool.runner_count)) + .fold(CI_SRV1_POOL.runner_count, |acc, pool| { + acc.min(pool.runner_count) + }) } pub fn ci_runner_pool_total_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { @@ -120,6 +124,8 @@ mod tests { #[test] fn witness_required_for_fleet_m1_derivation() { - assert!(ci_runner_pool_m1_probe_witness_holds(&CI_SELF_HOSTED_RUNNER_POOLS)); + assert!(ci_runner_pool_m1_probe_witness_holds( + &CI_SELF_HOSTED_RUNNER_POOLS + )); } } diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index ec2bf7f0637..4571ab2103f 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -295,7 +295,9 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { "{CI_DAG_PATH}: git diff read must use canonical Outcome, not a parallel coproduct" ); assert!( - CI_DAG.contains("ci_component_affected_from_git_diff_read(outcome: Outcome)"), + CI_DAG.contains( + "ci_component_affected_from_git_diff_read(outcome: Outcome)" + ), "{CI_DAG_PATH}: git diff read boundary must project through std.diagnostic Outcome" ); assert!( From 25a225997b36f91ea72ea9ef4b0a3b1fd3f953f8 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 03:17:42 +0000 Subject: [PATCH 28/56] fix(docs): clarify ci.dag is modeled authority, Rust is parity mirror Host transport comments overstated single-authority; ci.dag is the model, v4_ci_component_affected is the interim mirror ratcheted by smoke/unit tests until .dag eval owns the affected-set (claude 20259). Co-authored-by: Cursor --- src/v3/compiler/src/bin/detect_ci_affected_components.rs | 3 ++- src/v3/compiler/src/v4_ci_component_affected.rs | 7 ++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/v3/compiler/src/bin/detect_ci_affected_components.rs b/src/v3/compiler/src/bin/detect_ci_affected_components.rs index 8738969e678..a0f9b5b9603 100644 --- a/src/v3/compiler/src/bin/detect_ci_affected_components.rs +++ b/src/v3/compiler/src/bin/detect_ci_affected_components.rs @@ -1,5 +1,6 @@ // Host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff_read` (T-24). -// Replaces scripts/detect-affected-components.sh — path buckets live in ci.dag only. +// Replaces scripts/detect-affected-components.sh. Modeled authority is `src/v4/workflow/ci.dag`; +// this bin executes the Rust mirror in `v4_ci_component_affected` (parity-ratcheted to ci.dag). #![allow(clippy::disallowed_macros)] use std::io::Write; diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index d8db6dcc7b5..03e93f7d548 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -1,8 +1,9 @@ //! v4 `workflow/ci.dag` component affected-set — host transport for GitHub Actions. //! -//! **Authority:** `src/v4/workflow/ci.dag` (`ci_component_affected_from_git_diff` and -//! `ci_changed_path_affects_*`). This module is the CI runner projection only; path buckets -//! must not be duplicated in workflow YAML (gate #103). +//! **Modeled authority:** `src/v4/workflow/ci.dag` (`ci_component_affected_from_git_diff` and +//! `ci_changed_path_affects_*`). This module is an interim Rust mirror of those predicates for +//! the CI runner (not `.dag` eval yet); keep aligned via `workflow_policy_paths_match_ci_dag_authority` +//! and `v4_workflow_ci_runner_dag_smoke_test` prefix parity. Do not add path buckets to workflow YAML. /// Structural mirror of `CiComponentAffected` in `src/v4/workflow/ci.dag`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] From d88f7c1fc1a9db57c234166a72223a3605b7a474 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 03:55:02 +0000 Subject: [PATCH 29/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/workflow/ci.dag | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 0a171b3bfac..c619ac75786 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -125,9 +125,9 @@ type RunnerArch type SelfHostedRunnerPool { host: Symbol arch: RunnerArch - core_count: Int - runner_count: Int - jobserver_token_cap: Int + core_count: Int // 🟡 gated: formatter-int-refinement — must be ≥1 (operator fleet spec) + runner_count: Int // 🟡 gated: formatter-int-refinement — must be ≥1 + jobserver_token_cap: Int // 🟡 gated: formatter-int-refinement — must be ≥1 } // 🟡 gated — live-workflow projection interim (docs/r3-program-plan.md gates #98 `ci_yml_hand_authority_dissolved` and #100 `project_github_actions_landed`) — bind node://adhoc-35324347-e8a Lens-CI activation — dissolve-on-arrival: emitted/projected GitHub Actions workflow reads `ci_pipeline`/`LensCiCommand` directly and this step-name carrier is deleted; forbidden: adding signal/job/policy facts here instead of projecting them from `ci_pipeline`. @@ -258,6 +258,8 @@ data ci_dependency_cycle: Symbol = ci_dependency_cycle data ci_bootstrap_authority_violation: Symbol = ci_bootstrap_authority_violation data ci_workflow_file: Symbol = ci_workflow_file data ci_runner_pool_m1_witness_violation: Symbol = ci_runner_pool_m1_witness_violation +data ci_runner_pool_non_positive_capacity: Symbol = ci_runner_pool_non_positive_capacity +data ci_runner_pool_non_positive_fanout: Symbol = ci_runner_pool_non_positive_fanout fn ci_diagnostic(reason: Symbol) -> Diagnostic { Diagnostic { From 7aa89d7a75fa540780cb072d43a9d59873f58708 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 03:56:10 +0000 Subject: [PATCH 30/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v3/compiler/src/v4_ci_runner_pool.rs | 38 ++++++++----- .../v4_workflow_ci_runner_dag_smoke_test.rs | 7 ++- .../claim/workflow/runner_pool_m1_probe.dag | 14 +++-- src/v4/workflow/ci.dag | 57 +++++++++++-------- 4 files changed, 70 insertions(+), 46 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index 3c4d6c095aa..4a158bf9703 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -66,16 +66,30 @@ pub fn ci_runner_pool_host_count(pools: &[SelfHostedRunnerPool]) -> u32 { pools.len() as u32 } -pub fn ci_int_at_least_one(n: u32) -> u32 { - n.max(1) +pub fn ci_int_positive(n: u32) -> bool { + n >= 1 } -pub fn ci_runner_pool_m1_probe_witness_holds(pools: &[SelfHostedRunnerPool]) -> bool { - !pools.is_empty() && ci_fleet_max_runner_count() != ci_fleet_min_runner_count() +pub fn ci_runner_pool_capacity_valid(pool: SelfHostedRunnerPool) -> bool { + ci_int_positive(pool.core_count) + && ci_int_positive(pool.runner_count) + && ci_int_positive(pool.jobserver_token_cap) +} + +pub fn ci_runner_pool_fleet_capacities_valid() -> bool { + CI_SELF_HOSTED_RUNNER_POOLS + .iter() + .all(|pool| ci_runner_pool_capacity_valid(*pool)) +} + +pub fn ci_runner_pool_m1_probe_witness_holds() -> bool { + ci_runner_pool_fleet_capacities_valid() + && !CI_SELF_HOSTED_RUNNER_POOLS.is_empty() + && ci_fleet_max_runner_count() != ci_fleet_min_runner_count() } pub fn ci_m1_probe_cargo_fanout_slots_from_fleet() -> Option { - if !ci_runner_pool_m1_probe_witness_holds(&CI_SELF_HOSTED_RUNNER_POOLS) { + if !ci_runner_pool_m1_probe_witness_holds() { return None; } let min_runners = ci_fleet_min_runner_count(); @@ -91,16 +105,15 @@ pub fn ci_m1_probe_cargo_fanout_slots_from_fleet() -> Option { pub fn ci_m1_probe_cargo_check_jobs_from_fleet() -> Option { let fanout = ci_m1_probe_cargo_fanout_slots_from_fleet()?; - let fanout = ci_int_at_least_one(fanout); - if fanout == 0 { + if !ci_int_positive(fanout) { return None; } Some(ci_fleet_min_jobserver_token_cap() / fanout) } /// Modeled authority for `data m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. -pub fn m1_probe_cargo_check_jobs() -> u32 { - ci_m1_probe_cargo_check_jobs_from_fleet().unwrap_or(0) +pub fn m1_probe_cargo_check_jobs() -> Option { + ci_m1_probe_cargo_check_jobs_from_fleet() } #[cfg(test)] @@ -117,15 +130,14 @@ mod tests { #[test] fn m1_probe_cargo_check_jobs_derived_as_four() { + assert!(ci_runner_pool_fleet_capacities_valid()); assert_eq!(ci_m1_probe_cargo_fanout_slots_from_fleet(), Some(6)); assert_eq!(ci_m1_probe_cargo_check_jobs_from_fleet(), Some(4)); - assert_eq!(m1_probe_cargo_check_jobs(), 4); + assert_eq!(m1_probe_cargo_check_jobs(), Some(4)); } #[test] fn witness_required_for_fleet_m1_derivation() { - assert!(ci_runner_pool_m1_probe_witness_holds( - &CI_SELF_HOSTED_RUNNER_POOLS - )); + assert!(ci_runner_pool_m1_probe_witness_holds()); } } diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 4571ab2103f..0dddb337eee 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -425,10 +425,11 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { "{CI_DAG_PATH}: srv1/srv2 pool rows must match operator spec" ); assert!( - CI_DAG.contains("data m1_probe_cargo_check_jobs: Int"), - "{CI_DAG_PATH}: M1 cargo parallelism must be a derived Int fact" + CI_DAG.contains("data m1_probe_cargo_check_jobs: Outcome"), + "{CI_DAG_PATH}: M1 cargo parallelism must remain Outcome (no Rejected→0 collapse)" ); - let m1_jobs = v3_compiler::v4_ci_runner_pool::m1_probe_cargo_check_jobs(); + let m1_jobs = v3_compiler::v4_ci_runner_pool::m1_probe_cargo_check_jobs() + .expect("fleet model must derive M1 cargo-check jobs"); assert_eq!( m1_jobs, 4, "Rust transport mirror of m1_probe_cargo_check_jobs must match ci.dag fleet model" diff --git a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag index c21649228a5..f45b8b071ad 100644 --- a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag +++ b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag @@ -32,11 +32,15 @@ fn runner_pool_m1_fanout_slots_holds() -> Bool { } fn runner_pool_m1_cargo_jobs_holds() -> Bool { - (m1_probe_cargo_check_jobs == 4) - && match ci_m1_probe_cargo_check_jobs_from_fleet() { - Accepted { value: jobs, diagnostics: _ } => jobs == 4 - Rejected { diagnostics: _ } => false - } + match m1_probe_cargo_check_jobs { + Accepted { value: jobs, diagnostics: _ } => + (jobs == 4) + && match ci_m1_probe_cargo_check_jobs_from_fleet() { + Accepted { value: derived, diagnostics: _ } => derived == 4 + Rejected { diagnostics: _ } => false + } + Rejected { diagnostics: _ } => false + } } data runner_pool_srv1_claim_passes: Bool = runner_pool_srv1_runner_count_holds() diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index c619ac75786..5aaf1702f79 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -721,12 +721,20 @@ fn ci_component_affected_from_git_diff_read(outcome: Outcome) - } -fn ci_int_at_least_one(n: Int) -> Int { - if n < 1 { - 1 - } else { - n - } +fn ci_int_positive(n: Int) -> Bool { + n >= 1 +} + + +fn ci_runner_pool_capacity_valid(pool: SelfHostedRunnerPool) -> Bool { + ci_int_positive(n: pool.core_count) + && ci_int_positive(n: pool.runner_count) + && ci_int_positive(n: pool.jobserver_token_cap) +} + + +fn ci_runner_pool_fleet_capacities_valid() -> Bool { + for_all(xs: ci_self_hosted_runner_pools, predicate: ci_runner_pool_capacity_valid) } @@ -784,15 +792,14 @@ fn ci_runner_pool_has_nonuniform_runner_counts_on_fleet() -> Bool { } -fn ci_runner_pool_m1_probe_witness_holds(pools: List) -> Bool { - non_empty(xs: pools) +fn ci_runner_pool_m1_probe_witness_holds() -> Bool { + ci_runner_pool_fleet_capacities_valid() + && non_empty(xs: ci_self_hosted_runner_pools) && ci_runner_pool_has_nonuniform_runner_counts_on_fleet() } -data ci_runner_pool_m1_probe_witness: Bool = ci_runner_pool_m1_probe_witness_holds( - pools: ci_self_hosted_runner_pools -) +data ci_runner_pool_m1_probe_witness: Bool = ci_runner_pool_m1_probe_witness_holds() fn ci_m1_probe_cargo_fanout_slots_from_fleet() -> Outcome { @@ -821,22 +828,22 @@ fn ci_m1_probe_cargo_fanout_slots_from_fleet() -> Outcome { fn ci_m1_probe_cargo_check_jobs_from_fleet() -> Outcome { match ci_m1_probe_cargo_fanout_slots_from_fleet() { Accepted { value: fanout_slots, diagnostics: _ } => - int_div( - a: ci_fleet_min_jobserver_token_cap(), - b: ci_int_at_least_one(n: fanout_slots), - at: Textual { file: ci_workflow_file, extent: WholeFile } - ) + if ci_int_positive(n: fanout_slots) { + int_div( + a: ci_fleet_min_jobserver_token_cap(), + b: fanout_slots, + at: Textual { file: ci_workflow_file, extent: WholeFile } + ) + } else { + Rejected { + diagnostics: diagnostics_singleton( + d: ci_diagnostic(reason: ci_runner_pool_non_positive_fanout) + ) + } + } Rejected { diagnostics: r } => Rejected { diagnostics: r } } } -fn ci_m1_probe_cargo_check_jobs_fleet_int() -> Int { - match ci_m1_probe_cargo_check_jobs_from_fleet() { - Accepted { value: jobs, diagnostics: _ } => jobs - Rejected { diagnostics: _ } => 0 - } -} - - -data m1_probe_cargo_check_jobs: Int = ci_m1_probe_cargo_check_jobs_fleet_int() +data m1_probe_cargo_check_jobs: Outcome = ci_m1_probe_cargo_check_jobs_from_fleet() From 8b1b4ecbf0292fa71d521e05115c16529b7e1aaf Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 04:03:37 +0000 Subject: [PATCH 31/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/workflow/ci.dag | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 5aaf1702f79..9810ac0a4ab 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -257,9 +257,7 @@ data ci_dangling_reference: Symbol = ci_dangling_reference data ci_dependency_cycle: Symbol = ci_dependency_cycle data ci_bootstrap_authority_violation: Symbol = ci_bootstrap_authority_violation data ci_workflow_file: Symbol = ci_workflow_file -data ci_runner_pool_m1_witness_violation: Symbol = ci_runner_pool_m1_witness_violation data ci_runner_pool_non_positive_capacity: Symbol = ci_runner_pool_non_positive_capacity -data ci_runner_pool_non_positive_fanout: Symbol = ci_runner_pool_non_positive_fanout fn ci_diagnostic(reason: Symbol) -> Diagnostic { Diagnostic { @@ -669,8 +667,8 @@ fn ci_changed_path_affects_v3(changed: RepoPath) -> Bool { fn ci_changed_path_affects_v4(changed: RepoPath) -> Bool { ci_repo_path_has_prefix(path: changed, prefix: "src/v4/") || ci_repo_path_has_prefix(path: changed, prefix: "fixtures/v4-mvp1/") - || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-mvp1") - || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-m1") + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-mvp1/") + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-m1/") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-testclaim-") || ci_repo_path_has_prefix(path: changed, prefix: "dsl/std/") || changed == "Cargo.toml" From 548516db6a5c656b66a55bd196a1c22bb62fde39 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 04:05:07 +0000 Subject: [PATCH 32/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _internal/INVARIANTS_OPS.md | 2 +- .../compiler/src/v4_ci_component_affected.rs | 4 +- src/v3/compiler/src/v4_ci_runner_pool.rs | 77 +----------- .../v4_workflow_ci_runner_dag_smoke_test.rs | 37 ++---- .../claim/workflow/runner_pool_m1_probe.dag | 26 +--- src/v4/workflow/ci.dag | 116 +----------------- 6 files changed, 25 insertions(+), 237 deletions(-) diff --git a/_internal/INVARIANTS_OPS.md b/_internal/INVARIANTS_OPS.md index 31e94f8d6ec..22eb5996a83 100644 --- a/_internal/INVARIANTS_OPS.md +++ b/_internal/INVARIANTS_OPS.md @@ -134,7 +134,7 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED | `src/v3/compiler/src/self_host_receipt_p0.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / T-FixedPoint P0 — stable JSON receipt keys for `self_host_fixed_point` trends (DB-8 hand receipt). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when receipt schema is `.dag`/generated-owned. **Interim ratchet:** field-name unit tests in-module. | | `src/v3/compiler/src/test_runner.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / **T-PB-B** — integration test runner host (`ExecuteCommand` / claim evaluation seam). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when runner is generated or substrate-owned without hand orchestration. **Interim ratchet:** integration + cementing suites. | | `src/v3/compiler/src/v4_ci_component_affected.rs` | **TASKS.md** T-24 — Rust mirror of `ci_component_affected_from_git_diff` path buckets (`src/v4/workflow/ci.dag` is authority; must stay aligned per `ci.dag` workflow_policy predicates). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when `detect-ci-affected-components` invokes `.dag` eval over `ci.dag` predicates with no parallel Rust path logic. **Interim ratchet:** `workflow_policy_paths_match_ci_dag_authority` unit test + integration smoke. | -| `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_derived_as_four` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | +| `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_is_operator_constant` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | | `src/v3/compiler/src/v4_hollow_alias_gate.rs` | **TASKS.md** **T-30** (`src/v4/TASKS.md`); **Spec:** `docs/modeling-discipline.md` **Practice 8** — *Interim floor: the hollow-alias discriminator* (Practice 8 *Interim floor* on `main` post-#3226 `77b9e7d72` + Practice 9 #3234 `125fc88c8`; diff `main` if §8/§9 drift). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when T-30's structural `Node → Outcome` gate is generated from v4 `.dag` authority (no handwritten Practice-8 mirror). **Interim ratchet:** hermetic unit tests in-module pin the three-part hollow predicate + kernel-ambient exemption; paired **P2-staging** `.dag` nominal witness at `src/v4/std/fact_density.dag` (`SourceSpecReadFact` — **not** a landed substrate primitive per INVARIANTS §P2 until a generated consumer reads it; dissolution to `Node` payload when the v4-isolated bootstrap path lands; see file header + **PR review** (no maintained manifest). **T-30 enforcement mechanism:** structural `fact_density_hollow_alias_gate: Node -> Outcome>` is wired from `src/v4/lens/fact_density.dag` into the temporary compile-local `InferredTree -> Outcome>` adapter `fact_density_hollow_alias_compile_gate` and `CompileLens` row `fact_density_lens` in `src/v4/compiler/00_compile.dag`, and `validate_then_compile` applies required gates with `run_required_lens_gates_on_subtree` across the inferred root and every child node (compiles via v4 bootstrap gate; P2 consumer-gated); six `.dag` TestClaims in `src/v4/test/claim/lens_fact_density/` — `hollow_alias_compile_lens_rejects`, `fact_bundle_compile_lens_passes`, `hollow_alias_blocked_in_run_gates`, `hollow_alias_blocked_via_always_required_lenses`, `hollow_alias_vtc_empty_lenses_rejected`, `hollow_alias_nested_rejected` — scaffold the gate through `apply_compile_lens` / `run_required_lens_gates` / `always_required_lenses()` / `validate_then_compile` with empty caller-lenses and nested hollow-alias rejection (compile-only until T-22 execution). | | `src/v3/compiler/src/wall_clock_ratchet_manifest.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — wall-clock warn manifest for CI/binary shims (timing discipline). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when timing manifest is `.dag` data consumed by codegen. **Interim ratchet:** modeled CI workflow tests. | --- diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index 03e93f7d548..b5fd3996ba9 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -63,8 +63,8 @@ pub fn ci_changed_path_affects_v3(path: &str) -> bool { pub fn ci_changed_path_affects_v4(path: &str) -> bool { path.starts_with("src/v4/") || path.starts_with("fixtures/v4-mvp1/") - || path.starts_with("scripts/v4-mvp1") - || path.starts_with("scripts/v4-m1") + || path.starts_with("scripts/v4-mvp1/") + || path.starts_with("scripts/v4-m1/") || path.starts_with("scripts/v4-testclaim-") || path.starts_with("dsl/std/") || path == "Cargo.toml" diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index 4a158bf9703..db3946473ae 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -34,37 +34,8 @@ pub const CI_SRV2_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { pub const CI_SELF_HOSTED_RUNNER_POOLS: [SelfHostedRunnerPool; 2] = [CI_SRV1_POOL, CI_SRV2_POOL]; -pub fn ci_fleet_min_jobserver_token_cap() -> u32 { - CI_SELF_HOSTED_RUNNER_POOLS - .iter() - .fold(CI_SRV1_POOL.jobserver_token_cap, |acc, pool| { - acc.min(pool.jobserver_token_cap) - }) -} - -pub fn ci_fleet_max_runner_count() -> u32 { - CI_SELF_HOSTED_RUNNER_POOLS - .iter() - .fold(CI_SRV1_POOL.runner_count, |acc, pool| { - acc.max(pool.runner_count) - }) -} - -pub fn ci_fleet_min_runner_count() -> u32 { - CI_SELF_HOSTED_RUNNER_POOLS - .iter() - .fold(CI_SRV1_POOL.runner_count, |acc, pool| { - acc.min(pool.runner_count) - }) -} - -pub fn ci_runner_pool_total_runner_count(pools: &[SelfHostedRunnerPool]) -> u32 { - pools.iter().map(|p| p.runner_count).sum() -} - -pub fn ci_runner_pool_host_count(pools: &[SelfHostedRunnerPool]) -> u32 { - pools.len() as u32 -} +/// Operator M1 probe cargo-check parallelism (`data m1_probe_cargo_check_jobs` in `ci.dag`). +pub const M1_PROBE_CARGO_CHECK_JOBS: u32 = 4; pub fn ci_int_positive(n: u32) -> bool { n >= 1 @@ -82,38 +53,9 @@ pub fn ci_runner_pool_fleet_capacities_valid() -> bool { .all(|pool| ci_runner_pool_capacity_valid(*pool)) } -pub fn ci_runner_pool_m1_probe_witness_holds() -> bool { - ci_runner_pool_fleet_capacities_valid() - && !CI_SELF_HOSTED_RUNNER_POOLS.is_empty() - && ci_fleet_max_runner_count() != ci_fleet_min_runner_count() -} - -pub fn ci_m1_probe_cargo_fanout_slots_from_fleet() -> Option { - if !ci_runner_pool_m1_probe_witness_holds() { - return None; - } - let min_runners = ci_fleet_min_runner_count(); - let max_runners = ci_fleet_max_runner_count(); - let spread = max_runners - min_runners; - if spread == 0 { - return None; - } - let total_runners = ci_runner_pool_total_runner_count(&CI_SELF_HOSTED_RUNNER_POOLS); - let hosts = ci_runner_pool_host_count(&CI_SELF_HOSTED_RUNNER_POOLS); - Some((total_runners - min_runners) * hosts / spread) -} - -pub fn ci_m1_probe_cargo_check_jobs_from_fleet() -> Option { - let fanout = ci_m1_probe_cargo_fanout_slots_from_fleet()?; - if !ci_int_positive(fanout) { - return None; - } - Some(ci_fleet_min_jobserver_token_cap() / fanout) -} - /// Modeled authority for `data m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. -pub fn m1_probe_cargo_check_jobs() -> Option { - ci_m1_probe_cargo_check_jobs_from_fleet() +pub fn m1_probe_cargo_check_jobs() -> u32 { + M1_PROBE_CARGO_CHECK_JOBS } #[cfg(test)] @@ -129,15 +71,8 @@ mod tests { } #[test] - fn m1_probe_cargo_check_jobs_derived_as_four() { + fn m1_probe_cargo_check_jobs_is_operator_constant() { assert!(ci_runner_pool_fleet_capacities_valid()); - assert_eq!(ci_m1_probe_cargo_fanout_slots_from_fleet(), Some(6)); - assert_eq!(ci_m1_probe_cargo_check_jobs_from_fleet(), Some(4)); - assert_eq!(m1_probe_cargo_check_jobs(), Some(4)); - } - - #[test] - fn witness_required_for_fleet_m1_derivation() { - assert!(ci_runner_pool_m1_probe_witness_holds()); + assert_eq!(m1_probe_cargo_check_jobs(), 4); } } diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 0dddb337eee..a6354413ac9 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -46,8 +46,8 @@ const CI_V3_PREFIXES: &[&str] = &["src/v3/", "dsl/"]; const CI_V4_PREFIXES: &[&str] = &[ "src/v4/", "fixtures/v4-mvp1/", - "scripts/v4-mvp1", - "scripts/v4-m1", + "scripts/v4-mvp1/", + "scripts/v4-m1/", "scripts/v4-testclaim-", "dsl/std/", ]; @@ -278,18 +278,10 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { import_includes_name(&module, &["v4", "std", "algebra"], "any"), "{CI_DAG_PATH}: must import any from std.algebra for path-bucket existence" ); - assert!( - import_includes_name(&module, &["v4", "std", "algebra"], "non_empty"), - "{CI_DAG_PATH}: must import non_empty from std.algebra for runner-pool witness" - ); assert!( CI_DAG.contains("any(xs: git_diff.changed_paths, predicate: ci_changed_path_affects_v2)"), "{CI_DAG_PATH}: component affected-set must use std.algebra any" ); - assert!( - CI_DAG.contains("non_empty(xs: pools)"), - "{CI_DAG_PATH}: M1 probe witness must use std.algebra non_empty" - ); assert!( !CI_DAG.contains("CiGitDiffReadOutcome"), "{CI_DAG_PATH}: git diff read must use canonical Outcome, not a parallel coproduct" @@ -301,20 +293,12 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { "{CI_DAG_PATH}: git diff read boundary must project through std.diagnostic Outcome" ); assert!( - !CI_DAG.contains("ci_int_div_totalizing"), - "{CI_DAG_PATH}: runner-pool arithmetic must not fabricate int_div Rejected into a plausible quotient" - ); - assert!( - !CI_DAG.contains("ci_int_min_fold_sentinel"), - "{CI_DAG_PATH}: fleet min folds must seed from ci_srv1_pool rows, not a magic sentinel" - ); - assert!( - CI_DAG.contains("init: ci_srv1_pool.runner_count"), - "{CI_DAG_PATH}: fleet min/max folds must seed from modeled srv1 pool row" + !CI_DAG.contains("ci_m1_probe_cargo_fanout_slots_from_fleet"), + "{CI_DAG_PATH}: M1 cargo jobs must not use reverse-engineered fleet fanout derivation" ); assert!( - CI_DAG.contains("ci_m1_probe_cargo_fanout_slots_from_fleet()"), - "{CI_DAG_PATH}: M1 fanout must derive through witness-gated Outcome fleet API" + CI_DAG.contains("data m1_probe_cargo_check_jobs: Int = 4"), + "{CI_DAG_PATH}: M1 cargo parallelism must be an explicit operator constant in Wave-0" ); assert!( CI_DAG.contains("RerunNodeSetFailClosed { evidence: _ } => roster"), @@ -425,14 +409,13 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { "{CI_DAG_PATH}: srv1/srv2 pool rows must match operator spec" ); assert!( - CI_DAG.contains("data m1_probe_cargo_check_jobs: Outcome"), - "{CI_DAG_PATH}: M1 cargo parallelism must remain Outcome (no Rejected→0 collapse)" + CI_DAG.contains("data m1_probe_cargo_check_jobs: Int = 4"), + "{CI_DAG_PATH}: M1 cargo parallelism must be an explicit operator constant" ); - let m1_jobs = v3_compiler::v4_ci_runner_pool::m1_probe_cargo_check_jobs() - .expect("fleet model must derive M1 cargo-check jobs"); + let m1_jobs = v3_compiler::v4_ci_runner_pool::m1_probe_cargo_check_jobs(); assert_eq!( m1_jobs, 4, - "Rust transport mirror of m1_probe_cargo_check_jobs must match ci.dag fleet model" + "Rust transport mirror of m1_probe_cargo_check_jobs must match ci.dag operator constant" ); assert!( m1_step.contains(&format!("V4_M1_CARGO_CHECK_JOBS: \"{m1_jobs}\"")), diff --git a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag index f45b8b071ad..848d5496d61 100644 --- a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag +++ b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag @@ -1,16 +1,10 @@ // src/v4/test/claim/workflow/runner_pool_m1_probe.dag -// Scope: T-24 self-hosted runner pool + derived M1 cargo-check parallelism (operator srv1/srv2 spec). +// Scope: T-24 self-hosted runner pool + operator M1 cargo-check parallelism (srv1/srv2 spec). module v4.test.claim.workflow.runner_pool_m1_probe -import v4.std.collection { List } -import v4.std.diagnostic { Accepted, Outcome, Rejected } import v4.std.logic { Bool } import v4.workflow.ci { - SelfHostedRunnerPool, - ci_m1_probe_cargo_check_jobs_from_fleet, - ci_m1_probe_cargo_fanout_slots_from_fleet, - ci_self_hosted_runner_pools, ci_srv1_pool, ci_srv2_pool, m1_probe_cargo_check_jobs @@ -24,26 +18,10 @@ fn runner_pool_srv2_jobserver_cap_holds() -> Bool { ci_srv2_pool.jobserver_token_cap == 36 } -fn runner_pool_m1_fanout_slots_holds() -> Bool { - match ci_m1_probe_cargo_fanout_slots_from_fleet() { - Accepted { value: fanout, diagnostics: _ } => fanout == 6 - Rejected { diagnostics: _ } => false - } -} - fn runner_pool_m1_cargo_jobs_holds() -> Bool { - match m1_probe_cargo_check_jobs { - Accepted { value: jobs, diagnostics: _ } => - (jobs == 4) - && match ci_m1_probe_cargo_check_jobs_from_fleet() { - Accepted { value: derived, diagnostics: _ } => derived == 4 - Rejected { diagnostics: _ } => false - } - Rejected { diagnostics: _ } => false - } + m1_probe_cargo_check_jobs == 4 } data runner_pool_srv1_claim_passes: Bool = runner_pool_srv1_runner_count_holds() data runner_pool_srv2_claim_passes: Bool = runner_pool_srv2_jobserver_cap_holds() -data runner_pool_fanout_claim_passes: Bool = runner_pool_m1_fanout_slots_holds() data runner_pool_m1_jobs_claim_passes: Bool = runner_pool_m1_cargo_jobs_holds() diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 9810ac0a4ab..e3fbfb30999 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -50,7 +50,6 @@ import v4.std.algebra { fold_list } import v4.std.collection { List } import v4.std.text { Char, String } import v4.std.diagnostic {Correction, Diagnostic, Extent, Locus, NoCorrectionReason, Outcome, Accepted, Rejected, None, diagnostics_singleton} -import v4.std.integer { int_mul, int_div } import v4.std.algebra { any, count_equal, @@ -59,7 +58,6 @@ import v4.std.algebra { for_all, is_prefix_of, length, - non_empty, unique } import v4.std.verification { @@ -257,7 +255,6 @@ data ci_dangling_reference: Symbol = ci_dangling_reference data ci_dependency_cycle: Symbol = ci_dependency_cycle data ci_bootstrap_authority_violation: Symbol = ci_bootstrap_authority_violation data ci_workflow_file: Symbol = ci_workflow_file -data ci_runner_pool_non_positive_capacity: Symbol = ci_runner_pool_non_positive_capacity fn ci_diagnostic(reason: Symbol) -> Diagnostic { Diagnostic { @@ -736,112 +733,7 @@ fn ci_runner_pool_fleet_capacities_valid() -> Bool { } -fn ci_runner_pool_total_runner_count(pools: List) -> Int { - fold(pools, init: 0, f: fn(acc, pool) { - acc + pool.runner_count - }) -} - - -fn ci_runner_pool_host_count(pools: List) -> Int { - length(xs: pools) -} - - -fn ci_fleet_min_runner_count() -> Int { - fold(ci_self_hosted_runner_pools, init: ci_srv1_pool.runner_count, f: fn(acc, pool) { - if pool.runner_count < acc { - pool.runner_count - } else { - acc - } - }) -} - - -fn ci_fleet_max_runner_count() -> Int { - fold(ci_self_hosted_runner_pools, init: ci_srv1_pool.runner_count, f: fn(acc, pool) { - if pool.runner_count > acc { - pool.runner_count - } else { - acc - } - }) -} - - -fn ci_fleet_min_jobserver_token_cap() -> Int { - fold( - ci_self_hosted_runner_pools, - init: ci_srv1_pool.jobserver_token_cap, - f: fn(acc, pool) { - if pool.jobserver_token_cap < acc { - pool.jobserver_token_cap - } else { - acc - } - } - ) -} - - -fn ci_runner_pool_has_nonuniform_runner_counts_on_fleet() -> Bool { - ci_fleet_max_runner_count() != ci_fleet_min_runner_count() -} - - -fn ci_runner_pool_m1_probe_witness_holds() -> Bool { - ci_runner_pool_fleet_capacities_valid() - && non_empty(xs: ci_self_hosted_runner_pools) - && ci_runner_pool_has_nonuniform_runner_counts_on_fleet() -} - - -data ci_runner_pool_m1_probe_witness: Bool = ci_runner_pool_m1_probe_witness_holds() - - -fn ci_m1_probe_cargo_fanout_slots_from_fleet() -> Outcome { - if ci_runner_pool_m1_probe_witness { - let min_runners = ci_fleet_min_runner_count() - let max_runners = ci_fleet_max_runner_count() - let spread = max_runners - min_runners - int_div( - a: int_mul( - a: ci_runner_pool_total_runner_count(pools: ci_self_hosted_runner_pools) - min_runners, - b: ci_runner_pool_host_count(pools: ci_self_hosted_runner_pools) - ), - b: spread, - at: Textual { file: ci_workflow_file, extent: WholeFile } - ) - } else { - Rejected { - diagnostics: diagnostics_singleton( - d: ci_diagnostic(reason: ci_runner_pool_m1_witness_violation) - ) - } - } -} - - -fn ci_m1_probe_cargo_check_jobs_from_fleet() -> Outcome { - match ci_m1_probe_cargo_fanout_slots_from_fleet() { - Accepted { value: fanout_slots, diagnostics: _ } => - if ci_int_positive(n: fanout_slots) { - int_div( - a: ci_fleet_min_jobserver_token_cap(), - b: fanout_slots, - at: Textual { file: ci_workflow_file, extent: WholeFile } - ) - } else { - Rejected { - diagnostics: diagnostics_singleton( - d: ci_diagnostic(reason: ci_runner_pool_non_positive_fanout) - ) - } - } - Rejected { diagnostics: r } => Rejected { diagnostics: r } - } -} - - -data m1_probe_cargo_check_jobs: Outcome = ci_m1_probe_cargo_check_jobs_from_fleet() +// RULING-1: 🟢 operator fact — M1 rust-emit probe `cargo check --jobs` cap (operator 2026-05-28). +// Wave-0: explicit constant, not fleet-derived (jobserver÷runner allocation rule unpublished). +// ci_srv1_pool/ci_srv2_pool retain host capacity facts for YamlStatic projection follow-on (T-24/#98). +data m1_probe_cargo_check_jobs: Int = 4 From 6e8d026401d6483b21a6742b71e9745622a42ea5 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 05:12:39 +0000 Subject: [PATCH 33/56] =?UTF-8?q?fix(ci.dag):=20close=20RunnerArch=20to=20?= =?UTF-8?q?Arm64=20=E2=80=94=20delete=20open=20Unknown=20fallback?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Operator srv1/srv2 fleet rows only evidence Arm64; RunnerArchUnknown admitted an ungrounded pool state (codex RC @548516db, inline @ci.dag:121). Smoke test ratchets closed coproduct (codex 20315-class substrate fix). Co-authored-by: Cursor --- src/v3/compiler/src/v4_ci_runner_pool.rs | 2 +- .../integration/v4_workflow_ci_runner_dag_smoke_test.rs | 8 ++++++++ src/v4/workflow/ci.dag | 5 ++--- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index db3946473ae..be8bf60693f 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -1,6 +1,6 @@ //! Structural mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. -/// Structural mirror of `RunnerArch::Arm64` (single host arch today). +/// Closed fleet fact: operator srv1/srv2 are Arm64 only (`type RunnerArch = Arm64` in `ci.dag`). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RunnerArch { Arm64, diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index a6354413ac9..faa9abce90f 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -399,6 +399,14 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { CI_DAG.contains("type SelfHostedRunnerPool"), "{CI_DAG_PATH}: must model self-hosted runner pools (T-24 addendum)" ); + assert!( + !CI_DAG.contains("RunnerArchUnknown"), + "{CI_DAG_PATH}: runner arch must be closed Arm64 fleet fact, not an open fallback enum" + ); + assert!( + CI_DAG.contains("type RunnerArch = Arm64"), + "{CI_DAG_PATH}: runner arch must be a closed single-variant coproduct" + ); assert!( CI_DAG.contains("data ci_srv1_pool: SelfHostedRunnerPool") && CI_DAG.contains("runner_count: 20") diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index e3fbfb30999..284281ccabb 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -116,9 +116,8 @@ type CiComponentAffected { // Uses canonical `Outcome` from std.diagnostic (Practice 10 — no parallel read carrier). // RULING-1: 🟢 pretty-much-done — self-hosted fleet substrate (operator 2026-05-28: srv1/srv2 Ampere Altra). // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. -type RunnerArch - = Arm64 - | RunnerArchUnknown +// Closed fleet fact: operator srv1/srv2 are Ampere Altra (Arm64) only — no open fallback variant. +type RunnerArch = Arm64 type SelfHostedRunnerPool { host: Symbol From b2d8ad8c41fe3e5640b2bed4a45526e32dfdb96a Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 05:19:11 +0000 Subject: [PATCH 34/56] fix(ci.dag): restore single-variant RunnerArch enum for v4 compile MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `type RunnerArch = Arm64` alias syntax is unresolved in Lens-CI v4 compile (CI 26619390306). Keep closed coproduct with only `Arm64` variant — Unknown fallback still deleted. Co-authored-by: Cursor --- src/v3/compiler/src/v4_ci_runner_pool.rs | 2 +- .../tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs | 4 +++- src/v4/workflow/ci.dag | 3 ++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index be8bf60693f..ca8c797dd36 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -1,6 +1,6 @@ //! Structural mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. -/// Closed fleet fact: operator srv1/srv2 are Arm64 only (`type RunnerArch = Arm64` in `ci.dag`). +/// Closed fleet fact: operator srv1/srv2 are Arm64 only (single-variant `RunnerArch` in `ci.dag`). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RunnerArch { Arm64, diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index faa9abce90f..de08f428e92 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -404,7 +404,9 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { "{CI_DAG_PATH}: runner arch must be closed Arm64 fleet fact, not an open fallback enum" ); assert!( - CI_DAG.contains("type RunnerArch = Arm64"), + CI_DAG.contains("type RunnerArch") + && CI_DAG.contains("= Arm64") + && !CI_DAG.contains("RunnerArchUnknown"), "{CI_DAG_PATH}: runner arch must be a closed single-variant coproduct" ); assert!( diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 284281ccabb..c52f93cde63 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -117,7 +117,8 @@ type CiComponentAffected { // RULING-1: 🟢 pretty-much-done — self-hosted fleet substrate (operator 2026-05-28: srv1/srv2 Ampere Altra). // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. // Closed fleet fact: operator srv1/srv2 are Ampere Altra (Arm64) only — no open fallback variant. -type RunnerArch = Arm64 +type RunnerArch + = Arm64 type SelfHostedRunnerPool { host: Symbol From 9399374b0634fa9f9b5969fdedf3cd872403fdbd Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 05:26:50 +0000 Subject: [PATCH 35/56] fix(ci.dag): rename RunnerArch variant to RunnerArchArm64 for v4 compile Lens-CI v4 compile treats bare `Arm64` as unresolved type, not a sum variant tag (CI 26619597241). Prefix variant per v4 naming convention; Unknown fallback remains deleted. Co-authored-by: Cursor --- src/v3/compiler/src/v4_ci_runner_pool.rs | 6 +++--- .../integration/v4_workflow_ci_runner_dag_smoke_test.rs | 2 +- src/v4/workflow/ci.dag | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index ca8c797dd36..62367f50eff 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -3,7 +3,7 @@ /// Closed fleet fact: operator srv1/srv2 are Arm64 only (single-variant `RunnerArch` in `ci.dag`). #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RunnerArch { - Arm64, + RunnerArchArm64, } /// Structural mirror of `SelfHostedRunnerPool` in `src/v4/workflow/ci.dag`. @@ -18,7 +18,7 @@ pub struct SelfHostedRunnerPool { pub const CI_SRV1_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { host: "srv1", - arch: RunnerArch::Arm64, + arch: RunnerArch::RunnerArchArm64, core_count: 128, runner_count: 20, jobserver_token_cap: 25, @@ -26,7 +26,7 @@ pub const CI_SRV1_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { pub const CI_SRV2_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { host: "srv2", - arch: RunnerArch::Arm64, + arch: RunnerArch::RunnerArchArm64, core_count: 128, runner_count: 30, jobserver_token_cap: 36, diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index de08f428e92..7082a2da39a 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -405,7 +405,7 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { ); assert!( CI_DAG.contains("type RunnerArch") - && CI_DAG.contains("= Arm64") + && CI_DAG.contains("= RunnerArchArm64") && !CI_DAG.contains("RunnerArchUnknown"), "{CI_DAG_PATH}: runner arch must be a closed single-variant coproduct" ); diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index c52f93cde63..51d0b990f64 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -118,7 +118,7 @@ type CiComponentAffected { // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. // Closed fleet fact: operator srv1/srv2 are Ampere Altra (Arm64) only — no open fallback variant. type RunnerArch - = Arm64 + = RunnerArchArm64 type SelfHostedRunnerPool { host: Symbol @@ -159,7 +159,7 @@ data ci_srv2_host: Symbol = ci_srv2_host data ci_srv1_pool: SelfHostedRunnerPool = { host: ci_srv1_host - arch: Arm64 + arch: RunnerArchArm64 core_count: 128 runner_count: 20 jobserver_token_cap: 25 @@ -167,7 +167,7 @@ data ci_srv1_pool: SelfHostedRunnerPool = { data ci_srv2_pool: SelfHostedRunnerPool = { host: ci_srv2_host - arch: Arm64 + arch: RunnerArchArm64 core_count: 128 runner_count: 30 jobserver_token_cap: 36 From fa186159a173f32dc44c80a01227e5466bb36162 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 05:34:58 +0000 Subject: [PATCH 36/56] =?UTF-8?q?fix(ci.dag):=20drop=20RunnerArch=20coprod?= =?UTF-8?q?uct=20=E2=80=94=20Lens-CI=20entry=20compile=20cannot=20resolve?= =?UTF-8?q?=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Isolated v4 compile of ci.dag fails on any RunnerArch variant tag (Arm64, RunnerArchArm64). Fleet Arm64 is a comment-level closed operator fact; pool struct keeps host/capacity fields only. Rename misleading unit test. Co-authored-by: Cursor --- src/v3/compiler/src/v4_ci_component_affected.rs | 2 +- src/v3/compiler/src/v4_ci_runner_pool.rs | 10 +--------- .../v4_workflow_ci_runner_dag_smoke_test.rs | 10 ++-------- src/v4/workflow/ci.dag | 11 +++-------- 4 files changed, 7 insertions(+), 26 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index b5fd3996ba9..7974eb201da 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -113,7 +113,7 @@ mod tests { } #[test] - fn workflow_policy_paths_match_ci_dag_authority() { + fn workflow_policy_sample_paths_are_in_workflow_policy_bucket() { assert!(ci_changed_path_affects_workflow_policy( "src/v4/workflow/ci.dag" )); diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index 62367f50eff..e5b8c78a9f0 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -1,16 +1,10 @@ //! Structural mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. - -/// Closed fleet fact: operator srv1/srv2 are Arm64 only (single-variant `RunnerArch` in `ci.dag`). -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum RunnerArch { - RunnerArchArm64, -} +//! Operator fleet is Ampere Altra (Arm64) only — arch is a comment-level closed fact in `ci.dag`, not a field. /// Structural mirror of `SelfHostedRunnerPool` in `src/v4/workflow/ci.dag`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct SelfHostedRunnerPool { pub host: &'static str, - pub arch: RunnerArch, pub core_count: u32, pub runner_count: u32, pub jobserver_token_cap: u32, @@ -18,7 +12,6 @@ pub struct SelfHostedRunnerPool { pub const CI_SRV1_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { host: "srv1", - arch: RunnerArch::RunnerArchArm64, core_count: 128, runner_count: 20, jobserver_token_cap: 25, @@ -26,7 +19,6 @@ pub const CI_SRV1_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { pub const CI_SRV2_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { host: "srv2", - arch: RunnerArch::RunnerArchArm64, core_count: 128, runner_count: 30, jobserver_token_cap: 36, diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 7082a2da39a..4adcfcbd215 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -400,14 +400,8 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { "{CI_DAG_PATH}: must model self-hosted runner pools (T-24 addendum)" ); assert!( - !CI_DAG.contains("RunnerArchUnknown"), - "{CI_DAG_PATH}: runner arch must be closed Arm64 fleet fact, not an open fallback enum" - ); - assert!( - CI_DAG.contains("type RunnerArch") - && CI_DAG.contains("= RunnerArchArm64") - && !CI_DAG.contains("RunnerArchUnknown"), - "{CI_DAG_PATH}: runner arch must be a closed single-variant coproduct" + !CI_DAG.contains("RunnerArch"), + "{CI_DAG_PATH}: fleet Arm64 is a comment-level closed fact — no RunnerArch coproduct in Lens-CI entry compile" ); assert!( CI_DAG.contains("data ci_srv1_pool: SelfHostedRunnerPool") diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 51d0b990f64..69fb2bb7ddb 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -114,15 +114,12 @@ type CiComponentAffected { // RULING-1: 🟢 pretty-much-done — host `git diff --name-only` read outcome (T-24 / INVARIANTS P3). // `Rejected` selects the superset `ci_component_affected_fail_closed` (all flags true). // Uses canonical `Outcome` from std.diagnostic (Practice 10 — no parallel read carrier). -// RULING-1: 🟢 pretty-much-done — self-hosted fleet substrate (operator 2026-05-28: srv1/srv2 Ampere Altra). +// RULING-1: 🟢 pretty-much-done — self-hosted fleet substrate (operator 2026-05-28: srv1/srv2 Ampere Altra / Arm64). // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. -// Closed fleet fact: operator srv1/srv2 are Ampere Altra (Arm64) only — no open fallback variant. -type RunnerArch - = RunnerArchArm64 - +// Fleet arch is a closed operator fact (Arm64 only) — modeled in comments, not a sum type, so Lens-CI +// entry compile of this module does not need a coproduct the isolated v4 compiler cannot resolve. type SelfHostedRunnerPool { host: Symbol - arch: RunnerArch core_count: Int // 🟡 gated: formatter-int-refinement — must be ≥1 (operator fleet spec) runner_count: Int // 🟡 gated: formatter-int-refinement — must be ≥1 jobserver_token_cap: Int // 🟡 gated: formatter-int-refinement — must be ≥1 @@ -159,7 +156,6 @@ data ci_srv2_host: Symbol = ci_srv2_host data ci_srv1_pool: SelfHostedRunnerPool = { host: ci_srv1_host - arch: RunnerArchArm64 core_count: 128 runner_count: 20 jobserver_token_cap: 25 @@ -167,7 +163,6 @@ data ci_srv1_pool: SelfHostedRunnerPool = { data ci_srv2_pool: SelfHostedRunnerPool = { host: ci_srv2_host - arch: RunnerArchArm64 core_count: 128 runner_count: 30 jobserver_token_cap: 36 From a3e8947a9e3bf6dc8b7a1443c8847de5f159a419 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 06:09:24 +0000 Subject: [PATCH 37/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v3/compiler/src/v4_ci_component_affected.rs | 4 ++-- src/v4/workflow/ci.dag | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index 7974eb201da..cb2d93a8d9b 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -63,8 +63,8 @@ pub fn ci_changed_path_affects_v3(path: &str) -> bool { pub fn ci_changed_path_affects_v4(path: &str) -> bool { path.starts_with("src/v4/") || path.starts_with("fixtures/v4-mvp1/") - || path.starts_with("scripts/v4-mvp1/") - || path.starts_with("scripts/v4-m1/") + || path == "scripts/v4-mvp1-e2e-gate.sh" + || path == "scripts/v4-m1-rust-emit-probe.sh" || path.starts_with("scripts/v4-testclaim-") || path.starts_with("dsl/std/") || path == "Cargo.toml" diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 69fb2bb7ddb..f3844b6fbfa 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -659,8 +659,8 @@ fn ci_changed_path_affects_v3(changed: RepoPath) -> Bool { fn ci_changed_path_affects_v4(changed: RepoPath) -> Bool { ci_repo_path_has_prefix(path: changed, prefix: "src/v4/") || ci_repo_path_has_prefix(path: changed, prefix: "fixtures/v4-mvp1/") - || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-mvp1/") - || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-m1/") + || changed == "scripts/v4-mvp1-e2e-gate.sh" + || changed == "scripts/v4-m1-rust-emit-probe.sh" || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-testclaim-") || ci_repo_path_has_prefix(path: changed, prefix: "dsl/std/") || changed == "Cargo.toml" From e01bb307ee1bce953d0d25924fe4f3fed8b9a87c Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 06:10:55 +0000 Subject: [PATCH 38/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v3/compiler/src/v4_ci_component_affected.rs | 15 +++++++++++++++ .../v4_workflow_ci_runner_dag_smoke_test.rs | 11 ++++++++--- .../claim/workflow/ci_component_affected.dag | 16 +++++++++++++++- src/v4/workflow/ci.dag | 2 ++ 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index cb2d93a8d9b..705c277d03f 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -65,6 +65,8 @@ pub fn ci_changed_path_affects_v4(path: &str) -> bool { || path.starts_with("fixtures/v4-mvp1/") || path == "scripts/v4-mvp1-e2e-gate.sh" || path == "scripts/v4-m1-rust-emit-probe.sh" + || path.starts_with("scripts/v4-mvp1") + || path.starts_with("scripts/v4-m1") || path.starts_with("scripts/v4-testclaim-") || path.starts_with("dsl/std/") || path == "Cargo.toml" @@ -96,9 +98,22 @@ mod tests { fn v3_freeze_ignores_cargo_toml_for_v3_only() { assert!(!ci_changed_path_affects_v3("Cargo.toml")); assert!(ci_changed_path_affects_v3("src/v3/compiler/src/lib.rs")); + assert!(ci_changed_path_affects_v3("dsl/gunbc/ci.dag")); assert!(ci_changed_path_affects_v3("dsl/std/node.dag")); } + #[test] + fn v4_m1_probe_script_triggers_v4_bucket() { + assert!(ci_changed_path_affects_v4("scripts/v4-m1-rust-emit-probe.sh")); + assert!(ci_changed_path_affects_v4("scripts/v4-mvp1-e2e-gate.sh")); + } + + #[test] + fn dsl_std_triggers_v3_and_v4() { + assert!(ci_changed_path_affects_v3("dsl/std/node.dag")); + assert!(ci_changed_path_affects_v4("dsl/std/node.dag")); + } + #[test] fn workflow_policy_includes_modeled_ci_authority() { assert!(ci_changed_path_affects_workflow_policy( diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 4adcfcbd215..982c1263e3a 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -46,12 +46,17 @@ const CI_V3_PREFIXES: &[&str] = &["src/v3/", "dsl/"]; const CI_V4_PREFIXES: &[&str] = &[ "src/v4/", "fixtures/v4-mvp1/", - "scripts/v4-mvp1/", - "scripts/v4-m1/", + "scripts/v4-mvp1", + "scripts/v4-m1", "scripts/v4-testclaim-", "dsl/std/", ]; -const CI_V4_EXACT_PATHS: &[&str] = &["Cargo.toml", "Cargo.lock"]; +const CI_V4_EXACT_PATHS: &[&str] = &[ + "Cargo.toml", + "Cargo.lock", + "scripts/v4-mvp1-e2e-gate.sh", + "scripts/v4-m1-rust-emit-probe.sh", +]; fn assert_ci_dag_rust_prefix_parity(prefixes: &[&str]) { for prefix in prefixes { diff --git a/src/v4/test/claim/workflow/ci_component_affected.dag b/src/v4/test/claim/workflow/ci_component_affected.dag index 5e2c0114700..0922b00c298 100644 --- a/src/v4/test/claim/workflow/ci_component_affected.dag +++ b/src/v4/test/claim/workflow/ci_component_affected.dag @@ -15,8 +15,10 @@ import v4.workflow.ci { data ci_comp_path_src_v2: RepoPath = "src/v2/stage0/Cargo.toml" data ci_comp_path_cargo_lock: RepoPath = "Cargo.lock" data ci_comp_path_src_v3: RepoPath = "src/v3/compiler/src/lib.rs" +data ci_comp_path_dsl_v3_only: RepoPath = "dsl/gunbc/ci.dag" data ci_comp_path_dsl_std: RepoPath = "dsl/std/node.dag" data ci_comp_path_src_v4: RepoPath = "src/v4/workflow/ci.dag" +data ci_comp_path_v4_m1_script: RepoPath = "scripts/v4-m1-rust-emit-probe.sh" data ci_comp_path_workflow_yml: RepoPath = ".github/workflows/ci.yml" data ci_comp_path_unrelated: RepoPath = "docs/README.md" @@ -30,10 +32,20 @@ fn ci_comp_v2_from_src_v2_holds() -> Bool { } fn ci_comp_v3_from_dsl_holds() -> Bool { - let f = ci_comp_flags_for(paths: [ci_comp_path_dsl_std]) + let f = ci_comp_flags_for(paths: [ci_comp_path_dsl_v3_only]) !f.v2 && f.v3 && !f.v4 } +fn ci_comp_v3_and_v4_from_dsl_std_holds() -> Bool { + let f = ci_comp_flags_for(paths: [ci_comp_path_dsl_std]) + !f.v2 && f.v3 && f.v4 +} + +fn ci_comp_v4_from_m1_script_holds() -> Bool { + let f = ci_comp_flags_for(paths: [ci_comp_path_v4_m1_script]) + !f.v2 && !f.v3 && f.v4 +} + fn ci_comp_v4_and_policy_from_ci_dag_holds() -> Bool { let f = ci_comp_flags_for(paths: [ci_comp_path_src_v4]) f.v4 && f.workflow_policy @@ -51,6 +63,8 @@ fn ci_comp_unrelated_all_false_holds() -> Bool { data ci_comp_v2_claim_passes: Bool = ci_comp_v2_from_src_v2_holds() data ci_comp_v3_claim_passes: Bool = ci_comp_v3_from_dsl_holds() +data ci_comp_v3_v4_dsl_std_claim_passes: Bool = ci_comp_v3_and_v4_from_dsl_std_holds() +data ci_comp_v4_m1_script_claim_passes: Bool = ci_comp_v4_from_m1_script_holds() data ci_comp_v4_policy_claim_passes: Bool = ci_comp_v4_and_policy_from_ci_dag_holds() data ci_comp_cargo_lock_claim_passes: Bool = ci_comp_cargo_lock_v2_v4_not_v3_holds() data ci_comp_unrelated_claim_passes: Bool = ci_comp_unrelated_all_false_holds() diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index f3844b6fbfa..99cd8dede56 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -661,6 +661,8 @@ fn ci_changed_path_affects_v4(changed: RepoPath) -> Bool { || ci_repo_path_has_prefix(path: changed, prefix: "fixtures/v4-mvp1/") || changed == "scripts/v4-mvp1-e2e-gate.sh" || changed == "scripts/v4-m1-rust-emit-probe.sh" + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-mvp1") + || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-m1") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/v4-testclaim-") || ci_repo_path_has_prefix(path: changed, prefix: "dsl/std/") || changed == "Cargo.toml" From dab76309ad768293bf1d363e909b8990bf9209e3 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 06:12:20 +0000 Subject: [PATCH 39/56] chore: apply cargo fmt (CI fmt gate on e01bb307e) Co-authored-by: Cursor --- src/v3/compiler/src/v4_ci_component_affected.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs index 705c277d03f..61bfa79f064 100644 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ b/src/v3/compiler/src/v4_ci_component_affected.rs @@ -104,7 +104,9 @@ mod tests { #[test] fn v4_m1_probe_script_triggers_v4_bucket() { - assert!(ci_changed_path_affects_v4("scripts/v4-m1-rust-emit-probe.sh")); + assert!(ci_changed_path_affects_v4( + "scripts/v4-m1-rust-emit-probe.sh" + )); assert!(ci_changed_path_affects_v4("scripts/v4-mvp1-e2e-gate.sh")); } From 9485d7c26365998aabca40f473e1ae7a3baf9bdb Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 06:35:01 +0000 Subject: [PATCH 40/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/ci_affected_components/Cargo.toml | 13 +++ tools/ci_affected_components/src/lib.rs | 146 ++++++++++++++++++++++++ 2 files changed, 159 insertions(+) create mode 100644 tools/ci_affected_components/Cargo.toml create mode 100644 tools/ci_affected_components/src/lib.rs diff --git a/tools/ci_affected_components/Cargo.toml b/tools/ci_affected_components/Cargo.toml new file mode 100644 index 00000000000..8ed5170a603 --- /dev/null +++ b/tools/ci_affected_components/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "ci_affected_components" +version.workspace = true +edition.workspace = true +license.workspace = true +publish = false + +[lib] +path = "src/lib.rs" + +[[bin]] +name = "detect-ci-affected-components" +path = "src/main.rs" diff --git a/tools/ci_affected_components/src/lib.rs b/tools/ci_affected_components/src/lib.rs new file mode 100644 index 00000000000..8aaacc16cde --- /dev/null +++ b/tools/ci_affected_components/src/lib.rs @@ -0,0 +1,146 @@ +//! v4 `workflow/ci.dag` component affected-set — always-supported CI host transport. +//! +//! **Modeled authority:** `src/v4/workflow/ci.dag` (`ci_component_affected_from_git_diff` and +//! `ci_changed_path_affects_*`). This crate is an interim Rust mirror of those predicates for +//! the CI runner (not `.dag` eval yet); keep aligned via `v4_workflow_ci_runner_dag_smoke_test` +//! prefix parity. Lives outside `v3-compiler` so the affected job can emit `v3=false` without +//! compiling the frozen v3 package first (INVARIANTS P3 fail-closed boundary). + +/// Structural mirror of `CiComponentAffected` in `src/v4/workflow/ci.dag`. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct CiComponentAffected { + pub v2: bool, + pub v3: bool, + pub v4: bool, + pub workflow_policy: bool, +} + +/// Mirror of `ci_component_affected_fail_closed` — all components affected (INVARIANTS P3). +pub fn ci_component_affected_fail_closed() -> CiComponentAffected { + CiComponentAffected { + v2: true, + v3: true, + v4: true, + workflow_policy: true, + } +} + +/// Map `git diff --name-only` paths to component flags (same semantics as `ci.dag`). +pub fn ci_component_affected_from_changed_paths<'a, I>(changed: I) -> CiComponentAffected +where + I: IntoIterator, +{ + let mut out = CiComponentAffected { + v2: false, + v3: false, + v4: false, + workflow_policy: false, + }; + for path in changed { + if ci_changed_path_affects_v2(path) { + out.v2 = true; + } + if ci_changed_path_affects_v3(path) { + out.v3 = true; + } + if ci_changed_path_affects_v4(path) { + out.v4 = true; + } + if ci_changed_path_affects_workflow_policy(path) { + out.workflow_policy = true; + } + } + out +} + +pub fn ci_changed_path_affects_v2(path: &str) -> bool { + path.starts_with("src/v2/") || path == "Cargo.toml" || path == "Cargo.lock" +} + +pub fn ci_changed_path_affects_v3(path: &str) -> bool { + path.starts_with("src/v3/") || path.starts_with("dsl/") +} + +pub fn ci_changed_path_affects_v4(path: &str) -> bool { + path.starts_with("src/v4/") + || path.starts_with("fixtures/v4-mvp1/") + || path == "scripts/v4-mvp1-e2e-gate.sh" + || path == "scripts/v4-m1-rust-emit-probe.sh" + || path.starts_with("scripts/v4-mvp1") + || path.starts_with("scripts/v4-m1") + || path.starts_with("scripts/v4-testclaim-") + || path.starts_with("dsl/std/") + || path == "Cargo.toml" + || path == "Cargo.lock" +} + +pub fn ci_changed_path_affects_workflow_policy(path: &str) -> bool { + path.starts_with(".github/workflows/") + || path.starts_with("src/v4/workflow/ci") + || path.starts_with("tools/ci_affected_components") + || path.starts_with("src/v3/compiler/src/v4_ci_runner_pool") + || path.starts_with("scripts/check-workflow-path-regex-inventory") + || path.starts_with("scripts/workflow-path-regex-forbidden-substrings") +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn v2_workspace_deps_without_src_v2() { + assert!(ci_changed_path_affects_v2("Cargo.lock")); + assert!(!ci_changed_path_affects_v3("Cargo.lock")); + assert!(ci_changed_path_affects_v4("Cargo.lock")); + } + + #[test] + fn v3_freeze_ignores_cargo_toml_for_v3_only() { + assert!(!ci_changed_path_affects_v3("Cargo.toml")); + assert!(ci_changed_path_affects_v3("src/v3/compiler/src/lib.rs")); + assert!(ci_changed_path_affects_v3("dsl/gunbc/ci.dag")); + assert!(ci_changed_path_affects_v3("dsl/std/node.dag")); + } + + #[test] + fn v4_m1_probe_script_triggers_v4_bucket() { + assert!(ci_changed_path_affects_v4( + "scripts/v4-m1-rust-emit-probe.sh" + )); + assert!(ci_changed_path_affects_v4("scripts/v4-mvp1-e2e-gate.sh")); + } + + #[test] + fn dsl_std_triggers_v3_and_v4() { + assert!(ci_changed_path_affects_v3("dsl/std/node.dag")); + assert!(ci_changed_path_affects_v4("dsl/std/node.dag")); + } + + #[test] + fn workflow_policy_includes_modeled_ci_authority() { + assert!(ci_changed_path_affects_workflow_policy( + "src/v4/workflow/ci.dag" + )); + assert!(ci_changed_path_affects_workflow_policy( + ".github/workflows/ci.yml" + )); + assert!(ci_changed_path_affects_workflow_policy( + "src/v3/compiler/src/v4_ci_runner_pool.rs" + )); + assert!(ci_changed_path_affects_workflow_policy( + "tools/ci_affected_components/src/lib.rs" + )); + } + + #[test] + fn aggregate_fixture_matches_shell_script_buckets() { + let flags = ci_component_affected_from_changed_paths([ + "src/v4/workflow/ci.dag", + "docs/unrelated.md", + ]); + assert!(!flags.v2); + assert!(!flags.v3); + assert!(flags.v4); + assert!(flags.workflow_policy); + } +} From fd00928632a7e906d0139284d52711cbe437ee29 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 06:36:35 +0000 Subject: [PATCH 41/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/ci.yml | 7 +- Cargo.toml | 1 + _internal/INVARIANTS_OPS.md | 4 +- src/v3/compiler/Cargo.toml | 4 - src/v3/compiler/src/lib.rs | 1 - .../compiler/src/v4_ci_component_affected.rs | 159 ------------------ .../tests/integration/sg0_census_test.rs | 2 - .../v4_workflow_ci_runner_dag_smoke_test.rs | 14 +- src/v4/workflow/ci.dag | 6 +- .../ci_affected_components/src/main.rs | 11 +- 10 files changed, 22 insertions(+), 187 deletions(-) delete mode 100644 src/v3/compiler/src/v4_ci_component_affected.rs rename src/v3/compiler/src/bin/detect_ci_affected_components.rs => tools/ci_affected_components/src/main.rs (92%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 42d54965d87..88e30adcfb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,8 +60,9 @@ jobs: - name: cargo fmt --all --check run: cargo fmt --all --check # Affected-set detection — drives gating of v2/v3/v4 jobs (path buckets modeled in - # `src/v4/workflow/ci.dag`; host transport `detect-ci-affected-components`). First - # run on a cold self-hosted runner compiles v3-compiler; subsequent steps gate on outputs. + # `src/v4/workflow/ci.dag`; host transport `detect-ci-affected-components` in + # `tools/ci_affected_components`, outside v3-compiler so v3=false can emit without + # compiling the frozen v3 package). First run on a cold runner compiles this tiny crate only. affected: if: github.event.pull_request.draft != true runs-on: [self-hosted, linux, arm64] @@ -94,7 +95,7 @@ jobs: run: git fetch origin main:refs/remotes/origin/main - name: Detect affected components id: detect - run: cargo run -p v3-compiler --bin detect-ci-affected-components -- "${{ github.event_name }}" "$GITHUB_OUTPUT" + run: cargo run -p ci_affected_components --bin detect-ci-affected-components -- "${{ github.event_name }}" "$GITHUB_OUTPUT" ci: if: github.event.pull_request.draft != true needs: [affected] diff --git a/Cargo.toml b/Cargo.toml index 130181bdfba..42a6f6594af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,7 @@ members = [ "src/v2/tests", "src/v3/compiler", "tools/gen_gunbc_ci_workflow_dag", + "tools/ci_affected_components", "src/v3/grounding_pilot", "src/v3/grounding_engine", "src/v3/grounding_lifetime", diff --git a/_internal/INVARIANTS_OPS.md b/_internal/INVARIANTS_OPS.md index 22eb5996a83..30902315240 100644 --- a/_internal/INVARIANTS_OPS.md +++ b/_internal/INVARIANTS_OPS.md @@ -79,7 +79,8 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED |------|---------| | `src/v3/compiler/benches/tier3_mirror_perf.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` — **Tier-3 perf-budget Phase-1** / T-Tier3-Dissolution (`docs/briefs/r3-pb-tier3-perf-budget-worker.md`; parent brief #1331). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when Tier3 host mirrors dissolve per `docs/r3-structure.md` §Acceptance (Criterion harness no longer targets hot Rust substrate entrypoints). **Interim ratchet:** frozen `tier3_baseline.json` + bench stays `--locked` clean under CI. | | `src/v3/compiler/build.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor`; **authority:** `dsl/gunbc/compiler.dag` **stage0** (`stage0.hand_maintained_src` / regen edges surfaced to Cargo). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** `build.rs` mirror retires when stage ordering + copy/hash contracts are enforced only via `.dag` emit programs (`SELF_HOSTING.md` §2). **Interim ratchet:** bootstrap snapshot + fmt/ci gates keep `build.rs` aligned with `compiler.dag`. | -| `src/v3/compiler/src/bin/detect_ci_affected_components.rs` | **TASKS.md** T-24 — host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (dissolves `scripts/detect-affected-components.sh`; path buckets single-authority in `src/v4/workflow/ci.dag`). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR as the bin. **Dissolution:** delete when affected-component projection runs from `.dag` eval / generated CI runner without this hand `main`. **Interim ratchet:** `v4_ci_component_affected` unit tests + `v4_workflow_ci_runner_dag_smoke_test` alignment with `ci.dag`. | +| `tools/ci_affected_components/src/lib.rs` | **TASKS.md** T-24 — Rust mirror of `ci_component_affected_from_git_diff` path buckets (`src/v4/workflow/ci.dag` is authority; must stay aligned per `ci.dag` workflow_policy predicates). Lives outside `v3-compiler` so the affected job can emit `v3=false` without compiling the frozen v3 package (INVARIANTS P3 fail-closed boundary). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (`docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row lands in the same PR as the crate. **Dissolution:** delete when `detect-ci-affected-components` invokes `.dag` eval over `ci.dag` predicates with no parallel Rust path logic. **Interim ratchet:** `ci_affected_components` unit tests + `v4_workflow_ci_runner_dag_smoke_test` alignment with `ci.dag`. | +| `tools/ci_affected_components/src/main.rs` | **TASKS.md** T-24 — host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff` (dissolves `scripts/detect-affected-components.sh`; path buckets single-authority in `src/v4/workflow/ci.dag`). Lives outside `v3-compiler` so affected-set gating does not require a successful v3 package build. **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (`docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row lands in the same PR as the bin. **Dissolution:** delete when affected-component projection runs from `.dag` eval / generated CI runner without this hand `main`. **Interim ratchet:** `ci_affected_components` unit tests + `v4_workflow_ci_runner_dag_smoke_test` alignment with `ci.dag`. | | `src/v3/compiler/src/bin/gunbc_ci.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** + **T-Workflow-As-Data** — `bin/gunbc_ci` host shim for modeled CI (`dsl/gunbc/ci.dag`). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when CI selection + receipts are emitted/invoked without a hand `main` (`SELF_HOSTING.md` §2.2). **Interim ratchet:** `gunbc_ci` integration tests + SG-0 census. | | `src/v3/compiler/src/bin/r1c_e_emit_gates.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / R1C-E emit gates (`docs/r3-program-plan.md` T-Emit `.dag` `TestClaim` lane). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit-gate checks are invoked only from generated/bootstrap harness without this bin. **Interim ratchet:** `r1c_e_gates.rs` shared checks + integration harness. | | `src/v3/compiler/src/bin/regen_bootstrap.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — regen **bootstrap** stage host entry (`dsl/gunbc/regen*.dag` family). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when bootstrap regen is a single declared pipeline command with no parallel Rust `main`. **Interim ratchet:** `regen_bootstrap_emit.rs` + bootstrap snapshot CI. | @@ -133,7 +134,6 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED | `src/v3/compiler/src/regen_tokenize.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — tokenizer regen emit host module. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit output is pipeline-only. **Interim ratchet:** tokenizer regen tests. | | `src/v3/compiler/src/self_host_receipt_p0.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / T-FixedPoint P0 — stable JSON receipt keys for `self_host_fixed_point` trends (DB-8 hand receipt). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when receipt schema is `.dag`/generated-owned. **Interim ratchet:** field-name unit tests in-module. | | `src/v3/compiler/src/test_runner.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / **T-PB-B** — integration test runner host (`ExecuteCommand` / claim evaluation seam). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when runner is generated or substrate-owned without hand orchestration. **Interim ratchet:** integration + cementing suites. | -| `src/v3/compiler/src/v4_ci_component_affected.rs` | **TASKS.md** T-24 — Rust mirror of `ci_component_affected_from_git_diff` path buckets (`src/v4/workflow/ci.dag` is authority; must stay aligned per `ci.dag` workflow_policy predicates). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when `detect-ci-affected-components` invokes `.dag` eval over `ci.dag` predicates with no parallel Rust path logic. **Interim ratchet:** `workflow_policy_paths_match_ci_dag_authority` unit test + integration smoke. | | `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_is_operator_constant` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | | `src/v3/compiler/src/v4_hollow_alias_gate.rs` | **TASKS.md** **T-30** (`src/v4/TASKS.md`); **Spec:** `docs/modeling-discipline.md` **Practice 8** — *Interim floor: the hollow-alias discriminator* (Practice 8 *Interim floor* on `main` post-#3226 `77b9e7d72` + Practice 9 #3234 `125fc88c8`; diff `main` if §8/§9 drift). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when T-30's structural `Node → Outcome` gate is generated from v4 `.dag` authority (no handwritten Practice-8 mirror). **Interim ratchet:** hermetic unit tests in-module pin the three-part hollow predicate + kernel-ambient exemption; paired **P2-staging** `.dag` nominal witness at `src/v4/std/fact_density.dag` (`SourceSpecReadFact` — **not** a landed substrate primitive per INVARIANTS §P2 until a generated consumer reads it; dissolution to `Node` payload when the v4-isolated bootstrap path lands; see file header + **PR review** (no maintained manifest). **T-30 enforcement mechanism:** structural `fact_density_hollow_alias_gate: Node -> Outcome>` is wired from `src/v4/lens/fact_density.dag` into the temporary compile-local `InferredTree -> Outcome>` adapter `fact_density_hollow_alias_compile_gate` and `CompileLens` row `fact_density_lens` in `src/v4/compiler/00_compile.dag`, and `validate_then_compile` applies required gates with `run_required_lens_gates_on_subtree` across the inferred root and every child node (compiles via v4 bootstrap gate; P2 consumer-gated); six `.dag` TestClaims in `src/v4/test/claim/lens_fact_density/` — `hollow_alias_compile_lens_rejects`, `fact_bundle_compile_lens_passes`, `hollow_alias_blocked_in_run_gates`, `hollow_alias_blocked_via_always_required_lenses`, `hollow_alias_vtc_empty_lenses_rejected`, `hollow_alias_nested_rejected` — scaffold the gate through `apply_compile_lens` / `run_required_lens_gates` / `always_required_lenses()` / `validate_then_compile` with empty caller-lenses and nested hollow-alias rejection (compile-only until T-22 execution). | | `src/v3/compiler/src/wall_clock_ratchet_manifest.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — wall-clock warn manifest for CI/binary shims (timing discipline). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when timing manifest is `.dag` data consumed by codegen. **Interim ratchet:** modeled CI workflow tests. | diff --git a/src/v3/compiler/Cargo.toml b/src/v3/compiler/Cargo.toml index fe72eb7f89f..bf5a8cbaab3 100644 --- a/src/v3/compiler/Cargo.toml +++ b/src/v3/compiler/Cargo.toml @@ -93,7 +93,3 @@ path = "src/bin/r1c_e_emit_gates.rs" [[bin]] name = "gunbc-ci" path = "src/bin/gunbc_ci.rs" - -[[bin]] -name = "detect-ci-affected-components" -path = "src/bin/detect_ci_affected_components.rs" diff --git a/src/v3/compiler/src/lib.rs b/src/v3/compiler/src/lib.rs index d8006102634..14d57ca9d12 100644 --- a/src/v3/compiler/src/lib.rs +++ b/src/v3/compiler/src/lib.rs @@ -4101,7 +4101,6 @@ pub mod gunbc_ci; pub mod post_emit_verifier; pub mod r1c_e_gates; pub mod test_runner; -pub mod v4_ci_component_affected; pub mod v4_ci_runner_pool; pub mod wall_clock_ratchet_manifest; pub mod serialize { diff --git a/src/v3/compiler/src/v4_ci_component_affected.rs b/src/v3/compiler/src/v4_ci_component_affected.rs deleted file mode 100644 index 61bfa79f064..00000000000 --- a/src/v3/compiler/src/v4_ci_component_affected.rs +++ /dev/null @@ -1,159 +0,0 @@ -//! v4 `workflow/ci.dag` component affected-set — host transport for GitHub Actions. -//! -//! **Modeled authority:** `src/v4/workflow/ci.dag` (`ci_component_affected_from_git_diff` and -//! `ci_changed_path_affects_*`). This module is an interim Rust mirror of those predicates for -//! the CI runner (not `.dag` eval yet); keep aligned via `workflow_policy_paths_match_ci_dag_authority` -//! and `v4_workflow_ci_runner_dag_smoke_test` prefix parity. Do not add path buckets to workflow YAML. - -/// Structural mirror of `CiComponentAffected` in `src/v4/workflow/ci.dag`. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub struct CiComponentAffected { - pub v2: bool, - pub v3: bool, - pub v4: bool, - pub workflow_policy: bool, -} - -/// Mirror of `ci_component_affected_fail_closed` — all components affected (INVARIANTS P3). -pub fn ci_component_affected_fail_closed() -> CiComponentAffected { - CiComponentAffected { - v2: true, - v3: true, - v4: true, - workflow_policy: true, - } -} - -/// Map `git diff --name-only` paths to component flags (same semantics as `ci.dag`). -pub fn ci_component_affected_from_changed_paths<'a, I>(changed: I) -> CiComponentAffected -where - I: IntoIterator, -{ - let mut out = CiComponentAffected { - v2: false, - v3: false, - v4: false, - workflow_policy: false, - }; - for path in changed { - if ci_changed_path_affects_v2(path) { - out.v2 = true; - } - if ci_changed_path_affects_v3(path) { - out.v3 = true; - } - if ci_changed_path_affects_v4(path) { - out.v4 = true; - } - if ci_changed_path_affects_workflow_policy(path) { - out.workflow_policy = true; - } - } - out -} - -pub fn ci_changed_path_affects_v2(path: &str) -> bool { - path.starts_with("src/v2/") || path == "Cargo.toml" || path == "Cargo.lock" -} - -pub fn ci_changed_path_affects_v3(path: &str) -> bool { - path.starts_with("src/v3/") || path.starts_with("dsl/") -} - -pub fn ci_changed_path_affects_v4(path: &str) -> bool { - path.starts_with("src/v4/") - || path.starts_with("fixtures/v4-mvp1/") - || path == "scripts/v4-mvp1-e2e-gate.sh" - || path == "scripts/v4-m1-rust-emit-probe.sh" - || path.starts_with("scripts/v4-mvp1") - || path.starts_with("scripts/v4-m1") - || path.starts_with("scripts/v4-testclaim-") - || path.starts_with("dsl/std/") - || path == "Cargo.toml" - || path == "Cargo.lock" -} - -pub fn ci_changed_path_affects_workflow_policy(path: &str) -> bool { - path.starts_with(".github/workflows/") - || path.starts_with("src/v4/workflow/ci") - || path.starts_with("src/v3/compiler/src/v4_ci_component_affected") - || path.starts_with("src/v3/compiler/src/v4_ci_runner_pool") - || path.starts_with("src/v3/compiler/src/bin/detect_ci_affected_components") - || path.starts_with("scripts/check-workflow-path-regex-inventory") - || path.starts_with("scripts/workflow-path-regex-forbidden-substrings") -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn v2_workspace_deps_without_src_v2() { - assert!(ci_changed_path_affects_v2("Cargo.lock")); - assert!(!ci_changed_path_affects_v3("Cargo.lock")); - assert!(ci_changed_path_affects_v4("Cargo.lock")); - } - - #[test] - fn v3_freeze_ignores_cargo_toml_for_v3_only() { - assert!(!ci_changed_path_affects_v3("Cargo.toml")); - assert!(ci_changed_path_affects_v3("src/v3/compiler/src/lib.rs")); - assert!(ci_changed_path_affects_v3("dsl/gunbc/ci.dag")); - assert!(ci_changed_path_affects_v3("dsl/std/node.dag")); - } - - #[test] - fn v4_m1_probe_script_triggers_v4_bucket() { - assert!(ci_changed_path_affects_v4( - "scripts/v4-m1-rust-emit-probe.sh" - )); - assert!(ci_changed_path_affects_v4("scripts/v4-mvp1-e2e-gate.sh")); - } - - #[test] - fn dsl_std_triggers_v3_and_v4() { - assert!(ci_changed_path_affects_v3("dsl/std/node.dag")); - assert!(ci_changed_path_affects_v4("dsl/std/node.dag")); - } - - #[test] - fn workflow_policy_includes_modeled_ci_authority() { - assert!(ci_changed_path_affects_workflow_policy( - "src/v4/workflow/ci.dag" - )); - assert!(ci_changed_path_affects_workflow_policy( - ".github/workflows/ci.yml" - )); - assert!(ci_changed_path_affects_workflow_policy( - "src/v3/compiler/src/v4_ci_runner_pool.rs" - )); - } - - #[test] - fn workflow_policy_sample_paths_are_in_workflow_policy_bucket() { - assert!(ci_changed_path_affects_workflow_policy( - "src/v4/workflow/ci.dag" - )); - assert!(ci_changed_path_affects_workflow_policy( - "src/v3/compiler/src/v4_ci_runner_pool.rs" - )); - assert!(ci_changed_path_affects_workflow_policy( - "src/v3/compiler/src/v4_ci_component_affected.rs" - )); - assert!(ci_changed_path_affects_workflow_policy( - "src/v3/compiler/src/bin/detect_ci_affected_components.rs" - )); - } - - #[test] - fn aggregate_fixture_matches_shell_script_buckets() { - let flags = ci_component_affected_from_changed_paths([ - "src/v4/workflow/ci.dag", - "docs/unrelated.md", - ]); - assert!(!flags.v2); - assert!(!flags.v3); - assert!(flags.v4); - assert!(flags.workflow_policy); - } -} diff --git a/src/v3/compiler/tests/integration/sg0_census_test.rs b/src/v3/compiler/tests/integration/sg0_census_test.rs index 62783203e97..615160b14f1 100644 --- a/src/v3/compiler/tests/integration/sg0_census_test.rs +++ b/src/v3/compiler/tests/integration/sg0_census_test.rs @@ -276,7 +276,6 @@ const EXPECTED_HAND_AUTHORED_NON_TEST: &[&str] = &[ // survives. "src/v3/compiler/benches/tier3_mirror_perf.rs", "src/v3/compiler/build.rs", - "src/v3/compiler/src/bin/detect_ci_affected_components.rs", "src/v3/compiler/src/bin/gunbc_ci.rs", "src/v3/compiler/src/bin/r1c_e_emit_gates.rs", "src/v3/compiler/src/bin/regen_bootstrap.rs", @@ -357,7 +356,6 @@ const EXPECTED_HAND_AUTHORED_NON_TEST: &[&str] = &[ "src/v3/compiler/src/regen_tokenize.rs", "src/v3/compiler/src/self_host_receipt_p0.rs", "src/v3/compiler/src/test_runner.rs", - "src/v3/compiler/src/v4_ci_component_affected.rs", "src/v3/compiler/src/v4_ci_runner_pool.rs", "src/v3/compiler/src/v4_hollow_alias_gate.rs", "src/v3/compiler/src/wall_clock_ratchet_manifest.rs", diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 982c1263e3a..13e1b55959d 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -27,15 +27,15 @@ const M1_BINDING_TEST_FILTER: &str = const CLAIM_DAG: &str = include_str!("../../../../v4/test/claim/workflow/affected_set_ci_runner.dag"); const CLAIM_PATH: &str = "src/v4/test/claim/workflow/affected_set_ci_runner.dag"; -const V4_CI_COMPONENT_AFFECTED_RS: &str = include_str!("../../src/v4_ci_component_affected.rs"); +const CI_AFFECTED_COMPONENTS_LIB: &str = + include_str!("../../../../../tools/ci_affected_components/src/lib.rs"); /// Single-authority workflow_policy path buckets (`ci.dag` predicates ↔ Rust host mirror). const CI_WORKFLOW_POLICY_PREFIXES: &[&str] = &[ ".github/workflows/", "src/v4/workflow/ci", - "src/v3/compiler/src/v4_ci_component_affected", + "tools/ci_affected_components", "src/v3/compiler/src/v4_ci_runner_pool", - "src/v3/compiler/src/bin/detect_ci_affected_components", "scripts/check-workflow-path-regex-inventory", "scripts/workflow-path-regex-forbidden-substrings", ]; @@ -65,8 +65,8 @@ fn assert_ci_dag_rust_prefix_parity(prefixes: &[&str]) { "{CI_DAG_PATH}: authority must declare prefix `{prefix}`" ); assert!( - V4_CI_COMPONENT_AFFECTED_RS.contains(&format!("\"{prefix}\"")), - "v4_ci_component_affected.rs mirror must declare prefix `{prefix}`" + CI_AFFECTED_COMPONENTS_LIB.contains(&format!("\"{prefix}\"")), + "ci_affected_components lib mirror must declare prefix `{prefix}`" ); } } @@ -78,8 +78,8 @@ fn assert_ci_dag_rust_exact_path_parity(paths: &[&str]) { "{CI_DAG_PATH}: authority must declare exact path `{path}`" ); assert!( - V4_CI_COMPONENT_AFFECTED_RS.contains(&format!("\"{path}\"")), - "v4_ci_component_affected.rs mirror must declare exact path `{path}`" + CI_AFFECTED_COMPONENTS_LIB.contains(&format!("\"{path}\"")), + "ci_affected_components lib mirror must declare exact path `{path}`" ); } } diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 99cd8dede56..5c37dcaa1d0 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -103,7 +103,7 @@ type CiPipeline { // RULING-1: 🟢 pretty-much-done — GitHub Actions `affected` job outputs (v2/v3/v4/workflow_policy). // Structural replacement for scripts/detect-affected-components.sh (T-21/T-24); host transport: -// `cargo run -p v3-compiler --bin detect-ci-affected-components` (must stay aligned with these predicates). +// `cargo run -p ci_affected_components --bin detect-ci-affected-components` (must stay aligned with these predicates). type CiComponentAffected { v2: Bool v3: Bool @@ -118,6 +118,7 @@ type CiComponentAffected { // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. // Fleet arch is a closed operator fact (Arm64 only) — modeled in comments, not a sum type, so Lens-CI // entry compile of this module does not need a coproduct the isolated v4 compiler cannot resolve. +// 🟡 gated — feature:formatter-int-refinement — bind T-25-core — dissolve-on-arrival: replace annotated Int fields with Refined via T-25-core refine substrate; each field's ≥1 annotation becomes the validation predicate; forbidden: UInt/Nat for config literals (Peano representation makes integer data nodes impractical). type SelfHostedRunnerPool { host: Symbol core_count: Int // 🟡 gated: formatter-int-refinement — must be ≥1 (operator fleet spec) @@ -673,9 +674,8 @@ fn ci_changed_path_affects_v4(changed: RepoPath) -> Bool { fn ci_changed_path_affects_workflow_policy(changed: RepoPath) -> Bool { ci_repo_path_has_prefix(path: changed, prefix: ".github/workflows/") || ci_repo_path_has_prefix(path: changed, prefix: "src/v4/workflow/ci") - || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/v4_ci_component_affected") + || ci_repo_path_has_prefix(path: changed, prefix: "tools/ci_affected_components") || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/v4_ci_runner_pool") - || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/bin/detect_ci_affected_components") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/check-workflow-path-regex-inventory") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/workflow-path-regex-forbidden-substrings") } diff --git a/src/v3/compiler/src/bin/detect_ci_affected_components.rs b/tools/ci_affected_components/src/main.rs similarity index 92% rename from src/v3/compiler/src/bin/detect_ci_affected_components.rs rename to tools/ci_affected_components/src/main.rs index a0f9b5b9603..a88a80d8c81 100644 --- a/src/v3/compiler/src/bin/detect_ci_affected_components.rs +++ b/tools/ci_affected_components/src/main.rs @@ -1,14 +1,16 @@ // Host transport for `v4.workflow.ci` `ci_component_affected_from_git_diff_read` (T-24). // Replaces scripts/detect-affected-components.sh. Modeled authority is `src/v4/workflow/ci.dag`; -// this bin executes the Rust mirror in `v4_ci_component_affected` (parity-ratcheted to ci.dag). +// this bin executes the Rust mirror in `ci_affected_components` (parity-ratcheted to ci.dag). +// Crate lives outside v3-compiler so affected-set gating does not require compiling v3 first. #![allow(clippy::disallowed_macros)] use std::io::Write; use std::process::{Command, ExitCode}; use std::{env, fs, io}; -use v3_compiler::v4_ci_component_affected::{ +use ci_affected_components::{ ci_component_affected_fail_closed, ci_component_affected_from_changed_paths, + CiComponentAffected, }; fn usage() -> ! { @@ -59,10 +61,7 @@ fn git_read_changed_paths(range: &str) -> GitDiffRead { } } -fn write_github_output( - path: &str, - flags: v3_compiler::v4_ci_component_affected::CiComponentAffected, -) -> io::Result<()> { +fn write_github_output(path: &str, flags: CiComponentAffected) -> io::Result<()> { let mut file = fs::OpenOptions::new().append(true).open(path)?; writeln!(file, "v2={}", flags.v2)?; writeln!(file, "v3={}", flags.v3)?; From 01d5ae84e814acb3f5eb7af3a3d3dffd86dedfe4 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 06:38:00 +0000 Subject: [PATCH 42/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 4 ++++ dsl/gunbc/ci_github_actions_workflow.dag | 2 +- scripts/ci-merge/sg0-pr-body-append.3853.txt | 2 +- src/v4/test/claim/workflow/ci_component_affected.dag | 2 +- 4 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1843c4041ad..728a654ed63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -122,6 +122,10 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "ci_affected_components" +version = "0.1.0" + [[package]] name = "ciborium" version = "0.2.2" diff --git a/dsl/gunbc/ci_github_actions_workflow.dag b/dsl/gunbc/ci_github_actions_workflow.dag index 3ca00fc8629..bd07fdbb1cb 100644 --- a/dsl/gunbc/ci_github_actions_workflow.dag +++ b/dsl/gunbc/ci_github_actions_workflow.dag @@ -161,7 +161,7 @@ data gunbc_ci_github_actions_workflow: Workflow = { }, RunStep { name: Some { value: "Detect affected components" }, id: Some { value: "detect" }, - run: "cargo run -p v3-compiler --bin detect-ci-affected-components -- \"${{ github.event_name }}\" \"$GITHUB_OUTPUT\"", + run: "cargo run -p ci_affected_components --bin detect-ci-affected-components -- \"${{ github.event_name }}\" \"$GITHUB_OUTPUT\"", shell: Bash, env: none, working_directory: none, diff --git a/scripts/ci-merge/sg0-pr-body-append.3853.txt b/scripts/ci-merge/sg0-pr-body-append.3853.txt index 981ca9e5a7a..1d48012b6d8 100644 --- a/scripts/ci-merge/sg0-pr-body-append.3853.txt +++ b/scripts/ci-merge/sg0-pr-body-append.3853.txt @@ -1,3 +1,3 @@ SG-0 hand-path delta: +3 -SG-0 pairing: (c) Net +3 on `EXPECTED_HAND_AUTHORED_NON_TEST` (T-PB-A / `pb_hand_rust_at_shim_floor` non-test census per `ROADMAP.md:179`) for T-24 host-transport shims (`detect_ci_affected_components.rs`, `v4_ci_component_affected.rs`, `v4_ci_runner_pool.rs`) with matching INVARIANTS §P5(b) rows. Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). +SG-0 pairing: (c) Net +1 on `EXPECTED_HAND_AUTHORED_NON_TEST` (T-PB-A / `pb_hand_rust_at_shim_floor` non-test census per `ROADMAP.md:179`) for T-24 host-transport shim `v4_ci_runner_pool.rs` with matching INVARIANTS §P5(b) row. Affected-set mirror + bin live in `tools/ci_affected_components` (outside v3-compiler SG-0 census; INVARIANTS §P5(b) rows for lib + main). Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). diff --git a/src/v4/test/claim/workflow/ci_component_affected.dag b/src/v4/test/claim/workflow/ci_component_affected.dag index 0922b00c298..fe251064317 100644 --- a/src/v4/test/claim/workflow/ci_component_affected.dag +++ b/src/v4/test/claim/workflow/ci_component_affected.dag @@ -1,6 +1,6 @@ // src/v4/test/claim/workflow/ci_component_affected.dag // Scope: T-24 receipt — git diff path buckets → CiComponentAffected flags (dissolves detect-affected-components.sh). -// Status: structural claims; host transport is `detect-ci-affected-components` (v3-compiler bin). +// Status: structural claims; host transport is `detect-ci-affected-components` (`tools/ci_affected_components` bin). module v4.test.claim.workflow.ci_component_affected From 86399c5000c1591e128d1a4353d719e04805a181 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 06:45:29 +0000 Subject: [PATCH 43/56] fix: correct SG-0 hand-path delta to +1 for T-24 census net MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Append file declared +3 while origin/main…HEAD census diff is net +1 (v4_ci_runner_pool.rs only); unblocks ci job SG-0 net-shrink check. Co-authored-by: Cursor --- scripts/ci-merge/sg0-pr-body-append.3853.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/ci-merge/sg0-pr-body-append.3853.txt b/scripts/ci-merge/sg0-pr-body-append.3853.txt index 1d48012b6d8..feed9863da7 100644 --- a/scripts/ci-merge/sg0-pr-body-append.3853.txt +++ b/scripts/ci-merge/sg0-pr-body-append.3853.txt @@ -1,3 +1,3 @@ -SG-0 hand-path delta: +3 +SG-0 hand-path delta: +1 SG-0 pairing: (c) Net +1 on `EXPECTED_HAND_AUTHORED_NON_TEST` (T-PB-A / `pb_hand_rust_at_shim_floor` non-test census per `ROADMAP.md:179`) for T-24 host-transport shim `v4_ci_runner_pool.rs` with matching INVARIANTS §P5(b) row. Affected-set mirror + bin live in `tools/ci_affected_components` (outside v3-compiler SG-0 census; INVARIANTS §P5(b) rows for lib + main). Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). From 4a9193a1d0e31a5284ce29275b640b8156f0fac4 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 07:40:16 +0000 Subject: [PATCH 44/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v3/compiler/src/v4_ci_runner_pool.rs | 8 +++++++- .../v4_workflow_ci_runner_dag_smoke_test.rs | 12 ++++++++---- src/v4/test/claim/workflow/runner_pool_m1_probe.dag | 6 ++++++ src/v4/workflow/ci.dag | 11 ++++++++--- 4 files changed, 29 insertions(+), 8 deletions(-) diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/src/v3/compiler/src/v4_ci_runner_pool.rs index e5b8c78a9f0..a2f3f186589 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/src/v3/compiler/src/v4_ci_runner_pool.rs @@ -1,17 +1,20 @@ //! Structural mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. -//! Operator fleet is Ampere Altra (Arm64) only — arch is a comment-level closed fact in `ci.dag`, not a field. /// Structural mirror of `SelfHostedRunnerPool` in `src/v4/workflow/ci.dag`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct SelfHostedRunnerPool { pub host: &'static str, + pub arch: &'static str, pub core_count: u32, pub runner_count: u32, pub jobserver_token_cap: u32, } +pub const CI_RUNNER_ARCH_ARM64: &str = "arm64"; + pub const CI_SRV1_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { host: "srv1", + arch: CI_RUNNER_ARCH_ARM64, core_count: 128, runner_count: 20, jobserver_token_cap: 25, @@ -19,6 +22,7 @@ pub const CI_SRV1_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { pub const CI_SRV2_POOL: SelfHostedRunnerPool = SelfHostedRunnerPool { host: "srv2", + arch: CI_RUNNER_ARCH_ARM64, core_count: 128, runner_count: 30, jobserver_token_cap: 36, @@ -56,6 +60,8 @@ mod tests { #[test] fn srv_pools_match_operator_spec() { + assert_eq!(CI_SRV1_POOL.arch, CI_RUNNER_ARCH_ARM64); + assert_eq!(CI_SRV2_POOL.arch, CI_RUNNER_ARCH_ARM64); assert_eq!(CI_SRV1_POOL.runner_count, 20); assert_eq!(CI_SRV1_POOL.jobserver_token_cap, 25); assert_eq!(CI_SRV2_POOL.runner_count, 30); diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 13e1b55959d..d42565449ea 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -404,10 +404,14 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { CI_DAG.contains("type SelfHostedRunnerPool"), "{CI_DAG_PATH}: must model self-hosted runner pools (T-24 addendum)" ); - assert!( - !CI_DAG.contains("RunnerArch"), - "{CI_DAG_PATH}: fleet Arm64 is a comment-level closed fact — no RunnerArch coproduct in Lens-CI entry compile" - ); + assert!( + CI_DAG.contains("arch: ci_runner_arch_arm64"), + "{CI_DAG_PATH}: fleet arch must be a typed Symbol field on SelfHostedRunnerPool" + ); + assert!( + !CI_DAG.contains("RunnerArch"), + "{CI_DAG_PATH}: fleet arch uses Symbol field — no RunnerArch coproduct in Lens-CI entry compile" + ); assert!( CI_DAG.contains("data ci_srv1_pool: SelfHostedRunnerPool") && CI_DAG.contains("runner_count: 20") diff --git a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag index 848d5496d61..0e102ed9d2f 100644 --- a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag +++ b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag @@ -5,11 +5,16 @@ module v4.test.claim.workflow.runner_pool_m1_probe import v4.std.logic { Bool } import v4.workflow.ci { + ci_runner_arch_arm64, ci_srv1_pool, ci_srv2_pool, m1_probe_cargo_check_jobs } +fn runner_pool_fleet_arch_holds() -> Bool { + ci_srv1_pool.arch == ci_runner_arch_arm64 && ci_srv2_pool.arch == ci_runner_arch_arm64 +} + fn runner_pool_srv1_runner_count_holds() -> Bool { ci_srv1_pool.runner_count == 20 } @@ -22,6 +27,7 @@ fn runner_pool_m1_cargo_jobs_holds() -> Bool { m1_probe_cargo_check_jobs == 4 } +data runner_pool_arch_claim_passes: Bool = runner_pool_fleet_arch_holds() data runner_pool_srv1_claim_passes: Bool = runner_pool_srv1_runner_count_holds() data runner_pool_srv2_claim_passes: Bool = runner_pool_srv2_jobserver_cap_holds() data runner_pool_m1_jobs_claim_passes: Bool = runner_pool_m1_cargo_jobs_holds() diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 5c37dcaa1d0..19b6c03a159 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -1,5 +1,7 @@ // src/v4/workflow/ci.dag -// Scope: CI pipeline AS DATA; gunbc job/gate DAG + eager well-formedness; Wave-0 TestClaim roster selection; YamlStatic workflow projection deferred (full `ci_pipeline` → `.github/workflows/ci.yml` lands with T-24 emission slice). +// Scope: CI pipeline AS DATA; gunbc job/gate DAG + eager well-formedness; Wave-0 TestClaim roster selection. +// Wave-0 partial close (this PR): T-21/T-24 affected-set authority, detect-affected-components.sh dissolution, runner-pool/M1 facts modeled. +// T-24 CI/YAML authority bridge (emitter wired, hand-authored ci.yml deleted) remains open per src/v4/TASKS.md §T-24 — interim hand ci.yml edits are transport wiring only, not YAML-authority dissolution. // Status: filled — declarative core + eager well-formedness + T-21/T-24 component affected-set (dissolves scripts/detect-affected-components.sh via `ci_component_affected_from_git_diff` + `detect-ci-affected-components` host transport) + T-21/T-24 TestClaim roster selection + T-38 dissolution step declared (TestClaimCorpusEvalCommand job/gate/cache-digest; IRT-1 call site — ci_select_from_affected_set narrows roster to content_hash frontier — lands with dissolution PR that replaces scripts/v4-testclaim-corpus-gate.sh). module v4.workflow.ci @@ -116,11 +118,11 @@ type CiComponentAffected { // Uses canonical `Outcome` from std.diagnostic (Practice 10 — no parallel read carrier). // RULING-1: 🟢 pretty-much-done — self-hosted fleet substrate (operator 2026-05-28: srv1/srv2 Ampere Altra / Arm64). // Consumed by YamlStatic workflow projection and M1 rust-emit probe cargo parallelism cap. -// Fleet arch is a closed operator fact (Arm64 only) — modeled in comments, not a sum type, so Lens-CI -// entry compile of this module does not need a coproduct the isolated v4 compiler cannot resolve. +// Fleet arch is a closed operator fact as `arch: Symbol` (not a sum type — avoids Lens-CI coproduct resolution). // 🟡 gated — feature:formatter-int-refinement — bind T-25-core — dissolve-on-arrival: replace annotated Int fields with Refined via T-25-core refine substrate; each field's ≥1 annotation becomes the validation predicate; forbidden: UInt/Nat for config literals (Peano representation makes integer data nodes impractical). type SelfHostedRunnerPool { host: Symbol + arch: Symbol core_count: Int // 🟡 gated: formatter-int-refinement — must be ≥1 (operator fleet spec) runner_count: Int // 🟡 gated: formatter-int-refinement — must be ≥1 jobserver_token_cap: Int // 🟡 gated: formatter-int-refinement — must be ≥1 @@ -154,9 +156,11 @@ data m1_rust_emit_probe_signal: Symbol = m1_rust_emit_probe_signal data testclaim_corpus_eval_signal: Symbol = testclaim_corpus_eval_signal data ci_srv1_host: Symbol = ci_srv1_host data ci_srv2_host: Symbol = ci_srv2_host +data ci_runner_arch_arm64: Symbol = ci_runner_arch_arm64 data ci_srv1_pool: SelfHostedRunnerPool = { host: ci_srv1_host + arch: ci_runner_arch_arm64 core_count: 128 runner_count: 20 jobserver_token_cap: 25 @@ -164,6 +168,7 @@ data ci_srv1_pool: SelfHostedRunnerPool = { data ci_srv2_pool: SelfHostedRunnerPool = { host: ci_srv2_host + arch: ci_runner_arch_arm64 core_count: 128 runner_count: 30 jobserver_token_cap: 36 From 8bf1694953e8febe9e13c3eacfc14df129d3165c Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 07:42:59 +0000 Subject: [PATCH 45/56] chore: apply cargo fmt after SelfHostedRunnerPool arch field Unblocks fmt CI on openai-pro arch:Symbol + Wave-0 scope header fix. Co-authored-by: Cursor --- .../v4_workflow_ci_runner_dag_smoke_test.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index d42565449ea..2cfb9a1ae3b 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -404,11 +404,11 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { CI_DAG.contains("type SelfHostedRunnerPool"), "{CI_DAG_PATH}: must model self-hosted runner pools (T-24 addendum)" ); - assert!( - CI_DAG.contains("arch: ci_runner_arch_arm64"), - "{CI_DAG_PATH}: fleet arch must be a typed Symbol field on SelfHostedRunnerPool" - ); - assert!( + assert!( + CI_DAG.contains("arch: ci_runner_arch_arm64"), + "{CI_DAG_PATH}: fleet arch must be a typed Symbol field on SelfHostedRunnerPool" + ); + assert!( !CI_DAG.contains("RunnerArch"), "{CI_DAG_PATH}: fleet arch uses Symbol field — no RunnerArch coproduct in Lens-CI entry compile" ); From 5f28e081f821e764fbf8686b5c00dac39f2108cf Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 07:57:58 +0000 Subject: [PATCH 46/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _internal/INVARIANTS_OPS.md | 2 +- scripts/ci-merge/sg0-pr-body-append.3853.txt | 4 ++-- src/v3/compiler/Cargo.toml | 1 + src/v3/compiler/src/lib.rs | 1 - src/v3/compiler/tests/integration/sg0_census_test.rs | 1 - .../integration/v4_workflow_ci_runner_dag_smoke_test.rs | 9 ++++++++- src/v4/workflow/ci.dag | 1 - tools/ci_affected_components/src/lib.rs | 8 ++------ .../ci_affected_components/src/runner_pool.rs | 1 + 9 files changed, 15 insertions(+), 13 deletions(-) rename src/v3/compiler/src/v4_ci_runner_pool.rs => tools/ci_affected_components/src/runner_pool.rs (96%) diff --git a/_internal/INVARIANTS_OPS.md b/_internal/INVARIANTS_OPS.md index 30902315240..e93aedca40e 100644 --- a/_internal/INVARIANTS_OPS.md +++ b/_internal/INVARIANTS_OPS.md @@ -134,7 +134,7 @@ Per **Dispatch-Discipline Mechanisms (b)**, each path in `EXPECTED_HAND_AUTHORED | `src/v3/compiler/src/regen_tokenize.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — tokenizer regen emit host module. **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when emit output is pipeline-only. **Interim ratchet:** tokenizer regen tests. | | `src/v3/compiler/src/self_host_receipt_p0.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / T-FixedPoint P0 — stable JSON receipt keys for `self_host_fixed_point` trends (DB-8 hand receipt). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when receipt schema is `.dag`/generated-owned. **Interim ratchet:** field-name unit tests in-module. | | `src/v3/compiler/src/test_runner.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** / **T-PB-B** — integration test runner host (`ExecuteCommand` / claim evaluation seam). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when runner is generated or substrate-owned without hand orchestration. **Interim ratchet:** integration + cementing suites. | -| `src/v3/compiler/src/v4_ci_runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `m1_probe_cargo_check_jobs_is_operator_constant` + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | +| `tools/ci_affected_components/src/runner_pool.rs` | **TASKS.md** T-24 — Rust mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` (`src/v4/workflow/ci.dag` srv1/srv2 operator spec). Lives outside `v3-compiler` with affected-set transport. **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (`docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row lands in the same PR as the module. **Dissolution:** delete when M1 cargo parallelism and runner fleet facts project from `.dag` only. **Interim ratchet:** `runner_pool` unit tests + `v4_workflow_ci_runner_dag_smoke_test` `V4_M1_CARGO_CHECK_JOBS` binding. | | `src/v3/compiler/src/v4_hollow_alias_gate.rs` | **TASKS.md** **T-30** (`src/v4/TASKS.md`); **Spec:** `docs/modeling-discipline.md` **Practice 8** — *Interim floor: the hollow-alias discriminator* (Practice 8 *Interim floor* on `main` post-#3226 `77b9e7d72` + Practice 9 #3234 `125fc88c8`; diff `main` if §8/§9 drift). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** — **T-PB-A** / `pb_hand_rust_at_shim_floor` (SG-0 non-test census in `sg0_census_test.rs`; `docs/design-pure-bootstrap-zero.md`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_NON_TEST` literal land in the same PR. **Dissolution:** delete when T-30's structural `Node → Outcome` gate is generated from v4 `.dag` authority (no handwritten Practice-8 mirror). **Interim ratchet:** hermetic unit tests in-module pin the three-part hollow predicate + kernel-ambient exemption; paired **P2-staging** `.dag` nominal witness at `src/v4/std/fact_density.dag` (`SourceSpecReadFact` — **not** a landed substrate primitive per INVARIANTS §P2 until a generated consumer reads it; dissolution to `Node` payload when the v4-isolated bootstrap path lands; see file header + **PR review** (no maintained manifest). **T-30 enforcement mechanism:** structural `fact_density_hollow_alias_gate: Node -> Outcome>` is wired from `src/v4/lens/fact_density.dag` into the temporary compile-local `InferredTree -> Outcome>` adapter `fact_density_hollow_alias_compile_gate` and `CompileLens` row `fact_density_lens` in `src/v4/compiler/00_compile.dag`, and `validate_then_compile` applies required gates with `run_required_lens_gates_on_subtree` across the inferred root and every child node (compiles via v4 bootstrap gate; P2 consumer-gated); six `.dag` TestClaims in `src/v4/test/claim/lens_fact_density/` — `hollow_alias_compile_lens_rejects`, `fact_bundle_compile_lens_passes`, `hollow_alias_blocked_in_run_gates`, `hollow_alias_blocked_via_always_required_lenses`, `hollow_alias_vtc_empty_lenses_rejected`, `hollow_alias_nested_rejected` — scaffold the gate through `apply_compile_lens` / `run_required_lens_gates` / `always_required_lenses()` / `validate_then_compile` with empty caller-lenses and nested hollow-alias rejection (compile-only until T-22 execution). | | `src/v3/compiler/src/wall_clock_ratchet_manifest.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **T-PB-A** — wall-clock warn manifest for CI/binary shims (timing discipline). **PR receipt (P5 Mechanism (b)):** this row + census line same PR. **Dissolution:** delete when timing manifest is `.dag` data consumed by codegen. **Interim ratchet:** modeled CI workflow tests. | --- diff --git a/scripts/ci-merge/sg0-pr-body-append.3853.txt b/scripts/ci-merge/sg0-pr-body-append.3853.txt index feed9863da7..bdba3018827 100644 --- a/scripts/ci-merge/sg0-pr-body-append.3853.txt +++ b/scripts/ci-merge/sg0-pr-body-append.3853.txt @@ -1,3 +1,3 @@ -SG-0 hand-path delta: +1 +SG-0 hand-path delta: +0 -SG-0 pairing: (c) Net +1 on `EXPECTED_HAND_AUTHORED_NON_TEST` (T-PB-A / `pb_hand_rust_at_shim_floor` non-test census per `ROADMAP.md:179`) for T-24 host-transport shim `v4_ci_runner_pool.rs` with matching INVARIANTS §P5(b) row. Affected-set mirror + bin live in `tools/ci_affected_components` (outside v3-compiler SG-0 census; INVARIANTS §P5(b) rows for lib + main). Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). +SG-0 pairing: (c) Net +0 on `EXPECTED_HAND_AUTHORED_NON_TEST` — T-24 interim Rust mirrors (`tools/ci_affected_components` lib/main/runner_pool) live outside v3-compiler SG-0 census with INVARIANTS §P5(b) rows. Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). diff --git a/src/v3/compiler/Cargo.toml b/src/v3/compiler/Cargo.toml index bf5a8cbaab3..d5513f23e2b 100644 --- a/src/v3/compiler/Cargo.toml +++ b/src/v3/compiler/Cargo.toml @@ -45,6 +45,7 @@ libc = { version = "0.2", default-features = false } # `docs/briefs/r3-pb-tier3-perf-budget-worker.md` deliverable 0a/0b. criterion = "0.5" gen_gunbc_ci_workflow_dag = { path = "../../../tools/gen_gunbc_ci_workflow_dag" } +ci_affected_components = { path = "../../../tools/ci_affected_components" } serde = { workspace = true } serde_json = { workspace = true } # T-V2 G-1 manifest ratchet: structured Cargo.toml walk (`toml` value parse). diff --git a/src/v3/compiler/src/lib.rs b/src/v3/compiler/src/lib.rs index 14d57ca9d12..4eee9d02500 100644 --- a/src/v3/compiler/src/lib.rs +++ b/src/v3/compiler/src/lib.rs @@ -4101,7 +4101,6 @@ pub mod gunbc_ci; pub mod post_emit_verifier; pub mod r1c_e_gates; pub mod test_runner; -pub mod v4_ci_runner_pool; pub mod wall_clock_ratchet_manifest; pub mod serialize { use crate::dag::{Behavior, Dag}; diff --git a/src/v3/compiler/tests/integration/sg0_census_test.rs b/src/v3/compiler/tests/integration/sg0_census_test.rs index 615160b14f1..5d6475f7bd1 100644 --- a/src/v3/compiler/tests/integration/sg0_census_test.rs +++ b/src/v3/compiler/tests/integration/sg0_census_test.rs @@ -356,7 +356,6 @@ const EXPECTED_HAND_AUTHORED_NON_TEST: &[&str] = &[ "src/v3/compiler/src/regen_tokenize.rs", "src/v3/compiler/src/self_host_receipt_p0.rs", "src/v3/compiler/src/test_runner.rs", - "src/v3/compiler/src/v4_ci_runner_pool.rs", "src/v3/compiler/src/v4_hollow_alias_gate.rs", "src/v3/compiler/src/wall_clock_ratchet_manifest.rs", ]; diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 2cfb9a1ae3b..86613b75da6 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -35,7 +35,6 @@ const CI_WORKFLOW_POLICY_PREFIXES: &[&str] = &[ ".github/workflows/", "src/v4/workflow/ci", "tools/ci_affected_components", - "src/v3/compiler/src/v4_ci_runner_pool", "scripts/check-workflow-path-regex-inventory", "scripts/workflow-path-regex-forbidden-substrings", ]; @@ -331,6 +330,14 @@ fn v4_workflow_ci_component_bucket_prefixes_align_rust_mirror() { #[test] fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { + // ci.dag ↔ Rust mirror parity (P2 consumer — must run in CI via this `--exact` step). + assert_ci_dag_rust_prefix_parity(CI_WORKFLOW_POLICY_PREFIXES); + assert_ci_dag_rust_prefix_parity(CI_V2_PREFIXES); + assert_ci_dag_rust_prefix_parity(CI_V3_PREFIXES); + assert_ci_dag_rust_prefix_parity(CI_V4_PREFIXES); + assert_ci_dag_rust_exact_path_parity(CI_V2_EXACT_PATHS); + assert_ci_dag_rust_exact_path_parity(CI_V4_EXACT_PATHS); + let module = parse_module(CI_DAG, CI_DAG_PATH); assert!( module.items.iter().any(|item| matches!( diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 19b6c03a159..b141b7d8a7d 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -680,7 +680,6 @@ fn ci_changed_path_affects_workflow_policy(changed: RepoPath) -> Bool { ci_repo_path_has_prefix(path: changed, prefix: ".github/workflows/") || ci_repo_path_has_prefix(path: changed, prefix: "src/v4/workflow/ci") || ci_repo_path_has_prefix(path: changed, prefix: "tools/ci_affected_components") - || ci_repo_path_has_prefix(path: changed, prefix: "src/v3/compiler/src/v4_ci_runner_pool") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/check-workflow-path-regex-inventory") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/workflow-path-regex-forbidden-substrings") } diff --git a/tools/ci_affected_components/src/lib.rs b/tools/ci_affected_components/src/lib.rs index 8aaacc16cde..ab996d34f5c 100644 --- a/tools/ci_affected_components/src/lib.rs +++ b/tools/ci_affected_components/src/lib.rs @@ -6,7 +6,7 @@ //! prefix parity. Lives outside `v3-compiler` so the affected job can emit `v3=false` without //! compiling the frozen v3 package first (INVARIANTS P3 fail-closed boundary). -/// Structural mirror of `CiComponentAffected` in `src/v4/workflow/ci.dag`. +pub mod runner_pool; #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct CiComponentAffected { pub v2: bool, @@ -78,7 +78,6 @@ pub fn ci_changed_path_affects_workflow_policy(path: &str) -> bool { path.starts_with(".github/workflows/") || path.starts_with("src/v4/workflow/ci") || path.starts_with("tools/ci_affected_components") - || path.starts_with("src/v3/compiler/src/v4_ci_runner_pool") || path.starts_with("scripts/check-workflow-path-regex-inventory") || path.starts_with("scripts/workflow-path-regex-forbidden-substrings") } @@ -125,10 +124,7 @@ mod tests { ".github/workflows/ci.yml" )); assert!(ci_changed_path_affects_workflow_policy( - "src/v3/compiler/src/v4_ci_runner_pool.rs" - )); - assert!(ci_changed_path_affects_workflow_policy( - "tools/ci_affected_components/src/lib.rs" + "tools/ci_affected_components/src/runner_pool.rs" )); } diff --git a/src/v3/compiler/src/v4_ci_runner_pool.rs b/tools/ci_affected_components/src/runner_pool.rs similarity index 96% rename from src/v3/compiler/src/v4_ci_runner_pool.rs rename to tools/ci_affected_components/src/runner_pool.rs index a2f3f186589..680cbdd4f0d 100644 --- a/src/v3/compiler/src/v4_ci_runner_pool.rs +++ b/tools/ci_affected_components/src/runner_pool.rs @@ -1,4 +1,5 @@ //! Structural mirror of `SelfHostedRunnerPool` / `m1_probe_cargo_check_jobs` in `src/v4/workflow/ci.dag`. +//! Lives outside `v3-compiler` (same crate as affected-set host transport). /// Structural mirror of `SelfHostedRunnerPool` in `src/v4/workflow/ci.dag`. #[derive(Debug, Clone, Copy, PartialEq, Eq)] From fc2d8e8c55e8ba751c8298f5f2e679aac0165466 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 07:59:16 +0000 Subject: [PATCH 47/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 86613b75da6..9217154d53c 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -432,7 +432,7 @@ fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { CI_DAG.contains("data m1_probe_cargo_check_jobs: Int = 4"), "{CI_DAG_PATH}: M1 cargo parallelism must be an explicit operator constant" ); - let m1_jobs = v3_compiler::v4_ci_runner_pool::m1_probe_cargo_check_jobs(); + let m1_jobs = ci_affected_components::runner_pool::m1_probe_cargo_check_jobs(); assert_eq!( m1_jobs, 4, "Rust transport mirror of m1_probe_cargo_check_jobs must match ci.dag operator constant" From 35f3f5fa90cadf98107d78170f1ccce2f728fb89 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 08:08:19 +0000 Subject: [PATCH 48/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v4_workflow_ci_runner_dag_smoke_test.rs | 221 +++++++++++++----- tools/ci_affected_components/src/lib.rs | 5 +- 2 files changed, 169 insertions(+), 57 deletions(-) diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 9217154d53c..1a4a6845b35 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -30,59 +30,173 @@ const CLAIM_PATH: &str = "src/v4/test/claim/workflow/affected_set_ci_runner.dag" const CI_AFFECTED_COMPONENTS_LIB: &str = include_str!("../../../../../tools/ci_affected_components/src/lib.rs"); -/// Single-authority workflow_policy path buckets (`ci.dag` predicates ↔ Rust host mirror). -const CI_WORKFLOW_POLICY_PREFIXES: &[&str] = &[ - ".github/workflows/", - "src/v4/workflow/ci", - "tools/ci_affected_components", - "scripts/check-workflow-path-regex-inventory", - "scripts/workflow-path-regex-forbidden-substrings", +const CI_CHANGED_PATH_AFFECTS_FNS: &[&str] = &[ + "ci_changed_path_affects_v2", + "ci_changed_path_affects_v3", + "ci_changed_path_affects_v4", + "ci_changed_path_affects_workflow_policy", ]; -const CI_V2_PREFIXES: &[&str] = &["src/v2/"]; -const CI_V2_EXACT_PATHS: &[&str] = &["Cargo.toml", "Cargo.lock"]; -const CI_V3_PREFIXES: &[&str] = &["src/v3/", "dsl/"]; -const CI_V4_PREFIXES: &[&str] = &[ - "src/v4/", - "fixtures/v4-mvp1/", - "scripts/v4-mvp1", - "scripts/v4-m1", - "scripts/v4-testclaim-", - "dsl/std/", -]; -const CI_V4_EXACT_PATHS: &[&str] = &[ - "Cargo.toml", - "Cargo.lock", - "scripts/v4-mvp1-e2e-gate.sh", - "scripts/v4-m1-rust-emit-probe.sh", +struct CiAffectedFixture { + path: &'static str, + v2: bool, + v3: bool, + v4: bool, + workflow_policy: bool, +} + +/// Behavioral fixtures aligned with `src/v4/test/claim/workflow/ci_component_affected.dag`. +const CI_AFFECTED_BEHAVIORAL_FIXTURES: &[CiAffectedFixture] = &[ + CiAffectedFixture { + path: "src/v2/stage0/Cargo.toml", + v2: true, + v3: false, + v4: false, + workflow_policy: false, + }, + CiAffectedFixture { + path: "dsl/gunbc/ci.dag", + v2: false, + v3: true, + v4: false, + workflow_policy: false, + }, + CiAffectedFixture { + path: "dsl/std/node.dag", + v2: false, + v3: true, + v4: true, + workflow_policy: false, + }, + CiAffectedFixture { + path: "scripts/v4-m1-rust-emit-probe.sh", + v2: false, + v3: false, + v4: true, + workflow_policy: false, + }, + CiAffectedFixture { + path: "src/v4/workflow/ci.dag", + v2: false, + v3: false, + v4: true, + workflow_policy: true, + }, + CiAffectedFixture { + path: "Cargo.lock", + v2: true, + v3: false, + v4: true, + workflow_policy: false, + }, + CiAffectedFixture { + path: "docs/README.md", + v2: false, + v3: false, + v4: false, + workflow_policy: false, + }, ]; -fn assert_ci_dag_rust_prefix_parity(prefixes: &[&str]) { - for prefix in prefixes { - assert!( - CI_DAG.contains(&format!("prefix: \"{prefix}\"")), - "{CI_DAG_PATH}: authority must declare prefix `{prefix}`" - ); - assert!( - CI_AFFECTED_COMPONENTS_LIB.contains(&format!("\"{prefix}\"")), - "ci_affected_components lib mirror must declare prefix `{prefix}`" - ); +fn extract_fn_body<'a>(source: &'a str, fn_name: &str) -> &'a str { + let marker = format!("fn {fn_name}"); + let start = source + .find(&marker) + .unwrap_or_else(|| panic!("missing fn `{fn_name}`")); + let rest = &source[start + marker.len()..]; + let end = rest.find("\nfn ").unwrap_or(rest.len()); + &source[start..start + marker.len() + end] +} + +fn dag_prefix_literals_in_fn(body: &str) -> std::collections::BTreeSet { + let mut out = std::collections::BTreeSet::new(); + for line in body.lines() { + if let Some(idx) = line.find("prefix: \"") { + let rest = &line[idx + 9..]; + if let Some(end) = rest.find('"') { + out.insert(rest[..end].to_string()); + } + } } + out } -fn assert_ci_dag_rust_exact_path_parity(paths: &[&str]) { - for path in paths { - assert!( - CI_DAG.contains(&format!("changed == \"{path}\"")), - "{CI_DAG_PATH}: authority must declare exact path `{path}`" - ); - assert!( - CI_AFFECTED_COMPONENTS_LIB.contains(&format!("\"{path}\"")), - "ci_affected_components lib mirror must declare exact path `{path}`" +fn rust_prefix_literals_in_fn(body: &str) -> std::collections::BTreeSet { + let mut out = std::collections::BTreeSet::new(); + for line in body.lines() { + if let Some(idx) = line.find(".starts_with(\"") { + let rest = &line[idx + 15..]; + if let Some(end) = rest.find('"') { + out.insert(rest[..end].to_string()); + } + } + } + out +} + +fn dag_exact_path_literals_in_fn(body: &str) -> std::collections::BTreeSet { + let mut out = std::collections::BTreeSet::new(); + for line in body.lines() { + if let Some(idx) = line.find("changed == \"") { + let rest = &line[idx + 12..]; + if let Some(end) = rest.find('"') { + out.insert(rest[..end].to_string()); + } + } + } + out +} + +fn rust_exact_path_literals_in_fn(body: &str) -> std::collections::BTreeSet { + let mut out = std::collections::BTreeSet::new(); + for line in body.lines() { + if let Some(idx) = line.find("path == \"") { + let rest = &line[idx + 9..]; + if let Some(end) = rest.find('"') { + out.insert(rest[..end].to_string()); + } + } + } + out +} + +fn assert_ci_dag_rust_bucket_parity(fn_name: &str) { + let dag_body = extract_fn_body(CI_DAG, fn_name); + let rust_body = extract_fn_body(CI_AFFECTED_COMPONENTS_LIB, fn_name); + assert_eq!( + dag_prefix_literals_in_fn(dag_body), + rust_prefix_literals_in_fn(rust_body), + "{fn_name}: prefix literal sets must match between {CI_DAG_PATH} and ci_affected_components lib" + ); + assert_eq!( + dag_exact_path_literals_in_fn(dag_body), + rust_exact_path_literals_in_fn(rust_body), + "{fn_name}: exact-path literal sets must match between {CI_DAG_PATH} and ci_affected_components lib" + ); +} + +fn assert_ci_dag_rust_mirror_behavioral_parity() { + use ci_affected_components::ci_component_affected_from_changed_paths; + for fixture in CI_AFFECTED_BEHAVIORAL_FIXTURES { + let flags = ci_component_affected_from_changed_paths([fixture.path]); + assert_eq!(flags.v2, fixture.v2, "path `{}`: v2 flag", fixture.path); + assert_eq!(flags.v3, fixture.v3, "path `{}`: v3 flag", fixture.path); + assert_eq!(flags.v4, fixture.v4, "path `{}`: v4 flag", fixture.path); + assert_eq!( + flags.workflow_policy, fixture.workflow_policy, + "path `{}`: workflow_policy flag", + fixture.path ); } } +fn assert_ci_dag_rust_mirror_full_parity() { + for fn_name in CI_CHANGED_PATH_AFFECTS_FNS { + assert_ci_dag_rust_bucket_parity(fn_name); + } + assert_ci_dag_rust_mirror_behavioral_parity(); +} + fn parse_module(source: &str, path: &str) -> v3_compiler::parse_surface::SurfaceModule { let tokens = tokenize_for_test(source, path).unwrap_or_else(|e| panic!("{path}: tokenize: {e:?}")); @@ -316,27 +430,24 @@ fn v4_workflow_ci_test_claim_selection_entrypoints() { #[test] fn v4_workflow_ci_workflow_policy_prefixes_align_rust_mirror() { - assert_ci_dag_rust_prefix_parity(CI_WORKFLOW_POLICY_PREFIXES); + assert_ci_dag_rust_bucket_parity("ci_changed_path_affects_workflow_policy"); } #[test] fn v4_workflow_ci_component_bucket_prefixes_align_rust_mirror() { - assert_ci_dag_rust_prefix_parity(CI_V2_PREFIXES); - assert_ci_dag_rust_prefix_parity(CI_V3_PREFIXES); - assert_ci_dag_rust_prefix_parity(CI_V4_PREFIXES); - assert_ci_dag_rust_exact_path_parity(CI_V2_EXACT_PATHS); - assert_ci_dag_rust_exact_path_parity(CI_V4_EXACT_PATHS); + for fn_name in [ + "ci_changed_path_affects_v2", + "ci_changed_path_affects_v3", + "ci_changed_path_affects_v4", + ] { + assert_ci_dag_rust_bucket_parity(fn_name); + } } #[test] fn v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml() { - // ci.dag ↔ Rust mirror parity (P2 consumer — must run in CI via this `--exact` step). - assert_ci_dag_rust_prefix_parity(CI_WORKFLOW_POLICY_PREFIXES); - assert_ci_dag_rust_prefix_parity(CI_V2_PREFIXES); - assert_ci_dag_rust_prefix_parity(CI_V3_PREFIXES); - assert_ci_dag_rust_prefix_parity(CI_V4_PREFIXES); - assert_ci_dag_rust_exact_path_parity(CI_V2_EXACT_PATHS); - assert_ci_dag_rust_exact_path_parity(CI_V4_EXACT_PATHS); + // ci.dag ↔ Rust mirror parity (P2 consumer — set equality + behavioral fixtures; CI `--exact` step). + assert_ci_dag_rust_mirror_full_parity(); let module = parse_module(CI_DAG, CI_DAG_PATH); assert!( diff --git a/tools/ci_affected_components/src/lib.rs b/tools/ci_affected_components/src/lib.rs index ab996d34f5c..f82a7044f62 100644 --- a/tools/ci_affected_components/src/lib.rs +++ b/tools/ci_affected_components/src/lib.rs @@ -3,8 +3,9 @@ //! **Modeled authority:** `src/v4/workflow/ci.dag` (`ci_component_affected_from_git_diff` and //! `ci_changed_path_affects_*`). This crate is an interim Rust mirror of those predicates for //! the CI runner (not `.dag` eval yet); keep aligned via `v4_workflow_ci_runner_dag_smoke_test` -//! prefix parity. Lives outside `v3-compiler` so the affected job can emit `v3=false` without -//! compiling the frozen v3 package first (INVARIANTS P3 fail-closed boundary). +//! set-equality + behavioral fixture parity (not substring presence). Lives outside `v3-compiler` +//! so the affected job can emit `v3=false` without compiling the frozen v3 package first +//! (INVARIANTS P3 fail-closed boundary). pub mod runner_pool; #[derive(Debug, Clone, Copy, PartialEq, Eq)] From 1ab9c62c8307ddb9f71c59c9a58ebc9ecbe9383d Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 08:12:08 +0000 Subject: [PATCH 49/56] fix: wire runner pool capacity validators into TestClaim Connect ci_runner_pool_fleet_capacities_valid to runner_pool_m1_probe.dag so modeled Int-bound validators have a consumer per Practice 2. Co-authored-by: Cursor --- src/v4/test/claim/workflow/runner_pool_m1_probe.dag | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag index 0e102ed9d2f..341dcec3608 100644 --- a/src/v4/test/claim/workflow/runner_pool_m1_probe.dag +++ b/src/v4/test/claim/workflow/runner_pool_m1_probe.dag @@ -6,6 +6,7 @@ module v4.test.claim.workflow.runner_pool_m1_probe import v4.std.logic { Bool } import v4.workflow.ci { ci_runner_arch_arm64, + ci_runner_pool_fleet_capacities_valid, ci_srv1_pool, ci_srv2_pool, m1_probe_cargo_check_jobs @@ -15,6 +16,10 @@ fn runner_pool_fleet_arch_holds() -> Bool { ci_srv1_pool.arch == ci_runner_arch_arm64 && ci_srv2_pool.arch == ci_runner_arch_arm64 } +fn runner_pool_fleet_capacities_valid_holds() -> Bool { + ci_runner_pool_fleet_capacities_valid() +} + fn runner_pool_srv1_runner_count_holds() -> Bool { ci_srv1_pool.runner_count == 20 } @@ -28,6 +33,7 @@ fn runner_pool_m1_cargo_jobs_holds() -> Bool { } data runner_pool_arch_claim_passes: Bool = runner_pool_fleet_arch_holds() +data runner_pool_capacities_claim_passes: Bool = runner_pool_fleet_capacities_valid_holds() data runner_pool_srv1_claim_passes: Bool = runner_pool_srv1_runner_count_holds() data runner_pool_srv2_claim_passes: Bool = runner_pool_srv2_jobserver_cap_holds() data runner_pool_m1_jobs_claim_passes: Bool = runner_pool_m1_cargo_jobs_holds() From 84112151c74d2aeb1d92302456276e32d1b86124 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 08:22:01 +0000 Subject: [PATCH 50/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../v4_workflow_ci_runner_dag_smoke_test.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index 1a4a6845b35..e5ab2a5f6cc 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -98,14 +98,22 @@ const CI_AFFECTED_BEHAVIORAL_FIXTURES: &[CiAffectedFixture] = &[ }, ]; +fn fn_body_end(rest: &str) -> usize { + ["\npub fn ", "\nfn ", "\n#[cfg(test)]"] + .iter() + .filter_map(|prefix| rest.find(prefix)) + .min() + .unwrap_or(rest.len()) +} + fn extract_fn_body<'a>(source: &'a str, fn_name: &str) -> &'a str { let marker = format!("fn {fn_name}"); let start = source .find(&marker) .unwrap_or_else(|| panic!("missing fn `{fn_name}`")); - let rest = &source[start + marker.len()..]; - let end = rest.find("\nfn ").unwrap_or(rest.len()); - &source[start..start + marker.len() + end] + let after = start + marker.len(); + let rest = &source[after..]; + &source[start..after + fn_body_end(rest)] } fn dag_prefix_literals_in_fn(body: &str) -> std::collections::BTreeSet { @@ -125,7 +133,7 @@ fn rust_prefix_literals_in_fn(body: &str) -> std::collections::BTreeSet let mut out = std::collections::BTreeSet::new(); for line in body.lines() { if let Some(idx) = line.find(".starts_with(\"") { - let rest = &line[idx + 15..]; + let rest = &line[idx + 14..]; if let Some(end) = rest.find('"') { out.insert(rest[..end].to_string()); } From 62d65e4da8abb62f371dac88d9370ac564af44bb Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 08:23:16 +0000 Subject: [PATCH 51/56] fix: correct set-equality parity extraction for pub fn bodies Stop fn-body slicing at `\npub fn ` boundaries and collect all path/prefix literals per line so M1 smoke parity matches ci.dag. Co-authored-by: Cursor --- .../v4_workflow_ci_runner_dag_smoke_test.rs | 43 ++++++++----------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs index e5ab2a5f6cc..8046d0c5423 100644 --- a/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs +++ b/src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs @@ -116,15 +116,25 @@ fn extract_fn_body<'a>(source: &'a str, fn_name: &str) -> &'a str { &source[start..after + fn_body_end(rest)] } +fn literals_after_marker(line: &str, marker: &str) -> std::collections::BTreeSet { + let mut out = std::collections::BTreeSet::new(); + let mut search = line; + while let Some(idx) = search.find(marker) { + let rest = &search[idx + marker.len()..]; + if let Some(end) = rest.find('"') { + out.insert(rest[..end].to_string()); + search = &rest[end + 1..]; + } else { + break; + } + } + out +} + fn dag_prefix_literals_in_fn(body: &str) -> std::collections::BTreeSet { let mut out = std::collections::BTreeSet::new(); for line in body.lines() { - if let Some(idx) = line.find("prefix: \"") { - let rest = &line[idx + 9..]; - if let Some(end) = rest.find('"') { - out.insert(rest[..end].to_string()); - } - } + out.extend(literals_after_marker(line, "prefix: \"")); } out } @@ -132,12 +142,7 @@ fn dag_prefix_literals_in_fn(body: &str) -> std::collections::BTreeSet { fn rust_prefix_literals_in_fn(body: &str) -> std::collections::BTreeSet { let mut out = std::collections::BTreeSet::new(); for line in body.lines() { - if let Some(idx) = line.find(".starts_with(\"") { - let rest = &line[idx + 14..]; - if let Some(end) = rest.find('"') { - out.insert(rest[..end].to_string()); - } - } + out.extend(literals_after_marker(line, ".starts_with(\"")); } out } @@ -145,12 +150,7 @@ fn rust_prefix_literals_in_fn(body: &str) -> std::collections::BTreeSet fn dag_exact_path_literals_in_fn(body: &str) -> std::collections::BTreeSet { let mut out = std::collections::BTreeSet::new(); for line in body.lines() { - if let Some(idx) = line.find("changed == \"") { - let rest = &line[idx + 12..]; - if let Some(end) = rest.find('"') { - out.insert(rest[..end].to_string()); - } - } + out.extend(literals_after_marker(line, "changed == \"")); } out } @@ -158,12 +158,7 @@ fn dag_exact_path_literals_in_fn(body: &str) -> std::collections::BTreeSet std::collections::BTreeSet { let mut out = std::collections::BTreeSet::new(); for line in body.lines() { - if let Some(idx) = line.find("path == \"") { - let rest = &line[idx + 9..]; - if let Some(end) = rest.find('"') { - out.insert(rest[..end].to_string()); - } - } + out.extend(literals_after_marker(line, "path == \"")); } out } From 5d4a4fd856eb246156737d143a3bd05403389005 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 08:23:18 +0000 Subject: [PATCH 52/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 728a654ed63..c4db15b3bcb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1137,6 +1137,7 @@ dependencies = [ name = "v3-compiler" version = "0.1.0" dependencies = [ + "ci_affected_components", "criterion", "gen_gunbc_ci_workflow_dag", "libc", From 1727784fda17be7271b4950894e906e6bb7a6108 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 09:30:36 +0000 Subject: [PATCH 53/56] fix(pr-3853): add P5(b) receipt for smoke-test same-path expansion Codex flagged missing T-PB-B receipt for expanded v4_workflow_ci_runner_dag_smoke_test.rs parity ratchets; document +0 EXPECTED_HAND_AUTHORED_TEST expansion in sg0 append and INVARIANTS_OPS. Co-authored-by: Cursor --- _internal/INVARIANTS_OPS.md | 2 +- scripts/ci-merge/sg0-pr-body-append.3853.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/_internal/INVARIANTS_OPS.md b/_internal/INVARIANTS_OPS.md index e93aedca40e..1021be0b613 100644 --- a/_internal/INVARIANTS_OPS.md +++ b/_internal/INVARIANTS_OPS.md @@ -39,7 +39,7 @@ Per **Dispatch-Discipline Mechanisms (b)** above, each **new** path added to `EX | `src/v3/compiler/tests/integration/v4_extdeps_react_dag_smoke_test.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; **TASKS.md** T-4.7 (`src/v4/extdeps/frameworks/react.dag`, React 19.2.0–pinned framework substrate). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when `src/v4/extdeps/frameworks/react.dag` (or the v4 extdeps fixture set it belongs to) is exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust `compile_to_dag` probe. **Interim ratchet:** `v4_extdeps_react_dag_compiles` asserts `compile_to_dag` succeeds with empty `dag.diagnostics()` for the pinned `include_str!` source. | | `src/v3/compiler/tests/integration/v4_extdeps_file_system_dag_smoke_test.rs` | **TASKS.md** T-4.5 / Wave-2-C2 (`src/v4/extdeps/file_system.dag` — external file-system resource + modeled read/write effects; Practice 11 companion: no `import v4.std.node`, no `NodeFileBinding`; POSIX substrate exports retained for `posix.dag` / `testgen.dag`). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when `file_system.dag` is exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust probe. **Interim ratchet:** `v4_extdeps_file_system_dag_tokenizes_and_parses` plus Practice-11 companion tests (parse-surface import/type bans, POSIX-grounded `FilePath`, per-operation receipt record shapes, Wave-2 `ModeledFileEffects.file_read`/`file_write` arrow signatures + legacy `FileSystemOperations` / request-carrier coexistence). | | `src/v3/compiler/tests/integration/v4_p9_llvm_instruction_cost_single_owner_test.rs` | **P9 single-owner (R2-1):** replaces dissolved `v4_lens_cost_dag_smoke_test.rs` ratchet — `fn llvm_instruction_cost` must appear exactly once under `src/v4/`, in `src/v4/lens/cost.dag` (whole-tree parse does **not** substitute; see `docs/v4-close-interrogation.md` §P5(b) / `feature:p9-llvm-instruction-cost-single-owner`). Complements `.dag` TestClaim `src/v4/test/claim/lens_cost/p9_llvm_instruction_cost_registry_owner.dag` (registry exclusivity). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the harness. **Dissolution:** remove when M2 reflection or generated harness executes the `.dag` claim over the full v4 corpus without this host file-walk ratchet. **Interim ratchet:** `v4_p9_llvm_instruction_cost_defined_only_in_lens_cost_dag` walks `src/v4/**/*.dag` for `fn llvm_instruction_cost`; `v4_p9_llvm_instruction_cost_absent_from_llvm_ir_dag` asserts `llvm_ir.dag` does not re-author the cost table. | -| `src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs` | **TASKS.md** T-21 + T-24 Wave-0 (`src/v4/workflow/ci.dag` — `ci_select_from_*` under canonical `v4.workflow.ci`; `affected_set_rerun_nodes` → `List`; narrow = identity-aware subtree frontier in `verification.dag`; fail-closed = full roster; `src/v4/test/claim/workflow/affected_set_ci_runner.dag` structural receipts). **Tracked substrate bridge:** `verification.dag` `test_claim_ci_selection_fail_closed` carries 🟡 gated Practice-10 predicate-dissolution mark (dissolve when `ci_select` consumes `TestClaimCacheKey` from `05_eval`). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when Node-level TestClaim CI selection is exercised only by `.dag` `TestClaim` rows / generated harness / host runner without this parse probe (full wire: edit-locus + `TestClaimExerciseSurface` + `ci.yml` — follow-on A/B/C). **Interim ratchet:** `v4_workflow_ci_dag_tokenizes_and_parses`; `v4_workflow_ci_test_claim_selection_entrypoints`; `v4_workflow_affected_set_ci_runner_claim_*` — tokenize+parse + import/entrypoint wiring receipts; fail-closed roster contract substring receipts on `RerunNodeSetFailClosed => roster` and `test_claim_ci_selection_fail_closed`. | +| `src/v3/compiler/tests/integration/v4_workflow_ci_runner_dag_smoke_test.rs` | **TASKS.md** T-21 + T-24 Wave-0 (`src/v4/workflow/ci.dag` — `ci_select_from_*` under canonical `v4.workflow.ci`; `affected_set_rerun_nodes` → `List`; narrow = identity-aware subtree frontier in `verification.dag`; fail-closed = full roster; `src/v4/test/claim/workflow/affected_set_ci_runner.dag` structural receipts). **Tracked substrate bridge:** `verification.dag` `test_claim_ci_selection_fail_closed` carries 🟡 gated Practice-10 predicate-dissolution mark (dissolve when `ci_select` consumes `TestClaimCacheKey` from `05_eval`). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **PR #3853 same-path expansion (+0 SG-0 paths):** adds `v4_workflow_ci_workflow_policy_prefixes_align_rust_mirror` and `v4_workflow_ci_component_bucket_prefixes_align_rust_mirror` (set-equality prefix/exact-path literal extraction for all four `ci_changed_path_affects_*` fns); folds full `ci.dag` ↔ `tools/ci_affected_components` behavioral parity (`assert_ci_dag_rust_mirror_full_parity`, fixtures aligned with `ci_component_affected.dag`) into the CI `--exact` M1 binding step (`v4_workflow_ci_m1_rust_emit_probe_modeled_and_bound_to_ci_yml`). Explicitly deferred under **ROADMAP** § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; dissolve when affected-set path buckets project from `.dag` eval without parallel Rust mirrors. **Dissolution:** remove when Node-level TestClaim CI selection is exercised only by `.dag` `TestClaim` rows / generated harness / host runner without this parse probe (full wire: edit-locus + `TestClaimExerciseSurface` + `ci.yml` — follow-on A/B/C). **Interim ratchet:** `v4_workflow_ci_dag_tokenizes_and_parses`; `v4_workflow_ci_test_claim_selection_entrypoints`; `v4_workflow_affected_set_ci_runner_claim_*` — tokenize+parse + import/entrypoint wiring receipts; fail-closed roster contract substring receipts on `RerunNodeSetFailClosed => roster` and `test_claim_ci_selection_fail_closed`. | | `src/v3/compiler/tests/integration/v4_test_bootstrap_infra_closeout_test.rs` | **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; **TASKS.md** **T-19** (`src/v4/lens/testgen.dag`) + **T-20** (`src/v4/workflow/bootstrap.dag`) + **T-22** (`src/v4/compiler/05_eval.dag` DiagnosticAssert execution / `eval_rejected_assert_kind_deferred` dissolution; witnesses in `src/v4/test/claim/manual/diagnostic_assert_eval.dag`). **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the closeout ratchet; T-22 expansion in its PR updates this row; T-19 AlgebraLaw Nat corpus expansion (this PR) further updates this row (same path — no new census line); T-19 deferral lane: TASKS.md §T-19 `algebra_law_conformance.dag` corpus, _internal/ROADMAP_OPS.md § Nine lanes row T-PB-B. **Dissolution:** remove when the T-19/T-20/T-22 closeout checks are expressed as `.dag` `TestClaim` rows or generated harness coverage without this host parse-surface ratchet. **Interim ratchet:** `testgen_concept_surface_stays_closed_and_classified` checks the closed testgen scheduling arms and the `Generator` claim kind / anchor / classification / slot field set; `language_behavior_equivalence_generated_claims_parse` / `language_behavior_equivalence_run_test_claim_receipts_present` pin the LBE generator slice; `idempotent_operation_generated_claims_parse_and_pin_emission` pins the idempotent-operation generator slice (`src/v4/std/effects.dag` canonical `IdempotentShape`/`EffectShape` witnesses + `idempotent_operation_witness_node`; outside the six-way `TestgenConcept` coproduct; label-only skip); `manual_manifest_matches_claim_anchor_discriminants` checks manual claim anchors join to the manifest by `ManualAnchorKey`; `claim_corpus_has_no_direct_manual_anchor_assignments` scans `src/v4/test/claim/**/*.dag` so `TestClaim.anchor` literals cannot bypass `manual_claim_anchor(...)` after the `ClaimAnchorKey` split; `coproduct_exhaustiveness_generated_claim_parse_and_witnesses_present` checks the generated coproduct-exhaustiveness corpus parses, derives the invalid `Node` and generated claim anchor from one `GeneratedCoproductExhaustiveness` source, uses canonical `node_locus`, and schedules the generated `DiagnosticExhaustiveness` claim under `GeneratedClaimAnchor`; `t20_bootstrap_plan_keeps_self_hosting_chain_as_data` checks the seed/self0/self1/fixpt bootstrap chain is encoded as `CompileStage` / `BootstrapPlan` data; `t22_diagnostic_assert_eval_witnesses_parse` checks `diagnostic_assert_eval.dag` parses; `t22_eval_diagnostic_assert_not_deferred_in_substrate` checks `05_eval.dag` no longer contains `eval_rejected_assert_kind_deferred`, executes `DiagnosticAssert`, and routes `run_test_claim` through `aggregate_verdicts`; `t19_algebra_law_generated_claims_parse_and_use_testgen_emit` checks `algebra_law_conformance.dag` parses and asserts the testgen emit helpers + tautological-sides guard in `lens/testgen.dag`. | | `src/v3/compiler/tests/integration/coverage_defect_acceptance_dag_test.rs` | **Coverage-defect acceptance keys:** `src/v4/lens/coverage.dag` carries the canonical coverage-key set for `docs/design-dissolution-lens.md` §5.1; the old emit-template key is retired into `TemplateHole`, and the old string-escape key is split into `TemplateHole` plus `CanonicalCarrier`. **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the parse-level ratchet. **Dissolution:** remove when the v4 coverage lens runs as `.dag` / generated coverage and can assert the same acceptance rows without this host parser check. **Interim ratchet:** `coverage_defect_acceptance_keys_match_declared_rows` tokenizes/parses `src/v4/lens/coverage.dag` and asserts the exact parsed `(coverage_defect_* data row, CoverageDefectKey variant)` set matches the expected acceptance-key table while rejecting retired emit-template / string-escape names. | | `src/v3/compiler/tests/integration/v4_bin_main_dag_smoke_test.rs` | **T-15** (`src/v4/bin/main.dag` — trampoline **`String`** authority + B1 digest **placeholder** `Node`s; closed-tree invariant #2 / pure-bootstrap zero-floor per `docs/design-pure-bootstrap-zero.md`). **Grounded-indicator authoring on `main.dag` is HOLD** pending hub-relayed canonical spec (operator-direct format under-spec; pending canonical spec). **ROADMAP:** `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`. **PR receipt (P5 Mechanism (b)):** this INVARIANTS row + matching `EXPECTED_HAND_AUTHORED_TEST` line in `sg0_census_test.rs` land in the same PR as the smoke harness. **Dissolution:** remove when `main.dag` is exercised only by `.dag` `TestClaim` rows / a generated harness without this per-file Rust probe. **Interim ratchet:** `v4_bin_main_dag_tokenizes_and_parses_with_trampoline_source_anchor` runs `tokenize_for_test` + `parse_for_test` on the pinned `include_str!` source and asserts the trampoline / stub `data` identifiers plus the escaped `include!` spelling remain present in source text (full `compile_to_dag` on `main.dag` alone is deferred: `import v4.std.node` is not linked in the single-file harness). | diff --git a/scripts/ci-merge/sg0-pr-body-append.3853.txt b/scripts/ci-merge/sg0-pr-body-append.3853.txt index bdba3018827..b760c8c7287 100644 --- a/scripts/ci-merge/sg0-pr-body-append.3853.txt +++ b/scripts/ci-merge/sg0-pr-body-append.3853.txt @@ -1,3 +1,5 @@ SG-0 hand-path delta: +0 SG-0 pairing: (c) Net +0 on `EXPECTED_HAND_AUTHORED_NON_TEST` — T-24 interim Rust mirrors (`tools/ci_affected_components` lib/main/runner_pool) live outside v3-compiler SG-0 census with INVARIANTS §P5(b) rows. Follow-up dispatch: dissolve when `ci.dag` eval / generated CI runner owns affected-set and M1 parallelism without parallel Rust path logic (T-24 emission slice; tracked gunbc#3853). + +SG-0 pairing: (c) Net +0 on `EXPECTED_HAND_AUTHORED_TEST` — same-path expansion of `v4_workflow_ci_runner_dag_smoke_test.rs` (INVARIANTS §P5(b) row updated per PR #3853): set-equality `ci.dag` ↔ `tools/ci_affected_components` path-bucket parity (`v4_workflow_ci_workflow_policy_prefixes_align_rust_mirror`, `v4_workflow_ci_component_bucket_prefixes_align_rust_mirror`) plus behavioral fixtures aligned with `ci_component_affected.dag` (`assert_ci_dag_rust_mirror_full_parity` in M1 `--exact` binding step). Deferral: `_internal/ROADMAP_OPS.md` § **Nine lanes** row **T-PB-B** / `pb_rust_tests_outside_residual_zero`; dissolve when affected-set projection runs from `.dag` eval only (tracked gunbc#3853). From 836af8cbb603ec492a8158cda2c5e715a33eb60e Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 09:40:47 +0000 Subject: [PATCH 54/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/workflow/ci.dag | 2 +- tools/ci_affected_components/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index b141b7d8a7d..44159608d05 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -678,7 +678,7 @@ fn ci_changed_path_affects_v4(changed: RepoPath) -> Bool { fn ci_changed_path_affects_workflow_policy(changed: RepoPath) -> Bool { ci_repo_path_has_prefix(path: changed, prefix: ".github/workflows/") - || ci_repo_path_has_prefix(path: changed, prefix: "src/v4/workflow/ci") + || ci_repo_path_has_prefix(path: changed, prefix: "src/v4/workflow/ci/") || ci_repo_path_has_prefix(path: changed, prefix: "tools/ci_affected_components") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/check-workflow-path-regex-inventory") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/workflow-path-regex-forbidden-substrings") diff --git a/tools/ci_affected_components/src/lib.rs b/tools/ci_affected_components/src/lib.rs index f82a7044f62..ff66cb03ae7 100644 --- a/tools/ci_affected_components/src/lib.rs +++ b/tools/ci_affected_components/src/lib.rs @@ -77,7 +77,7 @@ pub fn ci_changed_path_affects_v4(path: &str) -> bool { pub fn ci_changed_path_affects_workflow_policy(path: &str) -> bool { path.starts_with(".github/workflows/") - || path.starts_with("src/v4/workflow/ci") + || path.starts_with("src/v4/workflow/ci/") || path.starts_with("tools/ci_affected_components") || path.starts_with("scripts/check-workflow-path-regex-inventory") || path.starts_with("scripts/workflow-path-regex-forbidden-substrings") From a63b7a81c3b3f294735ed251fe516c761132eb11 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 09:49:42 +0000 Subject: [PATCH 55/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/v4/workflow/ci.dag | 1 + 1 file changed, 1 insertion(+) diff --git a/src/v4/workflow/ci.dag b/src/v4/workflow/ci.dag index 44159608d05..1d4759bef5b 100644 --- a/src/v4/workflow/ci.dag +++ b/src/v4/workflow/ci.dag @@ -678,6 +678,7 @@ fn ci_changed_path_affects_v4(changed: RepoPath) -> Bool { fn ci_changed_path_affects_workflow_policy(changed: RepoPath) -> Bool { ci_repo_path_has_prefix(path: changed, prefix: ".github/workflows/") + || changed == "src/v4/workflow/ci.dag" || ci_repo_path_has_prefix(path: changed, prefix: "src/v4/workflow/ci/") || ci_repo_path_has_prefix(path: changed, prefix: "tools/ci_affected_components") || ci_repo_path_has_prefix(path: changed, prefix: "scripts/check-workflow-path-regex-inventory") From 4804ca0f36ba86a20bc9945b9546a134a6a3b2f1 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Fri, 29 May 2026 09:51:24 +0000 Subject: [PATCH 56/56] =?UTF-8?q?WIP:=20T-24:=20workflow/ci.dag=20emits=20?= =?UTF-8?q?ci.yml=20=E2=80=94=20dissolve=20detect-affected-components?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- tools/ci_affected_components/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/ci_affected_components/src/lib.rs b/tools/ci_affected_components/src/lib.rs index ff66cb03ae7..dda332316ef 100644 --- a/tools/ci_affected_components/src/lib.rs +++ b/tools/ci_affected_components/src/lib.rs @@ -77,6 +77,7 @@ pub fn ci_changed_path_affects_v4(path: &str) -> bool { pub fn ci_changed_path_affects_workflow_policy(path: &str) -> bool { path.starts_with(".github/workflows/") + || path == "src/v4/workflow/ci.dag" || path.starts_with("src/v4/workflow/ci/") || path.starts_with("tools/ci_affected_components") || path.starts_with("scripts/check-workflow-path-regex-inventory")