Skip to content

check: resolve alias/config and alias/DeferredName references (documented forms warned unknownName) - #4

Closed
yenda wants to merge 2 commits into
mainfrom
fix/config-deferred-imports
Closed

check: resolve alias/config and alias/DeferredName references (documented forms warned unknownName)#4
yenda wants to merge 2 commits into
mainfrom
fix/config-deferred-imports

Conversation

@yenda

@yenda yenda commented Aug 13, 2026

Copy link
Copy Markdown
Owner

Bug

The offered-names set that a qualified reference alias/Name is validated against (collect_referenced_trigger_names) held declared type names and referenced triggers only. Two reference forms drew false allium.reference.unknownName warnings (exit 1) although the aliased module visibly carries the construct:

1. alias/config.param — contradicting the language reference. The reference's "Config parameter references" section documents exactly this form:

A config parameter's default value can reference a parameter from an imported module's config block using a qualified name: required_copies: Integer = core/config.required_copies

and checker rule 46 requires it to resolve ("A qualified config reference in a default expression must resolve to a declared parameter in an imported module's config block"). On main, even that documented config-default position warns — and the message claims the module "does not define" a config block it plainly defines.

2. alias/DeferredName — a deferred declaration the module carries. Natural cross-module form: a module declaring deferred UnhandledException is exactly the module another spec wants to name in requires: mobile_auth/UnhandledException(request).

Repro (fails on main, passes here — transcribed into cross_module_lifecycle.rs): provider with a config block + deferred ExternalHelper; consumer referencing p/config.page_size (both in a config default and in a rule) and p/ExternalHelper → 3 false warnings on main, 0 here.

Fix

collect_referenced_trigger_names additionally offers:

  • config, when the module declares a config block;
  • each deferred declaration's root name (deferred Foo and deferred Foo.bar both offer Foo). A deferred declared against another module's alias (deferred other/Foo) names a construct that module owns and is deliberately not offered — extract_leading_ident returns None for qualified paths.

Not in scope (follow-up)

Field-level validation of config references (rules 46/47: does page_size exist in the imported block, do the types match). Today the QRef for alias/config.page_size carries only the name config, so a field typo produces the byte-identical diagnostic to a valid reference. This fix stops the false positive on the block reference; field resolution needs the qref collector to carry the member chain.

Tests

  • 3 unit tests on the offering set (config + deferred + dotted-deferred root offered; neither offered by a module without them; a foreign deferred other/Foreign offers neither the name nor the alias)
  • 3 integration tests (the ticket repro resolves and exits 0; p/NoSuchDeferred still warns; p/config against a module with no config block still warns)
  • Full workspace suite green: 655 tests, 0 failures.

Real-world impact

On a ~180-spec production corpus, the v3.5.0 → v3.5.3 upgrade produced 8 false unknownName warnings of these two shapes (5 config, 3 deferred), each now carrying a suppression directive plus an explanatory comment. With this fix those suppressions become unnecessary.

yenda and others added 2 commits August 13, 2026 10:01
The offered-names set a qualified reference alias/Name is validated against
held declared types and referenced triggers only. A module's config block and
its deferred declarations were absent, so two documented reference forms drew
false allium.reference.unknownName warnings:

- alias/config.param — the language reference's 'Config parameter references'
  section documents exactly this form, and checker rule 46 requires it to
  resolve; even the documented config-default position warned.
- alias/DeferredName — a deferred declaration the module visibly carries.

The diagnostic also claimed the module 'does not define' a config block it
plainly defines.

collect_referenced_trigger_names now offers 'config' when the module declares
a config block, and each deferred declaration's root name (deferred Foo and
deferred Foo.bar both offer Foo). A deferred declared against another
module's alias (deferred other/Foo) stays a foreign reference, not a local
offering. Field-level validation of config references (rules 46/47: does
page_size exist, do the types match) remains open — this fix stops the false
positive on the block reference itself.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fered

deferred other/Foreign records that 'other' owns the construct; the declaring
module must offer neither the name nor the alias. The behaviour was already
implemented (extract_leading_ident returns None for qualified paths) but had
no test holding it in place.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@yenda

yenda commented Aug 13, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the upstream PR: juxt#91 (same branch).

@yenda yenda closed this Aug 13, 2026
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.

1 participant