Repository navigation
feat(rules)!: regroup, demote and retire rules after the audit - #267
Merged
Merged
Conversation
The audit of every rule but style, against public Bend 2 code, sorted each rule into keep, guard, move, demote or retire. This applies the moves: - perf, a new group at warn: `strings` and `chars`, whose cost is real but which never cause a failure (out of correctness). - pedantic, off by default: `foreign` (0 of 30 sampled hits were defects), `fuel` (23% precise), `index` (38%), `strict` (its fix is 1.56x slower on JS) and `rewalk` (its fix is 45-60% slower on native). - opt-in: `coverage` and `closed`, a project's policy rather than a defect; only their own setting turns them on. - retired, codes never reused: `table` (U008) and `hoist` (U009), with no public hits; `ring` (U010), 1 of 4 real and no mechanical fix; `unit` (U012), 0 of 7; `scan` (U013), 50% precise with a false positive tokens cannot tell apart; `unsafe` (L003), which bend reports itself since 2.0.32. A code names the rule, not its group, so moved rules keep their codes, and each module moves to the directory of its new group. `index` still leaves a get on a fixed table alone: that test is src/rules/table.bend now. The import-closure laws coverage's proof leans on, which lived in unsafe's law file, are their own guarantee (laws/ImportReachIsClosed.bend), and the digest no longer carries each file's unsafe defs. The rule criteria gain a guard exception for rare shapes whose miss is silently wrong (`arms`, `escape`, `setting`). This repo's bolt.bend turns perf, pedantic (but `tail`), coverage and closed on, so its gate grades as before. BREAKING CHANGE: `table`, `hoist`, `ring`, `unit`, `scan` and `unsafe` are removed; a bolt.bend that still sets one gets a `setting` finding (C011). `strings`, `chars` and `foreign` are no longer errors by default, `strict`, `fuel`, `index`, `rewalk` and `foreign` are off unless `pedantic` (or the rule) is set, and `coverage` and `closed` are off unless set by name: a project that relied on them must add `def coverage()` / `def closed()`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186KEnw5sg7heUQZTJJU89N
… named files Two bugs put the wrong role on files, so findings were made up or hidden. A file was on the laws' side only when a root LAWS.bend or PROOF.bend in the run reached it. A guarantee kept one per file under laws/ and proofs/, linted without those root files (files named on the line, a run from inside laws/, the editor), was linted as code: most of fromrev's false positives and some of strict's, eager's, concat's and pick's. A file now has a role of its own (Role.own): a LAWS.bend or PROOF.bend by name; else, but for a package's main.bend, a proof file when it fills a law and a law file when it states one and fills none. Over the whole tree that seeds the walk, a file that imports a law file joins the laws' side, and code still wins: a file a main.bend reaches is code, laws and all. A run over a LAWS.bend without the package's main.bend took the code that LAWS.bend imports for law files and dropped its findings (bend2craft's entities.bend: 174 findings alone, none beside its LAWS.bend). Over files named on the line the planner no longer walks the imports: each file is told its own role, as the editor tells it, so the LSP's findings are the CLI's by construction (laws/LspDiagnosticsMatchCli.bend now states the named run's per-file findings, and its proof no longer needs a one-file walk). Laws: laws/RoleOwn.bend states own; the planner's per-file findings are on_run's (the marks over the whole tree, each own role over named files). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186KEnw5sg7heUQZTJJU89N
…alk over named files" This reverts commit 918d358. Role by content and no walk over named files were the wrong fix: few projects keep the laws/ and proofs/ layout, and roles must follow the imports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186KEnw5sg7heUQZTJJU89N
A file's role follows the imports: a file a LAWS.bend reaches is a law file unless a package's main.bend reaches it too. The walk only saw the files of the run, so naming a LAWS.bend without the main.bend that imports the same code took that code for laws and hid its findings (bend2craft's world/entities.bend: 174 findings alone, none beside world/LAWS.bend), and naming laws/<Name>.bend files without their LAWS.bend linted them as code. Over files named on the line the planner now lists the tree under the working directory, as a whole-tree run does, and reads every .bend file in it for its imports alone (Role.fact.text: lexed and outlined, never parsed); the marks are taken over that graph (Plan.marks.run), and only the named files are linted. A whole-tree run is unchanged. Laws: the planner's per-file findings are each source's told its role among Plan.marks.run's marks (laws/defs/GradedFindingCounts.bend). The editor reads one file and not the tree, so laws/LspDiagnosticsMatchCli.bend now compares it with `bolt <path>` as that command really runs, for a file the tree's imports leave at the role its name gives it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186KEnw5sg7heUQZTJJU89N
The graph a named run reads its roles from was the run's sources, then every source the tree's walk finds, so a named file under the working directory was in it twice (`a.bend` and `./a.bend`) and read twice. It is now the walk's sources, then each source of the run whose normalized path the walk did not find: one named outside the working directory. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186KEnw5sg7heUQZTJJU89N
… does `bolt <path>` takes a file's role from the imports of the whole tree, but the editor linted the one open file by its name alone, so a file a LAWS.bend reaches was a law file to the CLI and code in the editor, and laws/LspDiagnosticsMatchCli.bend had to assume the two agreed. On open and save, beside the checker's run, the server now gathers the World `bolt <path>` reads (src/lint/plan.bend's questions answered through the Files service, which can now list a directory) and reads the role marks from it (Plan.marks.named); the document keeps them, and each change is linted with the marks of the last open or save. The editor law now states the editor's lint, told those marks, is the CLI's, with no assumption on the file's role. laws/LspKeepsRoleMarks.bend states that open and save keep the marks they read and a change keeps them as they were. The graph is now walked over resolved paths, so a file named by an absolute path (as the editor names it) or as `./a.bend` is matched to its file in the tree; `bolt /w/laws/x.bend` from /w took it for code before. src/lsp/tests/checker.bend runs native only: each open now reads every file of the tree, and bolt's proofs are past the JS lane's stack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186KEnw5sg7heUQZTJJU89N
noah-emp
enabled auto-merge (squash)
November 1, 2026 16:04
Contributor
Author
|
Cause: GitHub retires the Fix in this PR: 9ffbe5c passes (Edited: an earlier version of this comment guessed at billing, which was wrong; this is a public repo.) Generated by Claude Code |
The shared nix-flake-check workflow defaults to macos-14, which GitHub retires on 2026-11-02 and fails during scheduled brownouts before then: the job is cancelled before any runner is assigned, so `check / check`, the check main requires, went red with no step run. Pass the runner list with macos-15, also arm64, so aarch64-darwin is still checked. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186KEnw5sg7heUQZTJJU89N
This was referenced Nov 1, 2026
Merged
ngngardner
pushed a commit
that referenced
this pull request
Nov 1, 2026
Resolve the rule regroup (#267): `empty` (U018) stays in `suspicious` beside `prefix` and `fromrev`; strings and chars are `perf` as main has them. The code table proof keeps main's arms, which already reach past the 30 rows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0186KEnst9PZ9GVQD8BtKhu4
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The audit of every rule but style, against public Bend 2 code, sorted each
rule into keep, guard, move, demote or retire. This applies the moves:
stringsandchars, whose cost is real butwhich never cause a failure (out of correctness).
foreign(0 of 30 sampled hits were defects),fuel(23% precise),index(38%),strict(its fix is 1.56x slower onJS) and
rewalk(its fix is 45-60% slower on native).coverageandclosed, a project's policy rather than a defect;only their own setting turns them on.
table(U008) andhoist(U009), with nopublic hits;
ring(U010), 1 of 4 real and no mechanical fix;unit(U012), 0 of 7;
scan(U013), 50% precise with a false positive tokenscannot tell apart;
unsafe(L003), which bend reports itself since 2.0.32.A code names the rule, not its group, so moved rules keep their codes, and
each module moves to the directory of its new group.
indexstill leavesa get on a fixed table alone: that test is src/rules/table.bend now. The
import-closure laws coverage's proof leans on, which lived in unsafe's law
file, are their own guarantee (laws/ImportReachIsClosed.bend), and the
digest no longer carries each file's unsafe defs. The rule criteria gain a
guard exception for rare shapes whose miss is silently wrong (
arms,escape,setting). This repo's bolt.bend turns perf, pedantic (buttail), coverage and closed on, so its gate grades as before.BREAKING CHANGE:
table,hoist,ring,unit,scanandunsafeareremoved; a bolt.bend that still sets one gets a
settingfinding (C011).strings,charsandforeignare no longer errors by default,strict,fuel,index,rewalkandforeignare off unlesspedantic(or therule) is set, and
coverageandclosedare off unless set by name: aproject that relied on them must add
def coverage()/def closed().Co-Authored-By: Claude Opus 5.5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_0186KEnw5sg7heUQZTJJU89N