Skip to content

feat(lint): W016 — bare-predicate aliasing fence (completes #396)#452

Merged
InauguralPhysicist merged 1 commit into
mainfrom
w016-bare-predicate-fence
Jul 5, 2026
Merged

feat(lint): W016 — bare-predicate aliasing fence (completes #396)#452
InauguralPhysicist merged 1 commit into
mainfrom
w016-bare-predicate-fence

Conversation

@InauguralPhysicist

Copy link
Copy Markdown
Collaborator

The last open half of #396, unblocked by #399's inline suppression.

The trap (#247/#262): a bare trajectory predicate reads the last-observed binding — an invisible alias that depends on whichever assignment ran most recently. W016 fires on bare predicates in if-conditions, assignment RHS, return position, and any other expression context, steering to the explicit <predicate> of <var> form.

Corpus-honest scope: loop conditions are exempt — the single-assign loop while not converged form is the documented tutorial idiom, and the ambiguous multi-assign case is already W014 (verified: no double-fire). Any explicit subject counts as named, including the stable of (x + 0.0) #262 aliasing workaround. Deliberate bare reads carry # lint: allow W016.

False-positive gate: zero W016 firings across lib/ + examples/, and a scan of all 10 consumer repos found zero bare-predicate exposure — no --lint CI fallout at the next pin bump.

Gates: release + ASan/UBSan detect_leaks=1 suites 2525/2525 (leak tally 0), test_lint.sh 44/44 (3 firing + 3 silent fixtures), make lsp + test_lsp_asan.sh 64/64. LSP surfaces W016 via the shared lint_collect pipeline. DIAGNOSTICS.md registry entry added; ROADMAP #396 checked off.

Closes #396

🤖 Generated with Claude Code

…#396)

The #247/#262 invisible-alias family: a bare predicate (if stable:,
ok is converged, return diverging) reads the last-observed binding,
and which binding that is depends on whatever assignment ran most
recently. W016 steers to the explicit '<predicate> of <var>' form.

Scope is corpus-honest: loop conditions are exempt — single-assign
'loop while not converged' is the documented tutorial idiom, and the
ambiguous multi-assign case is already W014 (no double-fire). Any
explicit subject counts as named, including the 'stable of (x + 0.0)'
#262 workaround. Deliberate bare reads carry '# lint: allow W016',
which is why this waited for #399.

Zero W016 firings across lib/ + examples/ and the 10 consumer
corpora. Surfaces in --lint --json and eigenlsp via the shared
lint_collect pipeline. With W015 (function-clobber core, #425) this
completes #396; the variable-level outer-mutation lint remains #404's
dataflow territory.

Gates: release + ASan/UBSan detect_leaks=1 suites 2525/2525, leak
tally 0; test_lint.sh 44/44; make lsp + test_lsp_asan.sh 64/64.

Closes #396

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@InauguralPhysicist InauguralPhysicist merged commit d6ca0e6 into main Jul 5, 2026
17 checks passed
@InauguralPhysicist InauguralPhysicist deleted the w016-bare-predicate-fence branch July 5, 2026 22:23
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.

Lint: fence the two load-bearing traps — W015 outer-mutation-without-local, W016 bare-predicate aliasing

1 participant