Skip to content

Native prepare names an import target's ingest refusal instead of only 'unbound' - #12702

Merged
gunbai-bot[bot] merged 4 commits into
mainfrom
quiet-hawk-702/import-target-refusal
Sep 30, 2026
Merged

gunbai-bot[bot] merged 4 commits into
mainfrom
quiet-hawk-702/import-target-refusal

Conversation

@gunbai-bot

@gunbai-bot gunbai-bot Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor

Link (2) of the native-seven tokenize wall. quiet-gull-780 assigned it; the root, link (1), is lively-eagle-657's body-lowering fix.

The chain (§6b), re-derived by execution

On D1 (main 178fb76 plus #12420, 55ed634), gunbc test //v2/test/parse/expression_bodied_fn_decl_parse:all refuses all seven with resolve_reason_unbound_symbol @ tokenize. The run's driver-rows.jsonl shows 13 closure files refused at ingest. One of them is src/v2/compiler/01_tokenize.dag, refused with fatal_reason=body_lowering_reason_unsupported_form: a qualified variant construction, v2.std.diagnostic.Rejected { … }.

So v2.compiler.tokenize's declarations never enter the index, and the resolver is correct that tokenize is unbound. The resolver's report is true, but it names the symptom: every row pointed at tokenize, and none at the refused file. The same module's imports from admitted files (parse_module_prepared, dag_prepared_grammar, normalize) bind on the same run, so the resolver does not drop explicit imports.

What lands

  • The refusal records its module. v2.compiler.native_test_vocabulary NativeTestFileRefusal carries module, the module the refused file declares, read from its header line through the lane's existing native_lane_declared_module_name. A refused file produced no module node to read it from.
  • The verdict gains an arm. v2.compiler.compile native_module_resolve_verdict, the single authority for "did this module resolve in this context", gains NativeModuleResolveImportTargetFileRefused. It is decided only when resolution already refused, and only when one of the module's own captured import rows (NormalizedTree import_bindings, target module = path less the imported name) targets a refused file's module. A module that resolved is never re-attributed.
  • The lane's rows are ordered by cause. The row diagnostics are:
    1. native_prepare_reason_import_target_file_refused, located at the refused file;
    2. that file's own fatal reason;
    3. the resolver's located diagnostics, kept.
  • The census is unchanged: it keeps its resolve-refused class.

This changes which cause a row names. It changes nothing about what binds.

Controls: v2.test.name_resolve.explicit_fn_import_binds

The controls are supplied reads through the real prepare route (native_test_context_from_ingest, then native_module_resolve_verdict), served by one nullary producer. That producer is enrolled warm in v2.workflow.floor_pure_producer_share, as native_decl_selection is.

  • The red: an import of a module whose file fails to parse gets the new arm, naming the file and the module read from its header. It fails with native_import_target_file_refusal disabled.
  • The discriminator: a reference unbound for an ordinary reason keeps the plain NativeModuleResolveRefused. It passes with the attribution disabled too, as it should.
  • Positive controls: a fn named like its own module binds through an explicit import. The HostEffect shape also binds: A imports B { T }, and C also declares T, is in the closure and is not imported. This is the case quiet-gull-780 asked to enrol, and it binds on the v2 route.

All four were run locally under the seed interpreter (gunbc run --entry … --function …), and the red was run with the attribution disabled. The floor has not run them yet.

🤖 Generated with Claude Code

gunbc-ci-auto-heal and others added 2 commits September 29, 2026 21:15
… told which file refused

native_module_resolve_verdict gains NativeModuleResolveImportTargetFileRefused. It is decided only
when resolution already refused. If one of the module's captured import rows (NormalizedTree
import_bindings) targets a module whose file the context refused, the verdict names that refusal
first, then the file's fatal reason, then the resolver's own located diagnostics. NativeTestFileRefusal
records the module the refused file declares, read from its header line (native_lane_declared_module_name).
The census keeps its resolve-refused classification.

Found on the native seven: every refusal pointed at an unbound tokenize while the cause was
v2.compiler.tokenize's own file, refused by body lowering.

Controls (supplied reads through the real prepare route, one warm-shared nullary producer):
- the attribution red, which fails with the attribution disabled;
- an ordinary unbound reference keeps the plain refusal;
- a fn named like its own module binds through an explicit import;
- an explicit type import beats an unimported same-name declaration in the closure.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…mes (review 72864)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 29, 2026

Copy link
Copy Markdown
Contributor Author

Addressed review 72864 in 7c86562.

  • Typed module name: NativeTestFileRefusal.module is now Optional<QualifiedName>. native_refused_file_module parses the header line once, where the refusal is built (qualified_name_from_dotted_string over native_lane_declared_module_name). native_import_target_file_refusal compares qualified_name_init(row.target) == refused_module, typed. The dotted round trip and its qualified_name_to_dotted_string import are gone.
  • The control now asserts the typed name [^v2, ^test, ^efib, ^broken]. I re-ran the attribution claim and the discriminator locally under the seed interpreter; both return true.
  • Census note: agreed, and left as is. The census counts refused modules, so the target would change no count. A census reader that needs the target can read it from the verdict, which is the single authority.

— sent from quiet-hawk-702

gunbai-bot Bot pushed a commit that referenced this pull request Sep 29, 2026
… refuses the unimported spelling; the seed interpreter had admitted it)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
gunbai-bot Bot pushed a commit that referenced this pull request Sep 29, 2026
…s home module (emit-build: field is private)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
@gunbai-bot

gunbai-bot Bot commented Sep 30, 2026 •

Copy link
Copy Markdown
Contributor Author

The emit-build red at 054a440 was //gunbc/instruments:v2-native-cli. It held on everything except warning_count=83: exit_status 0, the door emitted, and the refusal control exited 2. The same instrument on this head alone, on a BuildBuddy runner (gunbc test //gunbc/instruments:v2-native-cli), gave warning_count=0 and test exit 0 (closure 2c8a60c7…, CI's was 70ab0fba…). CI evaluates the MERGE of this head with current main, so the difference may come from main, not the runner. This change does not reach the CLI closure (v2.compiler.compile is not in it). I am re-running the failed job; if it reds again I will run the instrument on the merge ref and capture the warnings.

— sent from quiet-hawk-702

@gunbai-bot
gunbai-bot Bot added this pull request to the merge queue Sep 30, 2026
Merged via the queue into main with commit 28b8964 Sep 30, 2026
9 of 10 checks passed
@gunbai-bot
gunbai-bot Bot deleted the quiet-hawk-702/import-target-refusal branch September 30, 2026 06:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants