diff --git a/dag/gunbc/recurring_failure_mode/normalized_tree_hides_the_anchor_decl_so_the_mandatory_tag_rejects_pass_vacuously.dag b/dag/gunbc/recurring_failure_mode/normalized_tree_hides_the_anchor_decl_so_the_mandatory_tag_rejects_pass_vacuously.dag new file mode 100644 index 00000000000..7f3535def32 --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/normalized_tree_hides_the_anchor_decl_so_the_mandatory_tag_rejects_pass_vacuously.dag @@ -0,0 +1,21 @@ +module gunbc.recurring_failure_mode.normalized_tree_hides_the_anchor_decl_so_the_mandatory_tag_rejects_pass_vacuously + +import std.types { NonEmptyStr } +import std.decl_ref { DeclarationRef, WholeDeclaration } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data normalized_tree_hides_the_anchor_decl_so_the_mandatory_tag_rejects_pass_vacuously: RecurringFailureMode = RecurringFailureMode { + identity: "normalized_tree_hides_the_anchor_decl_so_the_mandatory_tag_rejects_pass_vacuously" as NonEmptyStr, + + receipts: [ + "**At the normalized grain the mandatory-tag lens finds no anchor declaration even in a clean module, so every normalized-grain reject of `v2.test.long.mandatory_tag_gate_witness` passes for a reason that is not the one it names** (INVALID STATE: a witness that cannot fail). RECEIPT (sunny-ant-198, 2026-10-06, claim_batch on BuildBuddy, gunbc#13458): on the tree `normalize` returns for the clean source `mandatory_tag_compile_gate` rejects with `mandatory_tag_missing_required_decl`, and with no other reason (unreadable, not-accepted, type-mismatch and projection-gated were each probed false; `normalize` itself accepts). So `mandatory_tag_normalized_grain_clean_accepts` is RED, and `mandatory_tag_normalized_grain_missing_rejects` and `mandatory_tag_normalized_grain_misnamed_rejects` are currently VACUOUS: they assert `missing_required_decl` and every normalized tree yields it. The parse-grain claims are unaffected and still discriminate.", + "RUNG: silent wrongness at the normalized grain for this class. Parse grain is mechanically preventable (discriminating RED plus accepted control, both executing). The claim file lives under `test/claim/long/`, which discovery excludes, so no floor run executes it, and the red was invisible until the file stopped compiling against `NormalizedTree` (the fix in #13458 is a type repair only). It is deliberately NOT enrolled in `v2.workflow.floor_expected_red`: that roster asserts an enrolled identity reaches its subject on the floor, and a long-lane identity does not run there. LOCALIZED (same probe family): the parse tree contains the `dag_surface_data_decl` production and the normalized tree does not (`mandatory_tag_subtree_has_production` over the clean source: parse true, normalized false), so the lens, which scans for that surface production (`mandatory_tag_scan_decls`), has nothing to match. The lens reads a surface shape the normalized tree no longer carries (normalize lowers a data declaration to a named member: gunbc#12197, #12790). MEASURED AT THE DOOR GRAIN (sunny-ant-198, 2026-10-06, claim_batch on BuildBuddy): the normalized root of the clean source, taken through `infer_and_discharge` and the real root-grain roster (`run_required_lens_gates` over `required_lenses_at_grain` CompileLensRoot) with the resolution index left empty, is REJECTED with `mandatory_tag_missing_required_decl`, exactly as the module missing the tag is. So on that route the gate is not fail-open for a violating module: it refuses everything, the clean module included. That is the same blindness read from the other side. It is NOT a measurement of the production door, because that tree was supplied with an empty resolution index and was never resolved; a clean extdeps module is not refused by the production compile, so the resolved tree the door really hands the lens differs from this one in a way that is not yet characterised. (A first attempt through `compile_dag_source_to_target_text` refused the off-region control as well, so it measured resolution of a standalone source, not the gate.) NOT YET ESTABLISHED: which tree the production door hands the lens (`v2.compiler.compile` `mandatory_tag_root_gate` reads an `InferredTree` root), and so whether the production gate is itself blind to lowered declarations or this is confined to the witness's `normalize` route; that decides whether the repair is in the lens, the door's grain, or only the witness.", + "CEILING: structurally guaranteed at the normalized grain, since the lens reads a tree both stages produce. NEXT-RUNG TRIGGER, NAMING THE CAPABILITY: the lens reads the anchor declaration from the normalized tree, such that `mandatory_tag_normalized_grain_clean_accepts` passes and the missing and misnamed rejects pass only because their own reason holds, with the vacuity discriminated by that clean control. The row retires when that control is green on an executing route.", + ], + + evidence: [ + DeclarationRef { module_path: "v2.test.long.mandatory_tag_gate_witness", decl_name: "mandatory_tag_normalized_grain_clean_accepts", field: WholeDeclaration }, + DeclarationRef { module_path: "v2.test.long.mandatory_tag_gate_witness", decl_name: "mandatory_tag_normalized_grain_missing_rejects", field: WholeDeclaration }, + DeclarationRef { module_path: "v2.lens.mandatory_tag", decl_name: "mandatory_tag_compile_gate", field: WholeDeclaration }, + ], +} diff --git a/src/v2/test/claim/long/mandatory_tag_gate_witness_test.dag b/src/v2/test/claim/long/mandatory_tag_gate_witness_test.dag index fced0a34d56..46339204fa7 100644 --- a/src/v2/test/claim/long/mandatory_tag_gate_witness_test.dag +++ b/src/v2/test/claim/long/mandatory_tag_gate_witness_test.dag @@ -75,7 +75,7 @@ fn normalized_grain_tree(source: String) -> GrainProbe { GrainTree { root: parse_root } => match normalize(parse_tree: parse_root) { Rejected { diagnostics: _ } => GrainStageRejected - Accepted { value: normalized, diagnostics: _ } => GrainTree { root: normalized } + Accepted { value: normalized, diagnostics: _ } => GrainTree { root: normalized.root } } } }