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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ jobs:
ci:
runs-on: [self-hosted, linux, arm64]
needs: [build, regen]
timeout-minutes: 100
timeout-minutes: 110
steps:
- name: Checkout
uses: actions/checkout@v5
Expand Down Expand Up @@ -276,7 +276,7 @@ jobs:
"$ROOT/target/release/claim_executor" --source-root "$ROOT/dag" --source-root "$ROOT/src/v2" --plan-entry src/v2/workflow/ci_floor_plan.dag --plan-function gunbc_ci_floor_plan --notice-title "v2 claim corpus"
env:
GUNBC_FLOOR_PHASE_JOURNAL: target/floor-phase-journal.tsv
timeout-minutes: 65
timeout-minutes: 75
- name: Floor cgroup peak post-read (calibration; survives a killed floor)
run: |
# 🟡 dissolve-on: ci_floor_phase_journal_if — bounded foreign-executor (GitHub Actions run:) shell transport for exactly four journal leaves: FileExists, header log, prefixed file read, and absent log. If/else control flow is already v2.std.orchestration intent; only those leaves remain medium-as-string Run.command values. DISSOLVES WHEN bash-emit (#5828 / ROADMAP shell-effectplan-to-bash / shell→intent Phase 2) binds typed filesystem observation plus diagnostic-log operations through host_effect_apply, so ci_floor_phase_journal_if contains no opaque shell command text.
Expand Down
4 changes: 2 additions & 2 deletions dag/gunbc/ci_spec.dag
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ data gunbc_ci_ordinary_floor_budget_minutes: Minute = minute(count: 55)

data gunbc_ci_admission_postcondition_budget_minutes: Minute = minute(count: 5)

data gunbc_ci_walk_overhead_allowance_minutes: Minute = minute(count: 5)
data gunbc_ci_walk_overhead_allowance_minutes: Minute = minute(count: 15)

fn gunbc_ci_workflow_wrapper_budget_minutes() -> Minute {
minute(count: minute_count(m: gunbc_ci_ordinary_floor_budget_minutes) + minute_count(m: gunbc_ci_admission_postcondition_budget_minutes) + minute_count(m: gunbc_ci_walk_overhead_allowance_minutes))
}

data gunbc_ci_two_population_budget_note: String = "The CI walk owns two disjoint wall allowances: 55 minutes for ordinary batches and 5 minutes for green-only admission postconditions. WalkPlan carries both so claim_executor, not the outer runner, prevents ordinary work from consuming the admission allowance. The wall spent OUTSIDE both populations — the pre-walk capture subprocess, plan resolve, finalization and receipt writes, phase-journal flushes — is neither ordinary nor postcondition work, so the GitHub step wrapper reserves the named gunbc_ci_walk_overhead_allowance_minutes term for it rather than silently letting a slow pre-walk eat the ordinary allowance from the outside (review 47517; the two watchdogs bound their own populations, and the wrapper is strictly the three-term sum, 65 minutes today). A budget refusal is located to its population inside the executor; a wrapper kill with both populations under budget is located to the overhead term."
data gunbc_ci_two_population_budget_note: String = "The CI walk owns two disjoint wall allowances: 55 minutes for ordinary batches and 5 minutes for green-only admission postconditions. WalkPlan carries both so claim_executor, not the outer runner, prevents ordinary work from consuming the admission allowance. The wall spent OUTSIDE both populations — the pre-walk capture subprocess, plan resolve, finalization and receipt writes, phase-journal flushes — is neither ordinary nor postcondition work, so the GitHub step wrapper reserves the named gunbc_ci_walk_overhead_allowance_minutes term for it rather than silently letting a slow pre-walk eat the ordinary allowance from the outside (review 47517; the two watchdogs bound their own populations, and the wrapper is strictly the three-term sum, 75 minutes today). A budget refusal is located to its population inside the executor; a wrapper kill with both populations under budget is located to the overhead term. The overhead term was raised 5→15 minutes (2026-08-05): measured CI floor pre-walk plus eager compile-clean install routinely exceeds 10 minutes before the ordinary population clock starts, so a 5-minute allowance let the GitHub step wrapper kill the job while ordinary budget remained — silent wrapper kill, not ordinary exhaustion."

