diff --git a/.github/workflows/falsifier.yml b/.github/workflows/falsifier.yml index c33563918b8..2785b882055 100644 --- a/.github/workflows/falsifier.yml +++ b/.github/workflows/falsifier.yml @@ -133,7 +133,7 @@ jobs: - name: native-cache cold control (warm-tier admission counterpart) run: | ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd) - "$ROOT/target/release/claim_executor" --source-root dag --source-root src/v2 --plan-entry src/v2/workflow/ci_floor_plan.dag --plan-function gunbc_falsifier_native_cache_cold_batches + "$ROOT/target/release/claim_executor" --source-root dag --source-root src/v2 --plan-entry src/v2/workflow/ci_floor_plan.dag --plan-function gunbc_falsifier_native_cache_cold_plan env: GUNBC_CI_NATIVE_CACHE_COLD_CONTROL: 1 timeout-minutes: 30 diff --git a/dag/gunbc/ci_spec.dag b/dag/gunbc/ci_spec.dag index d6e0a7bc7f4..9ceff5ec988 100644 --- a/dag/gunbc/ci_spec.dag +++ b/dag/gunbc/ci_spec.dag @@ -16,6 +16,11 @@ import gunbc.ci_layer_roots { } import gunbc.cli_invoke { claim_executor_run_plan_shell, + PlanFunction, + CiFloorPlan, + CiRegenFloorPlan, + CiPlanArtifactPlan, + plan_function_name, claim_executor_verify_artifacts_shell, gunbc_run_shell } @@ -361,12 +366,13 @@ fn git_fetch_script(policy: DiffPolicy) -> String { } data floor_plan_entry: String = "src/v2/workflow/ci_floor_plan.dag" -data floor_plan_function: String = "gunbc_ci_floor_plan" -data plan_artifact_plan_function: String = "gunbc_ci_plan_artifact_plan" -data regen_floor_plan_function: String = "gunbc_ci_regen_floor_plan" +data plan_function_string_projection_note: String = "These two are the NAME PROJECTION of gunbc.cli_invoke PlanFunction, not a second authority. The coproduct is where the roster is closed; these exist because the floor's own policy predicates (v2.workflow.ci_floor_plan gunbc_ci_floor_plan_uses_batch_stop_policy, gunbc_floor_arm_time_budget_refusal_applies) compare a plan identity as a String, and the claim_executor side receives it as an argv token. Deriving them through plan_function_name keeps one authority (§3): a rename edits the coproduct's match arm and both the argv and these comparisons follow, where three independent literals were exactly the fork that let the falsifier's fifth target drift. They delete when those predicates take a PlanFunction instead of a String." +data floor_plan_function: String = plan_function_name(p: CiFloorPlan) +data plan_artifact_plan_function: String = plan_function_name(p: CiPlanArtifactPlan) -fn scheduler_invoke_with(spec: CiSpec, plan_function: String) -> String { + +fn scheduler_invoke_with(spec: CiSpec, plan_function: PlanFunction) -> String { claim_executor_run_plan_shell( source_roots: witness_layer_roots, plan_entry: floor_plan_entry, @@ -377,7 +383,7 @@ fn scheduler_invoke_with(spec: CiSpec, plan_function: String) -> String { } fn scheduler_invoke(spec: CiSpec) -> String { - scheduler_invoke_with(spec: spec, plan_function: floor_plan_function) + scheduler_invoke_with(spec: spec, plan_function: CiFloorPlan) } fn gunbc_ci_floor_only_script(spec: CiSpec) -> String { @@ -428,7 +434,7 @@ fn gunbc_ci_regen_floor_only_script(spec: CiSpec) -> String { concat(git_fetch_script(policy: spec.diff_policy), "\n"), concat( concat(ci_regen_floor_skip_shortcut_script(), "\n"), - concat(scheduler_invoke_with(spec: spec, plan_function: regen_floor_plan_function), "\n") + concat(scheduler_invoke_with(spec: spec, plan_function: CiRegenFloorPlan), "\n") ) ) ) diff --git a/dag/gunbc/cli_invoke.dag b/dag/gunbc/cli_invoke.dag index b812444c7b0..a6524c844fb 100644 --- a/dag/gunbc/cli_invoke.dag +++ b/dag/gunbc/cli_invoke.dag @@ -53,15 +53,34 @@ fn claim_executor_notice_title_normalized(notice_title: String?) -> String? { } } +type PlanFunction + = CiFloorPlan + | CiRegenFloorPlan + | CiPlanArtifactPlan + | FalsifierPlan + | FalsifierNativeCacheColdPlan + +data plan_function_closed_roster_note: String = "THE CLOSED ROSTER OF PRODUCTION ClaimExecutor PLAN TARGETS, and it is a coproduct rather than a String parameter because a String is what let a plan target escape a migration that claimed to cover all of them. plan_function was an unconstrained String crossing the modeled boundary, so plan identity was carried by an argv token nothing could check: gunbc.falsifier_workflow passed the literal \"gunbc_falsifier_native_cache_cold_batches\", derived from no authority, and the 2026-07-30 WalkPlan rename — whose completeness argument was a hand-maintained count of four — could not reach it. The executor then correctly refused the stale shape on every falsifier run that armed that step.\n\nWHAT THE TYPE BUYS, stated as the guarantee rather than the intent: an inline string literal at a plan_function argument is now a TYPE ERROR, so the class that produced this incident is unwritable rather than validated (§5 construction-over-validation). The roster is closed by the coproduct, so a new production plan target cannot be authored without adding a variant, and every exhaustive match over PlanFunction — plan_function_name here, plan_variant_is_walk_plan_shaped in v2.test.claim.ci_floor_plan_witness — fails to compile until that variant is handled.\n\nTHE LIMIT OF THAT, corrected after review 46883 rejected the stronger claim this paragraph used to make. Compile-time forces an ARM TO EXIST for every variant; it does not force that arm to be EXECUTED by any witness, because the witness roster is a hand-authored list. So the guarantee is 'no target can exist unhandled', NOT 'the target set and the proof set are the same set'. The census is narrowed, not abolished, and saying otherwise would repeat the completeness failure this type exists to prevent.\n\nWHAT IT DOES NOT BUY, named rather than implied: the variant-to-plan-function-value pairing in the witness is still hand-authored, because resolving an argv token to a declaration needs the containment SymbolIndex the namespace lane is building — the type closes WHICH targets exist, not that each names a function whose declared return is WalkPlan. Dissolve-on: a typed declaration reference (std.decl_ref.DeclarationRef over a resolved plan symbol) replaces the name projection, at which point plan_function_name and the witness's hand pairing both delete." + +fn plan_function_name(p: PlanFunction) -> String { + match p { + CiFloorPlan => "gunbc_ci_floor_plan" + CiRegenFloorPlan => "gunbc_ci_regen_floor_plan" + CiPlanArtifactPlan => "gunbc_ci_plan_artifact_plan" + FalsifierPlan => "gunbc_falsifier_plan" + FalsifierNativeCacheColdPlan => "gunbc_falsifier_native_cache_cold_plan" + } +} + fn claim_executor_run_plan_transport_argv( source_roots: List, plan_entry: String, - plan_function: String, + plan_function: PlanFunction, notice_title: String? ) -> List { let base = concat( source_root_transport_argv(roots: source_roots), - ["--plan-entry", plan_entry, "--plan-function", plan_function] + ["--plan-entry", plan_entry, "--plan-function", plan_function_name(p: plan_function)] ) match claim_executor_notice_title_normalized(notice_title: notice_title) { Present { value: title } => concat(base, ["--notice-title", title]) @@ -101,7 +120,7 @@ fn claim_executor_notice_title_shell_suffix(notice_title: String?) -> String { fn claim_executor_run_plan_shell( source_roots: List, plan_entry: String, - plan_function: String, + plan_function: PlanFunction, notice_title: String?, rooted: Bool ) -> String { @@ -115,7 +134,7 @@ fn claim_executor_run_plan_shell( concat( concat(claim_executor_bin_shell(), flags), concat( - concat(concat(" --plan-entry ", plan_entry), concat(" --plan-function ", plan_function)), + concat(concat(" --plan-entry ", plan_entry), concat(" --plan-function ", plan_function_name(p: plan_function))), notice ) ) diff --git a/dag/gunbc/cli_services.dag b/dag/gunbc/cli_services.dag index 158fd24c7b2..010946ff6ad 100644 --- a/dag/gunbc/cli_services.dag +++ b/dag/gunbc/cli_services.dag @@ -2,6 +2,7 @@ module gunbc.cli_services import std.types { FilePath, String } import gunbc.cli_invoke { + PlanFunction, claim_executor_run_plan_transport_argv, claim_executor_verify_artifacts_transport_argv, gunbc_run_transport_argv @@ -52,7 +53,7 @@ service claim_executor.Executor { bin_path: FilePath source_roots: List plan_entry: String - plan_function: String + plan_function: PlanFunction notice_title: String? } output { diff --git a/dag/gunbc/falsifier_workflow.dag b/dag/gunbc/falsifier_workflow.dag index 3c7f323e77e..074d68ce3a6 100644 --- a/dag/gunbc/falsifier_workflow.dag +++ b/dag/gunbc/falsifier_workflow.dag @@ -23,12 +23,15 @@ import gunbc.floor_component_receipt { floor_component_receipt_artifact_name } import gunbc.ci_runner_target { gunbc_ci_selected_runner_spec } -import gunbc.ci_spec { plan_artifact_plan_function } -import gunbc.merge_admission_produce { ci_repo_root_shell } -import gunbc.ci_layer_roots { witness_layer_roots } import gunbc.cli_invoke { + CiPlanArtifactPlan, + FalsifierPlan, + FalsifierNativeCacheColdPlan, + plan_function_name, claim_executor_run_plan_shell } +import gunbc.merge_admission_produce { ci_repo_root_shell } +import gunbc.ci_layer_roots { witness_layer_roots } import extdeps.languages.yaml.emit { serialize_yaml } import extdeps.languages.yaml.gha_workflow { project_workflow_to_yaml } import std.types { NonEmptyStr } @@ -71,7 +74,7 @@ fn gunbc_falsifier_step_timeout_basis_is_measured_not_composed() -> Bool { data gunbc_falsifier_step_timeout_note: String = "120 -> 170 (2026-07-11, run 29135185172 receipt): the first corpus-reaching cold run was TIME-killed at the 120-min step ceiling with the corpus incomplete (1970 rows, closure 1396 modules, width 1) and floor peak 16146612224 bytes against a 16GiB slot budget, still growing - so 120 censored the measurement without bounding anything real (the memory cap is the true wall). 170 lets a nightly run reach either completion (exact-labeled receipt) or the cap kill (censored-labeled receipt); both are the falsifier doing its measurement job, and the job backstop DERIVES from this value so it stretches in step. Revisit down when the resolver graph-major module split (S2a move 2) shrinks cold-resolve wall and residency." -data falsifier_plan_function: String = "gunbc_falsifier_plan" +data falsifier_plan_function: String = plan_function_name(p: FalsifierPlan) fn falsifier_invoke() -> String { concat( @@ -79,7 +82,7 @@ fn falsifier_invoke() -> String { claim_executor_run_plan_shell( source_roots: witness_layer_roots, plan_entry: "src/v2/workflow/ci_floor_plan.dag", - plan_function: falsifier_plan_function, + plan_function: FalsifierPlan, notice_title: Absent, rooted: false ) @@ -115,7 +118,7 @@ fn compile_clean_cold_control_invoke() -> String { claim_executor_run_plan_shell( source_roots: witness_layer_roots, plan_entry: "src/v2/workflow/ci_floor_plan.dag", - plan_function: plan_artifact_plan_function, + plan_function: CiPlanArtifactPlan, notice_title: Absent, rooted: false ) @@ -138,6 +141,8 @@ fn compile_clean_cold_control_step() -> Step { } } +data falsifier_native_cache_cold_plan_target_note: String = "THE STEP WHOSE PLAN TARGET ESCAPED THE #7470 MIGRATION, kept as the receipt for why the target is now a typed variant instead of an argv token. Every other consumer derived its plan name from a constant, so the 2026-07-30 WalkPlan rename reached all four automatically; this step alone passed the inline literal \"gunbc_falsifier_native_cache_cold_batches\", derived from nothing, and was left behind returning a bare List>. The executor's strict parser then refused it on every one of the 8 falsifier runs that armed this step (0 successes), and it read as intermittent only because the step is skipped whenever the falsifier step fails first.\n\nThe first repair here added a naming constant beside the other four. That was still validation — it made the rename reach this site but left the next author free to type a fresh literal. The constant was therefore DELETED in the same change that introduced gunbc.cli_invoke PlanFunction: an inline literal at this argument is now a type error, so the roster is closed by construction and a String projection with no consumer would be exactly the inert carrier §2 forbids. Dissolution-on-climb (§4b): the wall replaces the lower-rung machinery rather than accumulating beside it." + data gunbc_falsifier_native_cache_cold_control_timeout_minutes: Int = 30 data gunbc_falsifier_native_cache_cold_control_note: String = "Native-cache cold control (P6 durable-cache rail, 2026-07-21): the nightly Wet emit-on-demand/self-host receipt batch re-executed with GUNBC_CI_NATIVE_CACHE_COLD_CONTROL=1, which makes emit_host_run_transport_cached ignore every .native_ready marker — the full emit+cargo+run chain runs cold on the falsifier cadence while the main falsifier_step's run of the same batch stays warm (the warm-rate receipt the per-PR enrollment decision reads). Widen-to-more-checking control arm, not an escape hatch: the env can only force the transport to do MORE work, never skip it. Mirrors compile_clean_cold_control_step." @@ -148,7 +153,7 @@ fn native_cache_cold_control_invoke() -> String { claim_executor_run_plan_shell( source_roots: witness_layer_roots, plan_entry: "src/v2/workflow/ci_floor_plan.dag", - plan_function: "gunbc_falsifier_native_cache_cold_batches", + plan_function: FalsifierNativeCacheColdPlan, notice_title: Absent, rooted: false ) diff --git a/dag/test/claim/gunbc_invoke_witness_test.dag b/dag/test/claim/gunbc_invoke_witness_test.dag index 5973462950d..3fef0e5887d 100644 --- a/dag/test/claim/gunbc_invoke_witness_test.dag +++ b/dag/test/claim/gunbc_invoke_witness_test.dag @@ -1,6 +1,7 @@ module test.claim.gunbc_invoke_witness import gunbc.cli_invoke { + CiFloorPlan, claim_executor_run_plan_shell, claim_executor_run_plan_transport_argv, claim_executor_verify_artifacts_shell, @@ -53,7 +54,7 @@ test fn gunbc_invoke_scheduler_matches_modeled_shell_holds() -> Bool { let modeled = claim_executor_run_plan_shell( source_roots: witness_layer_roots, plan_entry: "src/v2/workflow/ci_floor_plan.dag", - plan_function: "gunbc_ci_floor_plan", + plan_function: CiFloorPlan, notice_title: Present { value: gunbc_ci_spec.notice_title }, rooted: true ) @@ -79,7 +80,7 @@ test fn gunbc_invoke_empty_notice_title_omits_flag_holds() -> Bool { let shell = claim_executor_run_plan_shell( source_roots: witness_layer_roots, plan_entry: "src/v2/workflow/ci_floor_plan.dag", - plan_function: "gunbc_ci_floor_plan", + plan_function: CiFloorPlan, notice_title: Present { value: "" }, rooted: true ) @@ -94,14 +95,14 @@ test fn gunbc_invoke_transport_argv_empty_notice_title_omits_flag_holds() -> Boo let argv = claim_executor_run_plan_transport_argv( source_roots: witness_layer_roots, plan_entry: "src/v2/workflow/ci_floor_plan.dag", - plan_function: "gunbc_ci_floor_plan", + plan_function: CiFloorPlan, notice_title: Present { value: "" } ) !transport_argv_contains_flag(argv: argv, flag: "--notice-title") && claim_executor_run_plan_transport_argv( source_roots: witness_layer_roots, plan_entry: "src/v2/workflow/ci_floor_plan.dag", - plan_function: "gunbc_ci_floor_plan", + plan_function: CiFloorPlan, notice_title: Absent ) == argv } diff --git a/src/v2/test/claim/ci_floor_plan_witness_test.dag b/src/v2/test/claim/ci_floor_plan_witness_test.dag index 3684d9a6660..9d820a8d1b3 100644 --- a/src/v2/test/claim/ci_floor_plan_witness_test.dag +++ b/src/v2/test/claim/ci_floor_plan_witness_test.dag @@ -3,6 +3,17 @@ module v2.test.claim.ci_floor_plan_witness import std.realization { RunnableDiscoveryBatch, } +import gunbc.cli_invoke { + PlanFunction, + CiFloorPlan, + CiRegenFloorPlan, + CiPlanArtifactPlan, + FalsifierPlan, + FalsifierNativeCacheColdPlan, + plan_function_name +} +import gunbc.ci_yaml_emit { expected_ci_yml } +import gunbc.falsifier_workflow { expected_falsifier_yml } import v2.workflow.ci_floor_plan { gunbc_falsifier_ordinary_batches, gunbc_ci_floor_ordinary_batches, @@ -10,6 +21,7 @@ import v2.workflow.ci_floor_plan { gunbc_ci_regen_floor_plan, gunbc_ci_plan_artifact_plan, gunbc_falsifier_plan, + gunbc_falsifier_native_cache_cold_plan, floor_schedule_for, corpus_runnable_for, execution_corpus_runnable_for, corpus_witness_entries, execution_witness_entries, @@ -704,3 +716,52 @@ test fn plan_artifact_plan_carries_no_finalization() -> Bool { test fn falsifier_plan_carries_no_finalization() -> Bool { plan_carries_no_finalization(plan: gunbc_falsifier_plan()) } + +data falsifier_native_cache_cold_plan_row_note: String = "The FIFTH plan function, absent from this roster until 2026-08-01 — and its absence is the point. walk_plan_uniformity_note names these rows as the enforcement for the WalkPlan shape precisely because the typechecker does not check a declared return type against a body, so a plan function missing from THIS roster has no enforcement at all. gunbc_falsifier_native_cache_cold_plan was missed by the #7470 rename, kept returning a bare List>, and the executor's strict parser refused it on all 8 falsifier runs that reached the native-cache cold control step. Nothing here could red on that, because the roster counted four." + +test fn falsifier_native_cache_cold_plan_carries_no_finalization() -> Bool { + plan_carries_no_finalization(plan: gunbc_falsifier_native_cache_cold_plan()) +} + +data plan_roster_exhaustiveness_note: String = "WHAT THIS ROW ENFORCES, AND WHAT IT DOES NOT — the second half corrected after review 46883 caught this note claiming a guarantee it does not deliver, which is the rung-inflation failure DESIGN 4b names and is worth more than a quiet edit because the overclaim repeated the very completeness failure this change exists to remove.\n\nWHAT IS ENFORCED. plan_variant_is_walk_plan_shaped matches over gunbc.cli_invoke PlanFunction, the only way to name a plan target at claim_executor_run_plan_shell. Adding a sixth variant makes that match non-exhaustive, so this file STOPS COMPILING until the new target is given an arm. That is real and it is compile-time.\n\nWHAT IS NOT ENFORCED, stated plainly because an earlier revision of this note said the opposite. Compile-time forces the arm to EXIST; it does NOT force the arm to be EXECUTED. plan_target_roster below is hand-maintained, so an author who adds a variant, writes its arm, and does not extend the roster leaves that arm unrun while this row stays green — and because the typechecker does not check a declared return type against a body (floor_finalization_witness_note carries the probe), a malformed arm can sit there green. So the claim is NOT that the target set and the proof set are the same set by construction. The claim is narrower: every target IN THE ROSTER carries its declared finalization, and no target can exist without at least an arm.\n\nWHERE THE REAL TEETH ARE for the class that caused this incident: every_emitted_plan_target_names_its_variant and no_emitted_plan_target_retains_the_batches_shape read the GENERATED workflows, which are what CI actually executes. An emitted target is the only kind that can break CI, and those rows tie emissions to declared variants rather than to this roster.\n\nDissolve-on: variant enumeration over a closed coproduct (a total roster derived from the type rather than authored beside it), at which point plan_target_roster is derived, the gap above closes, and this paragraph deletes. Nothing in the language offers that today, so the residue is named rather than implied." + +fn plan_variant_is_walk_plan_shaped(p: PlanFunction) -> Bool { + match p { + CiFloorPlan => plan_declares_authority_count(p: gunbc_ci_floor_plan()) + CiRegenFloorPlan => plan_carries_no_finalization(plan: gunbc_ci_regen_floor_plan()) + CiPlanArtifactPlan => plan_carries_no_finalization(plan: gunbc_ci_plan_artifact_plan()) + FalsifierPlan => plan_carries_no_finalization(plan: gunbc_falsifier_plan()) + FalsifierNativeCacheColdPlan => plan_carries_no_finalization(plan: gunbc_falsifier_native_cache_cold_plan()) + } +} + +data plan_target_roster: List = [ + CiFloorPlan, + CiRegenFloorPlan, + CiPlanArtifactPlan, + FalsifierPlan, + FalsifierNativeCacheColdPlan +] + +fn every_plan_target_shaped(targets: List) -> Bool { + fold(targets, init: true, f: (acc, p) => acc && plan_variant_is_walk_plan_shaped(p: p)) +} + +test fn declared_plan_targets_are_walk_plan_shaped() -> Bool { + every_plan_target_shaped(targets: plan_target_roster) +} + +data plan_roster_control_placement_note: String = "THERE IS DELIBERATELY NO RUNTIME RED CONTROL FOR THE ROSTER ROW, and writing one would have been a lie worth naming. The obvious candidate — fold a deliberately-short target list and assert it refuses — is a tautology: every variant in the roster IS correctly shaped, so a short list returns true and the assertion would pass for the wrong reason, reporting coverage while discriminating nothing.\n\nThe compile-time half likewise has no Bool control: its failure mode is a build error, not a false value, so its control is a compile failure. Note the bound plan_roster_exhaustiveness_note states — that half forces an arm to exist, not to be executed — so neither the runtime nor the compile-time half is a universal-coverage claim, and this row must not be read as one.\n\nWhat DOES carry runtime teeth is per-variant and already enrolled: forked_declared_count_is_refused_by_the_same_predicate forks the floor declared count and requires the same predicate to refuse, and the three no-finalization rows carry the substitution control floor_finalization_witness_note describes. no_emitted_plan_target_retains_the_batches_shape is the regression control for THIS incident — it goes red if the pre-repair literal returns to either emitted artifact, and stays enrolled permanently rather than retiring now that the wall landed (4b: dissolution deletes the obsoleted production machinery, never the evidence)." + +test fn every_emitted_plan_target_names_its_variant() -> Bool { + string_contains(s: expected_ci_yml(), pattern: concat("--plan-function ", plan_function_name(p: CiFloorPlan))) + && string_contains(s: expected_ci_yml(), pattern: concat("--plan-function ", plan_function_name(p: CiRegenFloorPlan))) + && string_contains(s: expected_falsifier_yml(), pattern: concat("--plan-function ", plan_function_name(p: FalsifierPlan))) + && string_contains(s: expected_falsifier_yml(), pattern: concat("--plan-function ", plan_function_name(p: CiPlanArtifactPlan))) + && string_contains(s: expected_falsifier_yml(), pattern: concat("--plan-function ", plan_function_name(p: FalsifierNativeCacheColdPlan))) +} + +test fn no_emitted_plan_target_retains_the_batches_shape() -> Bool { + !string_contains(s: expected_ci_yml(), pattern: "--plan-function gunbc_falsifier_native_cache_cold_batches") + && !string_contains(s: expected_falsifier_yml(), pattern: "--plan-function gunbc_falsifier_native_cache_cold_batches") +} diff --git a/src/v2/workflow/ci_floor_plan.dag b/src/v2/workflow/ci_floor_plan.dag index b06d42cd1ea..6c43147bba3 100644 --- a/src/v2/workflow/ci_floor_plan.dag +++ b/src/v2/workflow/ci_floor_plan.dag @@ -976,8 +976,12 @@ fn gunbc_falsifier_native_cache_cold_batch() -> Runnable { } } -fn gunbc_falsifier_native_cache_cold_batches() -> List> { - [[gunbc_falsifier_native_cache_cold_batch()]] +fn gunbc_falsifier_native_cache_cold_plan() -> WalkPlan { + WalkPlan { + batches: [[gunbc_falsifier_native_cache_cold_batch()]], + finalization: NoFinalizationDeclared {}, + on_success_stages: [], + } } fn falsifier_batches_append_if_enrolled(acc: List>, enrolled: Bool, batch: Runnable) -> List> { @@ -1258,7 +1262,7 @@ fn gunbc_ci_plan_artifact_ordinary_batches() -> List> { floor_compile_clean_batch(batches: gunbc_ci_floor_ordinary_batches()) } -data walk_plan_uniformity_note: String = "EVERY plan function returns WalkPlan, including the three with no postconditions — on_success_stages: [] is a declared empty set, not an omission the executor papers over. The INSTANTIATION is where the four differ: this floor returns WalkPlan while regen, plan-artifact, and falsifier return WalkPlan. That DECLARES the intended finalization family and removes the std-level coproduct fork; it does not enforce either, because the typechecker does not check a declared return type against the body (probed by execution — std.realization_schedule walk_finalization_note carries it). Enforcement is the enrolled value witnesses in v2.test.claim.ci_floor_plan_witness plus the executor's runtime parser, and those dissolve when return-position checking lands. The executor has ONE strict parser for the record shape; there is deliberately NO fallback from a failed record parse to a bare-List> reading, because that fallback would let a malformed plan silently run with its success stages dropped — the exact silent-widen shape §5 forbids. The `_plan` names replace the `_batches` names in the same motion (operator ruling 2026-07-30): a function whose value now carries postcondition stages must not keep a name that says it returns only batches, or the next author reasonably assumes the stages are not part of the value. The four argv/step consumers follow automatically because they derive from the floor_plan_function / plan_artifact_plan_function / regen_floor_plan_function / falsifier_plan_function constants (gunbc.ci_spec, gunbc.falsifier_workflow) — those constants are the single naming authority, renamed with the functions." +data walk_plan_uniformity_note: String = "EVERY plan function returns WalkPlan, including the three with no postconditions — on_success_stages: [] is a declared empty set, not an omission the executor papers over. The INSTANTIATION is where the four differ: this floor returns WalkPlan while regen, plan-artifact, and falsifier return WalkPlan. That DECLARES the intended finalization family and removes the std-level coproduct fork; it does not enforce either, because the typechecker does not check a declared return type against the body (probed by execution — std.realization_schedule walk_finalization_note carries it). Enforcement is the enrolled value witnesses in v2.test.claim.ci_floor_plan_witness plus the executor's runtime parser, and those dissolve when return-position checking lands. The executor has ONE strict parser for the record shape; there is deliberately NO fallback from a failed record parse to a bare-List> reading, because that fallback would let a malformed plan silently run with its success stages dropped — the exact silent-widen shape §5 forbids. The `_plan` names replace the `_batches` names in the same motion (operator ruling 2026-07-30): a function whose value now carries postcondition stages must not keep a name that says it returns only batches, or the next author reasonably assumes the stages are not part of the value. The FIVE argv/step consumers follow automatically because a plan target is no longer a name at all: gunbc.cli_invoke PlanFunction is a closed coproduct and claim_executor_run_plan_shell takes a variant, so a rename edits one match arm and every consumer follows.\n\nTHIS CENSUS SAID FOUR FOR TWO DAYS, AND THE WRONG COUNT IS HOW THE FIFTH GOT MISSED — recorded here rather than quietly corrected, because the miss is the note's own failure mode and not the migrating author's. #7470 landed the rename declaring itself INCOMPLETE, migrated the four consumers this sentence enumerated, and left gunbc_falsifier_native_cache_cold_batches returning a bare List> under its old name. The executor's strict parser then refused it — correctly, exactly as the no-fallback clause above promises — and the falsifier's native-cache cold control step went red on every one of the 8 runs that reached it (0 successes) until this repair. It read as intermittent rather than permanent only because the step is SKIPPED whenever the falsifier step fails first, so a deterministic red hid behind whatever witness was failing that cycle.\n\nTHE ROOT CAUSE WAS NOT THE COUNT, IT WAS AN UNTYPED PARAMETER. The clause 'they derive from the constants' was TRUE of four and FALSE of the fifth: native_cache_cold_control_invoke passed plan_function: \"gunbc_falsifier_native_cache_cold_batches\" as an inline string literal, so it derived from nothing and no rename could reach it. Because plan_function was an unconstrained String, plan identity crossed the modeled boundary as an argv token nothing could check, and the completeness argument could only ever be a hand-maintained count.\n\nThe first repair added a fifth naming constant beside the other four. That was still validation — it fixed this site and left the next author free to type a fresh literal — so the constant was deleted again in the same change that introduced the closed coproduct (§4b dissolution-on-climb: the wall replaces the machinery it obsoletes rather than accumulating beside it). An inline literal at a plan_function argument is now a TYPE ERROR, and adding a production target without a variant is impossible, so THIS census is no longer what makes the set complete — it is a receipt for how the set came to be closed. What remains hand-authored is BOTH the variant-to-plan-value pairing in v2.test.claim.ci_floor_plan_witness plan_variant_is_walk_plan_shaped AND the roster that feeds it: the match is exhaustive, so no target can exist without an arm, but nothing forces that arm to be executed, so a wrongly-paired or unexecuted arm remains possible (review 46883). Dissolve-on: a typed DeclarationRef over a resolved plan symbol, at which point the name projection and the hand pairing both delete." fn gunbc_ci_on_success_stages() -> List> { []