From 729a1f5d607c3e75babfb541abd07c140cb248b9 Mon Sep 17 00:00:00 2001 From: gunbc-ci-auto-heal Date: Mon, 21 Sep 2026 08:31:32 +0000 Subject: [PATCH] The rule that decides whether the loader's bare-reference channel pulls a module Two gates, both named at their owning symbol, with a hermetic four-entry discriminating set and a recurring_failure_mode row for the silence. Co-Authored-By: Claude Opus 5 (1M context) --- ...nce_channel_declines_a_pull_in_silence.dag | 35 +++++++++++++++++++ .../bare_reference_channel/alias_home.dag | 3 ++ .../bare_alias_consumer.dag | 3 ++ .../bare_record_consumer.dag | 3 ++ .../imported_record_consumer.dag | 5 +++ .../bare_reference_channel/passenger_home.dag | 5 +++ .../bare_reference_channel/record_home.dag | 3 ++ .../transitive_alias_consumer.dag | 3 ++ 8 files changed, 60 insertions(+) create mode 100644 dag/gunbc/recurring_failure_mode/bare_reference_channel_declines_a_pull_in_silence.dag create mode 100644 fixtures/bare_reference_channel/alias_home.dag create mode 100644 fixtures/bare_reference_channel/bare_alias_consumer.dag create mode 100644 fixtures/bare_reference_channel/bare_record_consumer.dag create mode 100644 fixtures/bare_reference_channel/imported_record_consumer.dag create mode 100644 fixtures/bare_reference_channel/passenger_home.dag create mode 100644 fixtures/bare_reference_channel/record_home.dag create mode 100644 fixtures/bare_reference_channel/transitive_alias_consumer.dag diff --git a/dag/gunbc/recurring_failure_mode/bare_reference_channel_declines_a_pull_in_silence.dag b/dag/gunbc/recurring_failure_mode/bare_reference_channel_declines_a_pull_in_silence.dag new file mode 100644 index 00000000000..95c890bd0ab --- /dev/null +++ b/dag/gunbc/recurring_failure_mode/bare_reference_channel_declines_a_pull_in_silence.dag @@ -0,0 +1,35 @@ +module gunbc.recurring_failure_mode.bare_reference_channel_declines_a_pull_in_silence + +import std.types { NonEmptyStr } +import gunbc.recurring_failure_mode { RecurringFailureMode } + +data bare_reference_channel_declines_a_pull_in_silence: RecurringFailureMode = RecurringFailureMode { + identity: "bare_reference_channel_declines_a_pull_in_silence" as NonEmptyStr, + + receipts: [ + "bare reference channel declines a pull in silence: the loader's bare-reference channel decides, per NAME, whether to pull the module that declares it. Every arm that declines is a bare `continue` -- no diagnostic, no count, no record carried past the loader -- so a module whose type reference was declined is simply not compile-clean. It then drops out of the compiled closure into the NAME CENSUS ONLY, the item registry is built over REALIZED modules only, and the first LOUD symptom is `ResolvedCalleeRegistryRowAbsent` (`effect summary incomplete`) raised once per CALLING witness, modules away from the file that carries the defect. DESIGN section 5's absorbing fallback: a precise, located fact (this reference names a module nothing pulled) replaced by a wider, quieter state, with the locating signal destroyed.", + + "THE RULE, DERIVED FROM THE LOADER AND NAMED AT ITS OWNING SYMBOLS. There are TWO gates, in this order. GATE ONE, `v1_compiler.cli_run` `build_both_closure_edge_index`: the bare half runs only when `source_declares_import_lines(&source.content)` is FALSE. A single `import` line anywhere in a file turns the ENTIRE bare channel off for that file, for every name in it. GATE TWO, `v1_compiler.cli_run` `visit_bare_reference_providers`: inside the channel a name is pulled only if the census answers `GlobalBareUniqueBinding` (or `closure_bare_disposition` answers `UniqueOnChain`) AND its local `pullable` predicate holds -- the reference is in call position, OR the declaration has params, OR it carries a `type_annotation`, OR its `connective` is not `NoConnective`. Names that are self-declared, explicitly imported, substrate vocabulary (`std_types::kernel_type_set` / `container_type_arity`) or a `test fn`/`test data` row are skipped earlier. `AmbiguousOnChain` is the ONE arm that refuses loudly; every other decline is silent.", + + "WHAT THAT MEANS FOR A NULLARY TYPE ALIAS, which is the shape that bit. the branded alias `type ProcessNodeId = NonEmptyStr where brand(...)` has no params, no type_annotation and `NoConnective`, so referencing it in TYPE POSITION satisfies no arm of `pullable` and its module is not pulled. A coproduct (`Disj`) or a record type IS pulled from the same position, because its connective is not `NoConnective`.", + + "THE STANDING FACT ABOUT IMPORT LISTS IS HALF TRUE AND THE HALF THAT IS FALSE IS THE DANGEROUS ONE. A `.dag` import list does NOT bind at NAME RESOLUTION -- a name absent from the braces still resolves through the corpus-wide bare census (`v1_compiler.infer_env` `global_bare_fallback_invariant`), which is why an unlisted use is an ADVISORY and not an error. It DOES bind at the LOADER: gate one means the first `import` line an author adds silently switches off bare pulling for every OTHER name in that file. So a partially-imported file is strictly more dangerous than a zero-import one, and 'it has an import header' is not a safety property.", + + "THE DISCRIMINATING SET, hermetic: FOUR ENTRIES over seven modules in one source root, at `fixtures/bare_reference_channel/`. One compile each, same invocation, only the entry varying: `gunbc compile --output-dir --source-root fixtures/bare_reference_channel --entry fixtures/bare_reference_channel/.dag --target rust`. (1) `bare_record_consumer` -- no imports, bare reference to a RECORD type -- PULLS: the compile is clean and the reference is reported only as an `unlisted import use` advisory. (2) `bare_alias_consumer` -- no imports, bare reference to `type BrcAliasId = Int` -- DOES NOT PULL: the compile REFUSES with `unresolved type BrcAliasId` and the alias home is absent from the resolved closure. The pair differs in exactly the `pullable` condition. (3) `imported_record_consumer` -- the SAME bare reference as (1) plus one unrelated `import` line -- DOES NOT PULL: refuses with `unresolved type BrcRecordId`. The pair (1)/(3) differs in exactly gate one. (4) `transitive_alias_consumer` -- no imports, a bare CALL into a module that imports the alias home -- pulls the CALLEE, and the alias arrives as a passenger of its import closure, so the same alias reference that refuses in (2) compiles clean here. With `GUNBC_BARE_PULL_TRACE=1` a pulled name prints one `[bare-pull]` line naming the census state and a declined name prints nothing, which is the silence this row is about.", + + "THE HYPOTHESIS THIS ROW REPLACES, AND WHY IT LOOKED FALSIFIED. gunbc#11940 proposed that alias-shaped references are not pullable and then falsified it on `test.claim.extdeps_version_base`, which reaches `extdeps.version` through the same alias shape and compiles clean. The alias half was RIGHT; the counterexample resolves for a different reason. That witness also bare-references `min_coreutils_version`, a `data` declaration WITH a type annotation, so `pullable` holds, `extdeps.tools.gnu_coreutils` is pulled, and `extdeps.version` arrives as a PASSENGER of that module's import closure. Reproduced hermetically by entry (4) `transitive_alias_consumer`: a bare CALL to a function in a module that imports the alias home resolves the alias, while (2) identical alias reference still refuses. Whether a bare reference resolves is therefore not a property of the reference; it is a property of what ELSE the file happened to name.", + + "THE SET IS A DECLARED FRONTIER AND NOT A CONSUMED ONE, stated rather than left to be noticed (DESIGN section 3c). Nothing in the corpus runs these four compiles today: this row is their only reference, so the results above are read by a human running the invocation and by nobody else, and they are recorded as OUTCOMES (pulls / refuses, and which diagnostic) rather than as counts, because a transcribed figure with no producer rots (DESIGN section 6). THE NAMED CONSUMER: an instrument target under `gunbc test //gunbc/instruments: