Skip to content

feat(lint): '# lint: loaded-by' fragment directive — E003 context from the composer (#460)#463

Merged
InauguralPhysicist merged 1 commit into
mainfrom
fix-460-loaded-by
Jul 7, 2026
Merged

feat(lint): '# lint: loaded-by' fragment directive — E003 context from the composer (#460)#463
InauguralPhysicist merged 1 commit into
mainfrom
fix-460-loaded-by

Conversation

@InauguralPhysicist

Copy link
Copy Markdown
Collaborator

Resolves the ~380 cross-module E003 false positives from the v0.27.0 consumer sweep — the main friction to consumers turning on a --lint CI gate.

The design decision

The issue offered three directions: a fragment declaration, an entry-points-only convention, or blessing mass allow-file headers. The deciding factor: # lint: allow-file E003 abandons undefined-name protection for the fragment; a declared composer keeps it. A fragment linted against its composer's binding set stops flagging composed-in names but still fires on a genuine typo — so the directive turns 380 FPs into 0 without giving up the pass's value. (The eigs.json per-file allow-list, #455, stays open as the contributor on-ramp; it's now the blunt fallback rather than the fragment answer.)

Semantics

# lint: loaded-by <relpath> (conventionally the file header, repeatable):

  • E003 resolves <relpath> like a load_file target from the fragment's directory and collects the named file's transitive binding set — its binders plus everything its literal load_files bind — via the existing, audited e003_load machinery (the feature is ~25 lines because of that reuse).
  • The named file need not load the fragment: pointing at a concat sibling works, which covers the out-of-language composition sub-case (EigenMiniSat's ROM-bundle concat, where no in-language loader exists).
  • Fail-open like every E003 edge: unresolvable/unreadable/unparseable context (or a malformed directive) disables the pass for the file — never a false positive.
  • Works in --lint and the LSP: lint_collect gains a source param and the LSP passes the live document buffer, so the same fragments stop squiggling in editors too, and as-you-type edits to the directive take effect without a save.

Verified on the real corpus (repos untouched)

Repo Fragments E003 before → after
DMG src/cpu, src/opcodes, src/memory (loaded-by ../dmg.eigs) 217 → 0
EigenMiniSat lib/solver, lib/bench (loaded-by ../minisat.eigs) 99 → 0

Exactly the sweep's counts. Consumer rollout (adding the one-line headers) rides the next pin bump per repo.

Tests & docs

  • Six fixtures in test_lint.sh: standalone-fires, directive-suppresses, typo-still-fires under the directive, unresolvable-fails-open, concat-sibling-no-loader, plus the composed-name-stays-silent assertion.
  • docs/DIAGNOSTICS.md: directive documented in the suppression section (with "prefer this over allow-file E003") and the E003 model section.
  • CHANGELOG [Unreleased].
  • Stale "[81] Linter (13 checks)" label in run_all_tests.sh corrected (the count is dynamic).

Gates

  • Release suite: 2584/2584
  • ASan+UBSan detect_leaks=1: 2584/2584
  • test_lsp.py: 67/67; test_lsp_asan.sh: no sanitizer reports

Closes #460

🤖 Generated with Claude Code

…m the composer (#460)

A library fragment declares the file that composes it (load_file entry
point or concat sibling); E003 collects that file's transitive binding
set via the existing e003_load machinery and lints the fragment against
it. Composed-in names stop flagging while a genuine typo still fires —
the protection allow-file E003 abandons. Fail-open on unresolvable
context, like every E003 edge.

lint_collect gains a source param so the LSP passes the live document
buffer (as-you-type directive edits take effect); the CLI already had
source in hand.

Verified on the real consumer corpus: DMG fragments 217 E003 -> 0 via
'loaded-by ../dmg.eigs'; EigenMiniSat lib/ 99 -> 0 via the minisat.eigs
entry (trees untouched). Six fixtures in test_lint.sh cover fire,
suppress, typo-retention, fail-open, and the no-loader concat case.

Gates: release 2584/2584, ASan+UBSan detect_leaks=1 2584/2584,
test_lsp.py 67/67, test_lsp_asan.sh clean.

Closes #460

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@InauguralPhysicist InauguralPhysicist merged commit ec3405c into main Jul 7, 2026
17 checks passed
@InauguralPhysicist InauguralPhysicist deleted the fix-460-loaded-by branch July 7, 2026 01:43
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.

E003 ergonomics for library fragments: ~380 cross-module false positives across 6 consumer repos in the v0.27.0 sweep

1 participant