From 80db2b61e67754ac4b8a6945c79ab6722902931e Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 24 Sep 2026 23:11:47 -0400 Subject: [PATCH] chore: update --- AGENTS.md | 1 + docs/.obsidian/workspace.json | 93 +-- docs/00 INBOX/ai/nix-statix-deadnix-rules.md | 791 ------------------- docs/00 INBOX/ai/statix-architecture.md | 261 ------ docs/TODO.md | 9 + 5 files changed, 46 insertions(+), 1109 deletions(-) delete mode 100644 docs/00 INBOX/ai/nix-statix-deadnix-rules.md delete mode 100644 docs/00 INBOX/ai/statix-architecture.md diff --git a/AGENTS.md b/AGENTS.md index 7f30b49..3043e9b 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -105,6 +105,7 @@ Do not use `nix fmt` as a validation command until a formatter is added. - The `fix` app passes its current directory to Deadnix. Run `nix run .#fix` from the repository root so path exclusions match. +- During the Nix refactor, address each issue that comes up by adding either a Xatu rule or a new Nix style rule. - Git pathspec searches started in a subdirectory default to that subtree. Use `git -C ` or top-anchored pathspecs for repository-wide history searches. - Ariadne extraction must preserve the game-root season prefix for archived source. diff --git a/docs/.obsidian/workspace.json b/docs/.obsidian/workspace.json index 3bd14bd..9c1d02b 100644 --- a/docs/.obsidian/workspace.json +++ b/docs/.obsidian/workspace.json @@ -4,41 +4,21 @@ "type": "split", "children": [ { - "id": "e581539f950ca1bd", + "id": "6d9088d392cb8604", "type": "tabs", "children": [ { - "id": "0c587e5452c16787", + "id": "22a4c1f201a1b00e", "type": "leaf", "state": { "type": "markdown", "state": { - "file": "TODO.md", + "file": "00 INBOX/valheim progression.md", "mode": "source", "source": true }, "icon": "lucide-file", - "title": "TODO" - } - } - ] - }, - { - "id": "72e6501450a46859", - "type": "tabs", - "children": [ - { - "id": "06bc3d52246b600b", - "type": "leaf", - "state": { - "type": "markdown", - "state": { - "file": "00 INBOX/ai/steamcmd servers.md", - "mode": "source", - "source": true - }, - "icon": "lucide-file", - "title": "steamcmd servers" + "title": "valheim progression" } } ] @@ -111,7 +91,7 @@ "state": { "type": "localgraph", "state": { - "file": "TODO.md", + "file": "00 INBOX/valheim progression.md", "options": { "collapse-filter": true, "search": "", @@ -134,7 +114,7 @@ "repelStrength": 10, "linkStrength": 1, "linkDistance": 250, - "scale": 1, + "scale": 0.6666666666666666, "close": true } }, @@ -251,43 +231,42 @@ "table-editor-obsidian:Advanced Tables Toolbar": false } }, - "active": "0c587e5452c16787", + "active": "22a4c1f201a1b00e", "lastOpenFiles": [ - "00 INBOX/how to setup a steamcmd server.md", - "00 INBOX/ai/steamcmd servers.md", - "03 wrk/ariadne.md", - "00 INBOX/ai/ariadne-cli-skeleton.md", - "00 INBOX/ai/ariadne-project-goals.md", + "00 INBOX/ai/statix-architecture.md", + "00 INBOX/ai/nix-statix-deadnix-rules.md", + "00 INBOX/let order name resolution.md~", + "00 INBOX/nix name resolution.md", + "00 INBOX/let order name resolution.md", + "00 INBOX/nix name resolution.md~", + "00 INBOX/valheim progression.md", "TODO.md", - "00 INBOX/ai/dictionary-cli.md", - "00 INBOX/ai/dictionary-skill.md", - "03 wrk/falinks.md", - "03 wrk/machoke.md", - "00 INBOX/home assistant agent integration.md", - "02 notes/falinks public surfaces.md", + "00 INBOX/ai/deadnix-architecture.md", + "TODO.md~", + "00 INBOX/ai/xatu-rule-implementation-order.md", + "00 INBOX/ai/xatu-architecture-design.md", + "00 INBOX/ai/nix-style-linter-plan.md", + "00 INBOX/ai/nix-style-guide-agent-customization.md", + "00 INBOX/ai/game-guest-readiness-plan.md", + "00 INBOX/ai/xatu-node-rule-static-dispatch-plan.md", + "00 INBOX/ai/nix-style-linter-pr-1-vendor-rnix.md", + "00 INBOX/ai/nix-style-linter-pr-3-let-order.md", + "00 INBOX/ai/nix-style-linter-pr-2-scaffold-cli.md", + "00 INBOX/ai/homepage-pikachu-setup-plan.md", + "00 INBOX/ai/source-driven-remote-deploy-plan.md", + "00 INBOX/ai/monorepo-work-report.md", + "00 INBOX/ai/clew-ast-exploration.md", + "00 INBOX/ai/steamcmd servers.md", + "00 INBOX/ai/ariadne-pipeline-stage-boundary.md", + "00 INBOX/ai/ariadne-project-goals.md", + "02 notes/steamcmd server setup.md", + "00 INBOX/how to setup a steamcmd server.md", + "00 INBOX/ai/clew-ast-exploration.md~", "03 wrk/machoke.md~", - "02 notes/machoke public surface.md", "03 wrk/falinks.md~", - "99 meta/templates/checkmark.md", - "AGENTS.md", "99 meta/attachments/bases/unlinked mentions.base", - "99 meta/templates/note.md", - "AGENTS.md.md", "00 INBOX/ai", "03 wrk/ai", - "03 wrk/brain.md", - "01 sources/second brain setup for doing.md", - "00 INBOX/ai/hoopa design rewrite proposal 2.md", - "00 INBOX/ai/hoopa decisions.md", - "00 INBOX/ai/second brain setup for doing.md", - "00 INBOX/ai/hoopa design rewrite proposal.md", - "00 INBOX/ai/hoopa design review findings.md", - "00 INBOX/ai/hoopa follow up decisions.md", - "01 sources/obsidian and ai were made for each other.md", - "99 meta/Untitled", - "03 wrk", - "02 notes", - "01 sources", - "30 wrk" + "99 meta/Untitled" ] } \ No newline at end of file diff --git a/docs/00 INBOX/ai/nix-statix-deadnix-rules.md b/docs/00 INBOX/ai/nix-statix-deadnix-rules.md deleted file mode 100644 index 5c07dc2..0000000 --- a/docs/00 INBOX/ai/nix-statix-deadnix-rules.md +++ /dev/null @@ -1,791 +0,0 @@ -# Nix Statix and Deadnix Rules - -## Purpose - -This note rewrites the current `statix` and `deadnix` findings as possible `nix-style` rules. -Use the `Decision` line on each rule for `keep`, `discard`, `update`, or `need-more-info`. - -## Source Baseline - -- `statix` rule names come from `nix run --inputs-from . nixpkgs#statix -- list`. -- `deadnix` checks come from `nix run --inputs-from . nixpkgs#deadnix -- --help`. -- `deadnix` reports categories instead of named rules. -- At collection time, `src/dotfiles/apps.nix` ran `statix fix .` and `deadnix --edit` in `nix run .#fix`. -- At collection time, `statix.toml` disabled `repeated_keys`. - -## Statix Rules - -### `bool_comparison` - -Decision: keep - -Source: `statix` `W01`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Do not compare a boolean expression to `true` or `false`. -Use the expression directly for true checks. -Use `!` for false checks. - -Avoid: - -```nix -x == true -x == false -``` - -Use: - -```nix -x -!x -``` - -#### Rationale - -Boolean literal comparisons add noise without changing behavior. -Direct predicates make conditions easier to scan. - -### `empty_let_in` - -Decision: keep - -Source: `statix` `W02`. -Status at collection time: enabled. -Autofix: yes when the `let` body has no comments. - -#### Rule - -Do not keep a `let` expression that declares no bindings. -Replace it with its body. - -Avoid: - -```nix -let in value -``` - -Use: - -```nix -value -``` - -#### Rationale - -An empty `let` adds syntax without naming a dependency. -It usually remains after editing or debugging. - -### `manual_inherit` - -Decision: Keep - -Source: `statix` `W03`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Use `inherit` when an attribute assignment repeats the same name as its value. - -Avoid: - -```nix -{ - package = package; -} -``` - -Use: - -```nix -{ - inherit package; -} -``` - -#### Rationale - -`inherit` states that the attribute comes from the current scope. -It removes duplicated names. - -### `manual_inherit_from` - -Decision: - -Source: `statix` `W04`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Use `inherit (source)` when an assignment selects an attribute with the same name. - -Avoid: - -```nix -package = pkgs.package; -``` - -Use: - -```nix -inherit (pkgs) package; -``` - -#### Rationale - -`inherit (source)` states that the value comes from an attribute set. -It avoids repeated selector names. - -### `legacy_let_syntax` - -Decision: keep - -Source: `statix` `W05`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Do not use legacy `let { ... }` syntax. -Use documented Nix expressions. - -Avoid: - -```nix -let { - body = x + y; - x = 2; - y = 3; -} -``` - -Use: - -```nix -rec { - body = x + y; - x = 2; - y = 3; -}.body -``` - -#### Rationale - -Legacy `let` syntax is undocumented. -Documented forms are clearer to tools and readers. - -### `collapsible_let_in` - -Decision: keep - -Source: `statix` `W06`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Collapse a `let` expression when its body is another `let` expression. -Put both binding groups in one `let` when scope permits it. - -Avoid: - -```nix -let - a = 1; -in -let - b = 2; -in - a + b -``` - -Use: - -```nix -let - a = 1; - b = 2; -in - a + b -``` - -#### Rationale - -Nested `let` expressions add structure when they do not add a scope boundary. -A single binding group shows the local dependencies together. - -### `eta_reduction` - -Decision: keep - -Source: `statix` `W07`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Remove a lambda that only passes its argument to another function. -Keep the target function name when that preserves behavior. - -Avoid: - -```nix -map (x: double x) values -``` - -Use: - -```nix -map double values -``` - -#### Rationale - -The wrapper lambda adds no behavior. -The direct function reference exposes the operation. - -### `useless_parens` - -Decision: keep - -Source: `statix` `W08`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Remove parentheses around expressions when they do not affect parsing. - -Avoid: - -```nix -let - double = (x: x * 2); -in - (value) -``` - -Use: - -```nix -let - double = x: x * 2; -in - value -``` - -#### Rationale - -Redundant parentheses make expressions harder to scan. -Required precedence parentheses remain valid. - -### `empty_pattern` - -Decision: keep - -Source: `statix` `W10`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Use `_` instead of an empty variadic function pattern when the argument is ignored. -Do not apply this rule to NixOS-style modules that declare `imports`. - -Avoid: - -```nix -{ ... }: value -``` - -Use: - -```nix -_: value -``` - -#### Rationale - -`_` directly marks an ignored argument. -An empty variadic pattern looks like partial destructuring. - -### `redundant_pattern_bind` - -Decision: keep - -Source: `statix` `W11`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Do not bind a variadic pattern when the pattern captures no fields. -Use a single argument name instead. - -Avoid: - -```nix -args @ { ... }: args.nixpkgs -``` - -Use: - -```nix -args: args.nixpkgs -``` - -#### Rationale - -The empty pattern adds no destructuring value. -A named argument shows that the whole argument is used. - -### `unquoted_uri` - -Decision: keep - -Source: `statix` `W12`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Quote URI literals. -Do not use Nix's special unquoted URI syntax. - -Avoid: - -```nix -url = github:owner/repository; -``` - -Use: - -```nix -url = "github:owner/repository"; -``` - -#### Rationale - -Quoted strings work for all URI forms. -They avoid ambiguity with punctuation after the URI. - -### `empty_inherit` - -Decision: keep - -Source: `statix` `W14`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Remove `inherit` statements that inherit no names. - -Avoid: - -```nix -inherit; -``` - -Use no replacement. - -#### Rationale - -An empty `inherit` has no effect. -It usually remains after a refactor. - -### `deprecated_to_path` - -Decision: keep - -Source: `statix` `W17`. -Status at collection time: enabled. -Autofix: no. - -#### Rule - -Do not use `builtins.toPath` or unqualified `toPath`. -Use explicit path construction instead. - -Avoid: - -```nix -builtins.toPath "/path" -``` - -Use: - -```nix -/. + "/path" -./. + "/relative-path" -``` - -#### Rationale - -`toPath` is deprecated. -Explicit path construction states whether the result is absolute or relative. - -### `bool_simplification` - -Decision: keep - -Source: `statix` `W18`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Use `!=` instead of negating an equality comparison. - -Avoid: - -```nix -!(x == y) -``` - -Use: - -```nix -x != y -``` - -#### Rationale - -The direct operator expresses inequality without nested boolean syntax. - -### `useless_has_attr` - -Decision: keep - -Source: `statix` `W19`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Use `or` when an `if` expression only checks for an attribute before selecting it. - -Avoid: - -```nix -if x ? a then x.a else default -``` - -Use: - -```nix -x.a or default -``` - -#### Rationale - -The `or` form is the Nix operator for attribute defaults. -It avoids repeating the attribute path. - -### `repeated_keys` - -Decision: update so that it doesn't conflict with the custom module convention. - -Source: `statix` `W20`. -Status at collection time: disabled in `statix.toml`. -Autofix: no. - -#### Rule - -Group repeated attribute path prefixes in a nested attribute set. -Apply this rule only when at least three sibling assignments share the same first key. -Do not apply it inside `rec` attribute sets. - -Avoid: - -```nix -{ - services.a = 1; - services.b = 2; - services.c = 3; -} -``` - -Use: - -```nix -{ - services = { - a = 1; - b = 2; - c = 3; - }; -} -``` - -#### Rationale - -Grouping repeated prefixes reduces visual repetition. -The local config disables this rule, so it needs an explicit decision before promotion. - -### `empty_list_concat` - -Decision: keep - -Source: `statix` `W23`. -Status at collection time: enabled. -Autofix: yes. - -#### Rule - -Remove list concatenation with an empty list. - -Avoid: - -```nix -[] ++ values -values ++ [] -``` - -Use: - -```nix -values -``` - -#### Rationale - -Concatenating `[]` changes no values. -It usually remains after conditional list construction changed. - -## Deadnix Checks - -### Unused `let` bindings - -Decision: keep - -Source: `deadnix` default check. -Status at collection time: active in `nix run .#fix`. -Autofix: yes. - -#### Rule - -Remove `let` bindings when no live expression uses their names. -Do not keep a binding only because another dead binding uses it. -Use `# deadnix: skip` only for intentional unused declarations. - -Avoid: - -```nix -let - unused = 1; -in - value -``` - -Use: - -```nix -value -``` - -#### Rationale - -Unused bindings hide the dependencies that matter. -They also make refactors look unfinished. - -### Unused `inherit` names - -Decision: keep - -Source: `deadnix` default check. -Status at collection time: active in `nix run .#fix`. -Autofix: yes. - -#### Rule - -Remove names from `inherit` statements when no live expression uses those names. -Remove the whole `inherit` statement when it becomes empty. - -Avoid: - -```nix -let - inherit (builtins) unused; -in - value -``` - -Use: - -```nix -value -``` - -#### Rationale - -Unused inherited names create the same noise as unused `let` bindings. -An empty result also overlaps with `statix` `empty_inherit`. - -### Unused lambda arguments - -Decision: keep - -Source: `deadnix` default check. -Status at collection time: active in `nix run .#fix`. -Autofix: yes. - -#### Rule - -Mark an unused single lambda argument with `_`. -Do not keep a meaningful name for an ignored argument. - -Avoid: - -```nix -arg: value -``` - -Use: - -```nix -_: value -``` - -#### Rationale - -`_` states that the argument is intentionally ignored. -A named unused argument implies missing logic. - -### Unused lambda pattern names - -Decision: keep - -Source: `deadnix` default check. -Status at collection time: active in `nix run .#fix`. -Autofix: yes. - -#### Rule - -Remove unused names from lambda attribute patterns. -Keep only names used by the body or defaults. -Use `...` when callers can pass extra attributes. - -Avoid: - -```nix -{ used, unused, ... }: used -``` - -Use: - -```nix -{ used, ... }: used -``` - -#### Rationale - -Pattern names usually declare dependencies. -Unused names overstate the function's inputs. - -### Unused lambda pattern aliases - -Decision: keep - -Source: `deadnix` default check. -Status at collection time: active in `nix run .#fix`. -Autofix: yes. - -#### Rule - -Remove a lambda pattern alias when the body does not use the alias. -Keep the alias only when code reads the whole argument set. - -Avoid: - -```nix -args @ { used, ... }: used -``` - -Use: - -```nix -{ used, ... }: used -``` - -#### Rationale - -The alias says the function needs the complete input set. -Keeping it unused makes the function contract look wider than it is. - -### Ignored underscore bindings - -Decision: keep - -Source: `deadnix` `--no-underscore` option. -Status at collection time: inactive; current fixer does not pass `--no-underscore`. -Autofix: no separate rule. - -#### Rule - -Treat bindings whose names start with `_` as intentionally ignored. -Optionally skip unused diagnostics for those names. - -Avoid, when the skip policy is active: - -```nix -let - _unused = expensiveValue; -in - value -``` - -Use only for intentional placeholders. - -#### Rationale - -An underscore prefix is a common marker for intentionally unused names. -Skipping all underscore bindings can hide real dead code. - -### Used underscore bindings - -Decision: keep - -Source: `deadnix` `--warn-used-underscore` option. -Status at collection time: inactive; current fixer does not pass `--warn-used-underscore`. -Autofix: no. - -#### Rule - -Do not use a binding whose name starts with `_`. -Rename it to a normal name when code references it. - -Avoid: - -```nix -let - _package = pkgs.hello; -in - _package -``` - -Use: - -```nix -let - package = pkgs.hello; -in - package -``` - -#### Rationale - -The underscore prefix communicates that the name is intentionally unused. -Using it contradicts that signal. - -## Notes for Decisions - -- `statix` rules are mostly syntax rewrites. -- `deadnix` rules need scope analysis and dead-code reachability. -- `deadnix` does not report `rec` attribute-set bindings as removable findings. -- `statix` `repeated_keys` is present in the installed rule list but disabled locally. -- Rules that change module argument patterns need extra care around NixOS modules and `callPackage` functions. diff --git a/docs/00 INBOX/ai/statix-architecture.md b/docs/00 INBOX/ai/statix-architecture.md deleted file mode 100644 index ac48494..0000000 --- a/docs/00 INBOX/ai/statix-architecture.md +++ /dev/null @@ -1,261 +0,0 @@ -# Statix Architecture - -## Purpose - -This note explains how `statix` works as a Nix linter and fixer. -It focuses on architecture, not the value of each rule. - -Use this note when deciding how complete our repository-local Nix linter should become. - -## What Statix Is - -`statix` is a syntax-tree linter for Nix. -It parses source text into a Nix AST, walks that tree, and runs rules on matching nodes. - -It does not evaluate Nix. -It does not import files. -It does not know the final value of an attribute set. -It sees source structure, not runtime semantics. - -That design makes `statix` fast and deterministic. -It also limits it to rules that the parser can prove from local syntax. - -## Minimal Linter Vocabulary - -- Source text is the bytes in a Nix file. -- A parser converts source text into a syntax tree. -- A syntax tree records nodes such as lambdas, lists, strings, and operators. -- A token is a leaf item such as an identifier, comment, or URI literal. -- A rule inspects one syntax element and optionally returns a diagnostic. -- A diagnostic reports a span and a message. -- A suggestion adds a replacement for that span. -- A fixer applies suggestions back to source text. - -## Component Map - -The upstream architecture document names four major components. - -### CLI component - -The CLI owns operator interaction. -It parses subcommands and options, loads configuration, discovers files, and prints output. - -It supports these user flows: - -- `check`: report diagnostics. -- `fix`: apply all safe suggestions. -- `single`: apply one suggestion at a position. -- `explain`: print the long explanation for a rule code. -- `dump`: print a sample configuration file. -- `list`: print all available rules. - -### Library component - -The library owns lint rules and the data structures that rules return. -It defines `Report`, `Diagnostic`, `Suggestion`, `Rule`, `Metadata`, `Explain`, and `Lint`. - -Each rule is a small unit. -It receives one syntax element and returns zero or one report. - -The library also contains helpers that build replacement syntax. -Those helpers parse small replacement fragments back into AST nodes. -This makes fixes use valid Nix syntax instead of raw string assembly. - -### Virtual filesystem component - -The virtual filesystem stores file paths and file contents in memory. -It assigns each file a small `FileId`. - -The CLI reads files into this store before linting. -Diagnostics then carry `FileId` references instead of path strings. - -The VFS supports sequential iteration and parallel iteration. -`statix check` uses parallel iteration across files. - -### Macro component - -The macro component reduces rule boilerplate. -A `lint` macro generates rule metadata, explanation support, and the static rule object. - -A rule author writes the rule structure, metadata, documentation, and validation logic. -The macro wires that rule into the common linter interface. - -## Check Pipeline - -```mermaid -flowchart TD - A[Parse CLI options] --> B[Discover configuration] - B --> C[Build ignore set] - C --> D[Walk Nix files] - D --> E[Read files into VFS] - E --> F[Build active lint map] - F --> G[Parse each file with rnix] - G --> H[Walk syntax tree] - H --> I[Run rules matching each syntax kind] - I --> J[Collect reports] - J --> K[Render diagnostics] - K --> L[Exit 1 when reports exist] -``` - -The key optimization is the active lint map. -`statix` groups rules by `SyntaxKind` before it walks a file. -During traversal, it looks up only rules that declared interest in the current node kind. - -This avoids running every rule on every node. -It also keeps each rule narrow. - -## Rule Registration - -Rules are built into the binary. -There is no dynamic rule loading. - -A registry macro imports each rule module and builds a static `LINTS` vector. -The CLI filters that vector with configuration. -Disabled rule names disappear from the active lint map. - -This model has a simple trust boundary: - -- all rule code ships with the tool; -- configuration can disable rules; -- configuration cannot define new rules. - -## Rule Execution Model - -Each rule declares the syntax kinds it wants to inspect. -For example, one rule can ask for binary-operation nodes. -Another rule can ask for URI tokens. - -The traversal visits tree entries with `preorder_with_tokens`. -That includes both nodes and tokens. -Rules can therefore inspect structured AST nodes and raw tokens. - -A rule returns a `Report` when it finds a problem. -The report contains one or more diagnostics. -Each diagnostic has a source range and a message. -A diagnostic can also include a `Suggestion`. - -Rules do not share state with each other. -They also do not run a whole-program analysis. -A rule sees the syntax element passed to it and whatever children or parents it chooses to inspect. - -## Parse Errors - -`statix` turns parser errors into reports. -Those reports use code `0` and severity `Error`. - -Parse errors flow through the same output machinery as lint findings. -This lets the CLI render syntax errors and lint diagnostics with one reporter. - -## Output Model - -`statix` has several output formats. - -The human format uses `ariadne` to render annotated source snippets. -The `errfmt` format prints one compact line per diagnostic. -The JSON format exists behind a feature flag. - -The output layer receives reports and the VFS. -It converts byte ranges into line and column positions at render time. - -This separates rule logic from display logic. -Rules do not need to know how the terminal or editor consumes diagnostics. - -## Fix Pipeline - -A fixable diagnostic contains a `Suggestion`. -A suggestion contains the range to replace and replacement syntax. - -`statix fix` uses the same parser and rule walk as `check`, but filters for reports that contain suggestions. -It then sorts and filters suggestions to avoid overlapping edits. - -The fixer applies selected reports to a copy of the source. -Then it parses and scans the changed source again. -It repeats this process until no more suggestions appear. - -That iterative design matters because one edit can expose a later edit. -It also avoids applying stale ranges after source text changes. - -## Single Fix Pipeline - -The `single` command applies one fix at a requested line and column. -It converts the line and column to a byte offset. -Then it finds the first fixable report whose diagnostic range contains that offset. - -This shape supports editor workflows. -An editor can request a fix for the diagnostic under the cursor. - -## Configuration Model - -Configuration is small. -A `statix.toml` file can disable rules by name. -It can also add ignore globs. - -The CLI discovers configuration by walking ancestors from the configured path. -If no config exists, it uses defaults. - -The command also respects `.gitignore` unless unrestricted mode is enabled. -Ignore handling happens before parsing. - -## Architectural Strengths - -`statix` has a clean separation between these concerns: - -- file discovery; -- parsing; -- rule selection; -- rule execution; -- reporting; -- fixing. - -Rules stay small because the framework handles traversal and output. -Fixes are safer because replacement syntax comes from parsed Nix fragments. -The lint map avoids unnecessary rule calls. -Parallel file traversal improves throughput for large trees. - -The static rule registry is easy to audit. -It fits a repository-local linter well when we want deterministic behavior. - -## Architectural Limits - -`statix` does not evaluate Nix. -It cannot know imported module results, overlays, option merges, or generated attributes. - -Most rules must remain local syntax rules. -A rule that needs semantic knowledge can easily become wrong. - -Fixes rely on byte ranges in source text. -They must avoid overlapping ranges. -They must rerun after edits because previous ranges become stale. - -The macro system reduces rule boilerplate, but it hides generated behavior. -That tradeoff is useful for many rules, but it can make debugging harder. - -## Lessons for Our Linter - -Start with a clear rule interface. -A rule should declare its name, matching syntax kinds, and diagnostic output. - -Keep parsing and diagnostics separate from output. -The same diagnostic should support terminal output, editor output, and tests. - -Use syntax-kind indexing when rules are local. -It prevents unnecessary calls and makes rule ownership explicit. - -Treat autofix as a second contract. -A diagnostic can exist without a safe fix. -A fix must define exact replacement ranges and avoid overlap. - -Rerun analysis after applying a batch of fixes. -Source ranges become invalid after edits. - -Do not add Nix evaluation accidentally. -If a rule needs evaluated values, design that as a separate analysis layer. - -## Open Design Questions for Our Linter - -- Should our linter support fixes, or stay report-only for now? -- Should rules register by syntax kind like `statix`? -- Should our suppression model live in the parser layer or rule layer? -- Should parse errors use the same diagnostic type as style rules? -- Should editor-friendly output be part of the first complete architecture? -- Should future semantic rules use a separate pass from local syntax rules? diff --git a/docs/TODO.md b/docs/TODO.md index 54b5873..536bc01 100644 --- a/docs/TODO.md +++ b/docs/TODO.md @@ -22,6 +22,8 @@ - dictionary cli tool - kitchen.md - Rust project creator +- random number generator utility +- reading material helper # migration @@ -98,6 +100,13 @@ - https://www.youtube.com/watch?v=kzcI5F4tGiU - https://www.youtube.com/watch?v=iKwPaB5TUdI - https://www.youtube.com/watch?v=A-CtdQFRX64 +- xatu literature + - https://rust-analyzer.github.io/book/contributing/syntax.html?utm_source=chatgpt.com + - https://github.com/dotnet/roslyn/blob/main/docs/compilers/Design/Red-Green%20Trees.md?utm_source=chatgpt.com + - https://github.com/rust-analyzer/rowan/blob/master/examples/s_expressions.rs?utm_source=chatgpt.com + - https://dl.acm.org/doi/10.1145/964001.964011 + - https://web.cecs.pdx.edu/~apt/esop15.pdf?utm_source=chatgpt.com + - https://www.researchgate.net/publication/2377179_Efficient_and_flexible_incremental_parsing?utm_source=chatgpt.com # tech debt