data gunbc_ci_floor_batch_stop_policy_note: String = "Floor batch stop policy (operator ruling 2026-07-22, fail-fast lane): claim_executor's walk halt is event-scoped so cheap-gate-early reorder does not truncate main's ledger. pull_request → StopBeforeDependents (fail-fast: a cheap-gate red stops before compile/corpus). push (main) and schedule (falsifier) → FullLedger (record batch failure and continue; exit non-zero at end). Unknown/unrecognized events default to FullLedger — never silently stop-early and lose ledger (the absorbing fallback). Authority: gunbc_ci_floor_batch_stop_policy_for_github_event in v2.workflow.ci_floor_plan; consumer: claim_executor.rs run_walk (see gunbc_ci_floor_batch_stop_policy_claim_executor_seed_note)."

Expand Down
45 changes: 45 additions & 0 deletions dag/gunbc/v1_interpreter_primitive_surface.dag
Original file line number Diff line number Diff line change
Expand Up @@ -1040,6 +1040,51 @@ fn v1_interpreter_authored_roster_arms() -> List<InterpreterPrimitiveDispatchArm
dispatch_emit_site: EvalBuiltinInnerSite,
enumeration: AuthoredInRoster,
},
InterpreterPrimitiveDispatchArm {
arm: InterpreterPrimitiveArmId { identity: "free_call.consume_floor_compile_clean_gate_failure_detail" },
form: FreeCall,
authored_spelling: "consume_floor_compile_clean_gate_failure_detail",
realization_module: "v1_interpreter",
dispatch_symbol: "eval_builtin_inner",
dispatch_emit_site: EvalBuiltinInnerSite,
enumeration: AuthoredInRoster,
},
InterpreterPrimitiveDispatchArm {
arm: InterpreterPrimitiveArmId { identity: "free_call.record_regen_verify_gate_failure_detail" },
form: FreeCall,
authored_spelling: "record_regen_verify_gate_failure_detail",
realization_module: "v1_interpreter",
dispatch_symbol: "eval_builtin_inner",
dispatch_emit_site: EvalBuiltinInnerSite,
enumeration: AuthoredInRoster,
},
InterpreterPrimitiveDispatchArm {
arm: InterpreterPrimitiveArmId { identity: "free_call.consume_regen_verify_gate_failure_detail" },
form: FreeCall,
authored_spelling: "consume_regen_verify_gate_failure_detail",
realization_module: "v1_interpreter",
dispatch_symbol: "eval_builtin_inner",
dispatch_emit_site: EvalBuiltinInnerSite,
enumeration: AuthoredInRoster,
},
InterpreterPrimitiveDispatchArm {
arm: InterpreterPrimitiveArmId { identity: "free_call.record_generated_artifact_drift_gate_failure_detail" },
form: FreeCall,
authored_spelling: "record_generated_artifact_drift_gate_failure_detail",
realization_module: "v1_interpreter",
dispatch_symbol: "eval_builtin_inner",
dispatch_emit_site: EvalBuiltinInnerSite,
enumeration: AuthoredInRoster,
},
InterpreterPrimitiveDispatchArm {
arm: InterpreterPrimitiveArmId { identity: "free_call.consume_generated_artifact_drift_gate_failure_detail" },
form: FreeCall,
authored_spelling: "consume_generated_artifact_drift_gate_failure_detail",
realization_module: "v1_interpreter",
dispatch_symbol: "eval_builtin_inner",
dispatch_emit_site: EvalBuiltinInnerSite,
enumeration: AuthoredInRoster,
},
InterpreterPrimitiveDispatchArm {
arm: InterpreterPrimitiveArmId { identity: "free_call.witness_compile_clean_cli_floor_verdicts_agree" },
form: FreeCall,
Expand Down
5 changes: 5 additions & 0 deletions dag/std/primitives.dag
Original file line number Diff line number Diff line change
Expand Up @@ -597,6 +597,11 @@ fn builtin_registry_surface_names() -> List<String> {
"witness_layer_roots_compile_clean_check",
"witness_layer_roots_compile_clean_emit_check",
"consume_floor_compile_clean_gate_verdict",
"consume_floor_compile_clean_gate_failure_detail",
"record_regen_verify_gate_failure_detail",
"consume_regen_verify_gate_failure_detail",
"record_generated_artifact_drift_gate_failure_detail",
"consume_generated_artifact_drift_gate_failure_detail",
"witness_compile_clean_cli_floor_verdicts_agree",
"test_migration_debt_module_count",
"test_migration_debt_total_loc",
Expand Down
2 changes: 1 addition & 1 deletion dag/test/claim/ci_workflow_witness_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ test fn ci_workflow_witness_holds() -> Bool {
&& ci_job_backstop_dropped_the_selection_control_term()
&& (minute_count(m: gunbc_ci_ordinary_floor_budget_minutes) == 55)
&& (minute_count(m: gunbc_ci_admission_postcondition_budget_minutes) == 5)
&& (minute_count(m: gunbc_ci_walk_overhead_allowance_minutes) == 5)
&& (minute_count(m: gunbc_ci_walk_overhead_allowance_minutes) == 15)
&& (minute_count(m: gunbc_ci_workflow_wrapper_budget_minutes()) == minute_count(m: gunbc_ci_ordinary_floor_budget_minutes) + minute_count(m: gunbc_ci_admission_postcondition_budget_minutes) + minute_count(m: gunbc_ci_walk_overhead_allowance_minutes))
&& (gunbc_ci_workflow_wrapper_timeout_minutes == minute_count(m: gunbc_ci_workflow_wrapper_budget_minutes()))
}
108 changes: 108 additions & 0 deletions dag/test/claim/floor_gate_failure_receipt_witness_test.dag
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
module test.claim.floor_gate_failure_receipt_witness

import std.process { ProcessExit, ExitSuccess, exit_failure }
import gunbc.test_module_hygiene { failure_receipt_companion, Optional, Present }
import gunbc.generated_artifact_assessment {
GeneratedArtifactObservation, GeneratedArtifactObserved, assess_generated_artifact_population,
first_failing_diagnostic_path
}
import gunbc.generated_artifact { CiYamlArtifact, GitignoreArtifact }
import tools.dag_compile_clean_gate { dag_compile_clean_failure_reason }
import tools.generated_artifact_gate { generated_artifact_drift_failure_reason }
import tools.regen_verify_transport { regen_verify_failure_detail }
import tools.regen_verify_gate { regen_verify_failure_reason }

data witness_note: String = "Floor gate failure-receipt companions must name located reasons on Bool(false), not only returned Bool(false). Controls pin the naming convention via gunbc.test_module_hygiene.failure_receipt_companion and the reason projection helpers without re-running the expensive live gates."

data planted_regen_stderr: String = "Stage0 is stale: 1 generated file(s) differ from fresh self-compile.\nChanged generated file(s): v1_compiler_emit_rust.rs\n"

data planted_artifact_path: String = ".github/workflows/ci.yml"

fn constructed_drift_observation(path: String) -> GeneratedArtifactObserved {
GeneratedArtifactObserved {
artifact: CiYamlArtifact,
path: path,
generated_content: "expected bytes",
committed_content: concat("expected bytes", "\n# drift"),
extra_validation: true
}
}

test fn regen_verify_failure_detail_names_drifted_file_holds() -> Bool {
string_contains(
s: regen_verify_failure_detail(stdout: "regen_divergence_count=1\n", stderr: planted_regen_stderr),
pattern: "v1_compiler_emit_rust.rs"
)
}

test fn regen_verify_failure_detail_refuses_empty_capture_holds() -> Bool {
string_contains(
s: regen_verify_failure_detail(stdout: "", stderr: ""),
pattern: "no diagnostic output"
)
}

test fn regen_verify_failure_reason_empty_only_on_success() -> Bool {
regen_verify_failure_reason(exit: ExitSuccess) == ""
}

test fn generated_artifact_drift_verdict_names_planted_path_holds() -> Bool {
let observations = [
constructed_drift_observation(path: planted_artifact_path),
GeneratedArtifactObserved {
artifact: GitignoreArtifact,
path: ".gitignore",
generated_content: "same",
committed_content: "same",
extra_validation: true
}
]
string_contains(
s: first_failing_diagnostic_path(
expected: [CiYamlArtifact, GitignoreArtifact],
observations: observations
),
pattern: planted_artifact_path
)
&& !assess_generated_artifact_population(
expected: [CiYamlArtifact, GitignoreArtifact],
observations: observations
)
}

test fn generated_artifact_drift_failure_reason_empty_only_on_success() -> Bool {
generated_artifact_drift_failure_reason(exit: ExitSuccess) == ""
&& string_contains(
s: generated_artifact_drift_failure_reason(
exit: exit_failure(
reason: concat("generated-artifact drift/validation failed: ", planted_artifact_path)
)
),
pattern: planted_artifact_path
)
}

test fn dag_compile_clean_failure_reason_empty_only_on_success() -> Bool {
dag_compile_clean_failure_reason(exit: ExitSuccess) == ""
&& string_contains(
s: dag_compile_clean_failure_reason(
exit: exit_failure(reason: "compile-clean: unresolved import in dag/test/example.dag")
),
pattern: "dag/test/example.dag"
)
}

test fn floor_gate_failure_receipt_companion_names_holds() -> Bool {
match failure_receipt_companion(function: "dag_compile_clean_gate_passes") {
Present { value: companion } => companion == "dag_compile_clean_gate_failure_receipt"
_ => false
}
&& match failure_receipt_companion(function: "generated_artifact_drift_gate_passes") {
Present { value: companion } => companion == "generated_artifact_drift_gate_failure_receipt"
_ => false
}
&& match failure_receipt_companion(function: "regen_verify_gate_passes") {
Present { value: companion } => companion == "regen_verify_gate_failure_receipt"
_ => false
}
}
13 changes: 13 additions & 0 deletions dag/tools/dag_compile_clean_gate.dag
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@ module tools.dag_compile_clean_gate
import std.process { ProcessExit, ExitSuccess, exit_failure }
import tools.dag_compile_clean_transport { run_clean_tree_compile }

data dag_compile_clean_failure_receipt_note: String = "The loudness half: the floor witness collapses this gate's ProcessExit to Bool via tools.ci_gates.exit_ok, so compile-clean reds reported only returned Bool(false). The gate consumes the executor's one in-run compile receipt; the failure-receipt companion projects the same receipt's located diagnostic without a second compile."

fn dag_compile_clean_failure_reason(exit: ProcessExit) -> String {
match exit {
ExitSuccess => ""
ExitFailure { code: _, reason: reason } => reason
}
}

func run_dag_compile_clean_gate_body() -> ProcessExit {
if run_clean_tree_compile() {
ExitSuccess
Expand All @@ -17,6 +26,10 @@ func run_dag_compile_clean_gate() -> ProcessExit {
run_dag_compile_clean_gate_body()
}

func dag_compile_clean_failure_receipt() -> String {
consume_floor_compile_clean_gate_failure_detail()
}

func main() -> ProcessExit {
run_dag_compile_clean_gate_body()
}
17 changes: 16 additions & 1 deletion dag/tools/floor_effect_gate_witness.dag
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import tools.extdeps_scope_placement_gate {
scope_placement_failure_reason,
scope_placement_membership_verdict,
}
import tools.dag_compile_clean_gate { dag_compile_clean_failure_receipt }
import tools.generated_artifact_gate { generated_artifact_drift_failure_receipt }
import tools.regen_verify_gate { regen_verify_failure_receipt }
import gunbc.test_module_hygiene {
failure_receipt_companion,
}
Expand All @@ -22,7 +25,7 @@ data extdeps_scope_placement_gate_passes_name: String = "extdeps_scope_placement

data scope_placement_gate_loudness_seed_probe_passes_name: String = "scope_placement_gate_loudness_seed_probe_passes"

data floor_gate_failure_receipt_note: String = "claim_executor derives a failure-receipt companion from a Bool witness's own name and evaluates it in THIS entry's context, so the companion must be declared here beside the witness it explains — not only in the gate module that builds the reason. Naming is mechanical: <witness>_passes or <witness>_holds yields <witness>_failure_receipt, delegated to gunbc.test_module_hygiene.failure_receipt_companion (the single authority; cli_run::failure_receipt_companion routes through the same module). scope_placement_gate_loudness_seed_probe_* is a hermetic always-false _passes witness + failure_receipt companion enrolled solely so dag/test/claim/extdeps_scope_placement_gate_loudness_witness_test.dag can execute production seed_runner_bool_false_failure_detail against a located receipt without re-running the wet placement gate; it must stay OFF CiSpec.witness_entries and OFF any future entry-scoped *_passes auto-discovery (auto-enrollment would red CI). Mute frontier (identity join on this entry, 2026-08-05): eight _passes witnesses, two _failure_receipt companions (extdeps_scope_placement_gate_failure_receipt, scope_placement_gate_loudness_seed_probe_failure_receipt; _companion_name helpers are not companions); two companions join gates — extdeps_scope_placement_gate (production, landed gunbc#7644) and scope_placement_gate_loudness_seed_probe (hermetic test probe, not production). Six production gates still return bare returned Bool(false) on refusal with no located receipt: cheap_claim_pool_gate, dag_compile_clean_gate, emit_host_gate, extdeps_external_authority_gate, generated_artifact_drift_gate, regen_verify_gate. Dissolution trigger: a gate leaves this frontier when this entry declares its <witness>_failure_receipt companion beside the _passes witness. Frontier counts are hand-authored prose debt — dissolve-on: derived projection from this entry's declarations (see loudness_witness_note sequencing note)."
data floor_gate_failure_receipt_note: String = "claim_executor derives a failure-receipt companion from a Bool witness's own name and evaluates it in THIS entry's context, so the companion must be declared here beside the witness it explains — not only in the gate module that builds the reason. Naming is mechanical: <witness>_passes or <witness>_holds yields <witness>_failure_receipt, delegated to gunbc.test_module_hygiene.failure_receipt_companion (the single authority; cli_run::failure_receipt_companion routes through the same module). scope_placement_gate_loudness_seed_probe_* is a hermetic always-false _passes witness + failure_receipt companion enrolled solely so dag/test/claim/extdeps_scope_placement_gate_loudness_witness_test.dag can execute production seed_runner_bool_false_failure_detail against a located receipt without re-running the wet placement gate; it must stay OFF CiSpec.witness_entries and OFF any future entry-scoped *_passes auto-discovery (auto-enrollment would red CI). Mute frontier (identity join on this entry, 2026-08-05): eight _passes witnesses, five _failure_receipt companions (extdeps_scope_placement_gate_failure_receipt, scope_placement_gate_loudness_seed_probe_failure_receipt, dag_compile_clean_gate_failure_receipt, generated_artifact_drift_gate_failure_receipt, regen_verify_gate_failure_receipt; _companion_name helpers are not companions). Three production gates still return bare returned Bool(false) on refusal with no located receipt: cheap_claim_pool_gate, emit_host_gate, extdeps_external_authority_gate. Dissolution trigger: a gate leaves this frontier when this entry declares its <witness>_failure_receipt companion beside the _passes witness. Frontier counts are hand-authored prose debt — dissolve-on: derived projection from this entry's declarations (see loudness_witness_note sequencing note)."

fn extdeps_scope_placement_gate_failure_receipt_companion_name() -> String {
match failure_receipt_companion(function: extdeps_scope_placement_gate_passes_name) {
Expand Down Expand Up @@ -71,6 +74,18 @@ func scope_placement_gate_loudness_seed_probe_failure_receipt() -> String {
)
}

func dag_compile_clean_gate_failure_receipt() -> String {
dag_compile_clean_failure_receipt()
}

func generated_artifact_drift_gate_failure_receipt() -> String {
generated_artifact_drift_failure_receipt()
}

func regen_verify_gate_passes() -> Bool {
tools.ci_gates.exit_ok(e: run_spec_gate(g: RegenVerifyGate))
}

func regen_verify_gate_failure_receipt() -> String {
regen_verify_failure_receipt()
}
Loading
Loading