@drkmttr/adhere 0.17.5 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -97,6 +97,7 @@ your rules.
97
97
  - [Reading the report](#reading-the-report)
98
98
  - [Rule format](#rule-format)
99
99
  - [Config](#config)
100
+ - [Other Providers](#providers)
100
101
  - [Running lint](#running-lint)
101
102
  - [Comments and suppressions](#comments-and-suppressions)
102
103
  - [Cache](#cache)
@@ -123,12 +124,14 @@ curl -fsSL --create-dirs -o ~/.local/bin/adhere \
123
124
  chmod +x ~/.local/bin/adhere
124
125
  ```
125
126
 
126
- - The npm package brings its own TypeScript compiler, for the
127
- [`symbols` and `references`](#what-jev-reads) Jev reads by default. No other
128
- setup is needed.
129
- - The standalone executable has no compiler, so it lints only with `reads: []`
130
- or `reads: ["workspacePackages"]` in the [config](#config). It suits a global
131
- install that your agent config can always call.
127
+ - The npm package brings its own TypeScript compiler. Opt in with
128
+ `--type-aware` or `typeAware: true` to add both
129
+ [`symbols` and `references`](#what-jev-reads); type awareness is off by default.
130
+ No other compiler setup is needed.
131
+ - The standalone executable has no compiler. It runs the default, compiler-free
132
+ audit with workspace context, or code alone with `reads: []`. Type-aware audits
133
+ require the npm package or a checkout with its development dependencies.
134
+ It suits a global install that your agent config can always call.
132
135
  - It is built for macOS and Linux, on arm64 and x64, and for Windows x64:
133
136
  download `adhere-Windows-x86_64.exe` from the
134
137
  [latest release](https://github.com/darkmatter/adhere/releases/latest).
@@ -354,13 +357,13 @@ writing a rule.
354
357
 
355
358
  ### What else the studies found
356
359
 
357
- | Lesson | What the study found |
358
- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
359
- | "Should" is for people, not a weaker check. | Rules written with "should" and with "must" scored nearly the same ([study](eval/studies/rule-vocabulary.md)). |
360
- | A wrong finding is usually the rule's fault. | Above 0.8, 31 of 35 wrong findings repeated within a rule: a scope its words reach past, or the same misreading again. Fixing the wording fixes them together. Below 0.8, one-off misreads grow, to about one finding in six at 0.6 to 0.7 ([study](eval/studies/presets.md)). |
361
- | Narrow a rule in its description. | Jev scores an `excludeIf` near 0.5 for real and false findings alike, so it thins a rule's findings about as much as a higher threshold ([study](eval/studies/presets.md)). Narrowing the description moves the judgment itself: scoping alchemy's idempotent-delete rule to providers' delete handlers dropped its findings elsewhere from 0.67–0.88 to 0.08–0.21, with nothing real lost ([study](eval/studies/idempotent-delete.md)). |
362
- | Beware rules that turn on what the file does not show. | The weakest preset rules hinged on facts outside the file: whether a client has a default timeout, whether a script is an entry point, whether a key is public ([study](eval/studies/presets.md)). Warning below a context of 0.7 marked one finding in five, and those were real about half the time, where the rest were real three times in four ([study](eval/studies/sufficiency.md)). Make such a rule a warning, or give Jev the fact with config-level [`reads`](#what-jev-reads), an [`appendState`](#rules-as-typescript-files) hook, or an `@adhere` note. |
363
- | Jev believes comments. | Eight of nine real violations of the idempotent-delete rule carried a comment wrongly saying they were fine, and scored 0.31 to 0.62; without comments, all nine scored 0.81 or more ([study](eval/studies/idempotent-delete.md)). That is why adhere takes comments out. A fact Jev needs, such as an exemption, goes in an `@adhere` note, which stays ([study](eval/studies/comments.md)). |
360
+ | Lesson | What the study found |
361
+ | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
362
+ | "Should" is for people, not a weaker check. | Rules written with "should" and with "must" scored nearly the same ([study](eval/studies/rule-vocabulary.md)). |
363
+ | A wrong finding is usually the rule's fault. | Above 0.8, 31 of 35 wrong findings repeated within a rule: a scope its words reach past, or the same misreading again. Fixing the wording fixes them together. Below 0.8, one-off misreads grow, to about one finding in six at 0.6 to 0.7 ([study](eval/studies/presets.md)). |
364
+ | Narrow a rule in its description. | Jev scores an `excludeIf` near 0.5 for real and false findings alike, so it thins a rule's findings about as much as a higher threshold ([study](eval/studies/presets.md)). Narrowing the description moves the judgment itself: scoping alchemy's idempotent-delete rule to providers' delete handlers dropped its findings elsewhere from 0.67–0.88 to 0.08–0.21, with nothing real lost ([study](eval/studies/idempotent-delete.md)). |
365
+ | Beware rules that turn on what the file does not show. | The weakest preset rules hinged on facts outside the file: whether a client has a default timeout, whether a script is an entry point, whether a key is public ([study](eval/studies/presets.md)). Warning below a context of 0.7 marked one finding in five, and those were real about half the time, where the rest were real three times in four ([study](eval/studies/sufficiency.md)). Make such a rule a warning, or give Jev the fact with [`typeAware` or workspace `reads`](#what-jev-reads), an [`appendState`](#rules-as-typescript-files) hook, or an `@adhere` note. |
366
+ | Jev believes comments. | Eight of nine real violations of the idempotent-delete rule carried a comment wrongly saying they were fine, and scored 0.31 to 0.62; without comments, all nine scored 0.81 or more ([study](eval/studies/idempotent-delete.md)). That is why adhere takes comments out. A fact Jev needs, such as an exemption, goes in an `@adhere` note, which stays ([study](eval/studies/comments.md)). |
364
367
 
365
368
  ## Commands
366
369
 
@@ -570,26 +573,66 @@ finding its matchers dropped, with their scores.
570
573
 
571
574
  ### What Jev reads
572
575
 
573
- Beside the file's code, Jev reads three kinds of context, for every rule:
576
+ By default, Jev reads the file's code and its imported workspace packages, with
577
+ no native compiler startup. Opt in with `typeAware: true` in the config or
578
+ `adhere lint --type-aware` to add both compiler context maps for every rule:
579
+
580
+ | Name | What Jev reads |
581
+ | ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
582
+ | `workspacePackages` | The repo's own packages the file imports, each name with its directory, as in `{ "orders-core": "packages/orders" }`. A package it imports that is not listed is an installed one. |
583
+ | `symbols` | The compiler's type blocks for each name, plus compiler documentation and JSDoc tags; not literal editor hover text. |
584
+ | `references` | Whole declarations of symbols the code uses from other files of the repo, keyed by `symbol:repository-relative pathname`: a function with its body, a method without the rest of its class. |
585
+
586
+ `symbols` omits standard-library and Node/Bun runtime built-ins, including their
587
+ methods. Project and third-party symbols remain, even when they share a built-in
588
+ name. Built-in type names can still appear inside those symbols' type signatures.
589
+
590
+ `references` is a flat string-to-string map. Keys keep the symbol's name as used
591
+ in the target code, including import aliases, and the pathname's original casing.
592
+ Values are complete declaration excerpts, not incoming reference call sites.
593
+ Overlapping declarations under one key are merged; disjoint excerpts are joined
594
+ with `…` between them. For example, code importing `twice as scale` can receive:
595
+
596
+ ```json
597
+ {
598
+ "references": {
599
+ "__comment": "Declarations of symbols used by the target code, provided only as context. Keys are symbol:repository-relative pathname; values are source excerpts, not incoming call sites.",
600
+ "scale:src/Math.ts": "export function twice(value: number): number {\n return value * 2;\n}"
601
+ }
602
+ }
603
+ ```
604
+
605
+ When sent to Jev, each enabled `references`, `symbols`, and `workspacePackages`
606
+ map includes a reserved `__comment` explaining its contents. These comments are
607
+ included before `appendState` hooks and restored after hooks. Top-level guidance
608
+ also tells Jev that these maps are context only: judge the target `code`, not the
609
+ additional declarations or metadata.
574
610
 
575
- | Name | What Jev reads |
576
- | ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
577
- | `workspacePackages` | The repo's own packages the file imports, each name with its directory, as in `{ "orders-core": "packages/orders" }`. A package it imports that is not listed is an installed one. |
578
- | `symbols` | The compiler's type blocks for each name, plus compiler documentation and JSDoc tags; not literal editor hover text. |
579
- | `references` | The declaration of each name the file uses from another file of the repo, whole: a function with its body, a method without the rest of its class. |
611
+ Each symbol's complete resolved content is truncated to 256 characters by
612
+ default. Set `maxSymbolLength` in the config to change this limit. Documentation
613
+ and JSDoc tags are first capped separately by `maxSymbolDocumentationLength`, also
614
+ 256 by default; `0` omits documentation and tags. Smaller limits reduce request
615
+ size but can cut off type signatures, overloads, useful details, or examples.
580
616
 
581
- To read fewer, list the ones you want in the config's `reads`:
617
+ `typeAware` defaults to `false`. When enabled, it adds **both** `symbols` and
618
+ `references`, regardless of `reads`. The `reads` setting now chooses workspace
619
+ context only: its default is `["workspacePackages"]`; `[]` omits that map.
620
+ Legacy `"symbols"` or `"references"` entries in `reads` alone do not enable native
621
+ context, and leaving them out does not disable it when `typeAware` is true.
582
622
 
583
623
  ```ts
584
624
  // .adhere/config.ts
585
625
  import { defineConfig } from "@drkmttr/adhere";
586
626
 
587
627
  export default defineConfig({
588
- reads: ["workspacePackages"], // no symbols or references
628
+ typeAware: true, // opt in to both symbols and references
629
+ reads: [], // omit workspacePackages, not compiler context
589
630
  });
590
631
  ```
591
632
 
592
- `reads: []` sends the code alone.
633
+ For code alone, use `reads: []` with type awareness off; do not pass
634
+ `--type-aware`. To retain workspace context without a compiler, leave the
635
+ settings at their defaults.
593
636
 
594
637
  Each name is the key Jev reads it under, so a rule's description can name it in
595
638
  backticks, as the questions name `code`:
@@ -626,10 +669,12 @@ import { parse } from "orders-core";
626
669
  - What adhere has no name for, such as a file of the repository's, a rule in
627
670
  TypeScript adds with [`appendState`](#rules-as-typescript-files).
628
671
 
629
- **Cost and privacy.** `symbols` and `references` send Jev more than the file it
672
+ **Cost and privacy.** Opting into type awareness sends Jev more than the file it
630
673
  judges: whole declarations from other files, plus compiler-provided documentation
631
- and JSDoc tags in `symbols`, even with `includeComments` off. The plan's estimate leaves their tokens out. Leave them
632
- out of `reads` to send less.
674
+ and JSDoc tags in `symbols`, even with `includeComments` off. It also starts the
675
+ native compiler during execution. The plan's estimate leaves those tokens out.
676
+ Keep `typeAware` off to avoid that extra context and compiler work; changing
677
+ `reads` only changes workspace context.
633
678
 
634
679
  <details>
635
680
  <summary>Where the packages come from</summary>
@@ -689,7 +734,7 @@ export default defineRule({
689
734
  - The state is what Jev reads beside each question: `code`, the file's sections
690
735
  as Jev reads them, under their numbers from 1, as in
691
736
  `{ code: { "1": "import …", "2": "export const …" } }`, beside what the
692
- config [`reads`](#what-jev-reads).
737
+ config's [`reads` and `typeAware`](#what-jev-reads) enable.
693
738
  - `file` is the file's absolute `path`, and its `contents` as written, comments
694
739
  and all.
695
740
  - Nothing the hook returns is checked, so it can change `code` too, or replace
@@ -748,8 +793,11 @@ export default defineConfig({
748
793
  model: "jev-latest",
749
794
  threshold: 0.8,
750
795
  sufficiencyThreshold: 0.6,
751
- reads: ["workspacePackages", "symbols", "references"],
796
+ reads: ["workspacePackages"],
797
+ typeAware: true, // optional; false by default
752
798
  presets: ["effect"],
799
+ maxSymbolDocumentationLength: 256,
800
+ maxSymbolLength: 256,
753
801
  exclude: ["**/generated/**"],
754
802
  overrides: { "effect/basics/instrument-with-pipe": "off" },
755
803
  rules: {
@@ -767,18 +815,21 @@ type UserId = typeof UserId.Type
767
815
  });
768
816
  ```
769
817
 
770
- | Key | Default | Meaning |
771
- | ---------------------- | ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
772
- | `model` | `"jev-latest"` | The model id sent to TypeSafe. |
773
- | `threshold` | `0.8` | Report a rule when Jev's probability is above this. |
774
- | `sufficiencyThreshold` | `0.6` | Below it, a finding warns that Jev may not see enough to decide. |
775
- | `presets` | none | Built-in rule sets, or their topics. See [Presets](#presets). |
776
- | `rules` | `.adhere/rules/` | Rules inline, as above, or a directory (see [Where rules live](#where-rules-live)). Either replaces `.adhere/rules/`: none of its rules, root or nested, is read then. |
777
- | `exclude` | none | Globs, relative to the working directory, of files no rule judges. |
778
- | `overrides` | none | Settings for a rule by its id. See [Overrides](#overrides). |
779
- | `includeComments` | `false` | Send every comment to Jev. See [Comments](#comments). |
780
- | `reads` | `["workspacePackages", "symbols", "references"]` | What Jev reads beside each file's code, for every rule. `[]` is the code alone. See [What Jev reads](#what-jev-reads). |
781
- | `provider` | TypeSafe's Jev | Where the questions go instead, with its own model. See [Providers](#providers). |
818
+ | Key | Default | Meaning |
819
+ | ------------------------------ | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
820
+ | `model` | `"jev-latest"` | The model id sent to TypeSafe. |
821
+ | `threshold` | `0.8` | Report a rule when Jev's probability is above this. |
822
+ | `sufficiencyThreshold` | `0.6` | Below it, a finding warns that Jev may not see enough to decide. |
823
+ | `presets` | none | Built-in rule sets, or their topics. See [Presets](#presets). |
824
+ | `rules` | `.adhere/rules/` | Rules inline, as above, or a directory (see [Where rules live](#where-rules-live)). Either replaces `.adhere/rules/`: none of its rules, root or nested, is read then. |
825
+ | `exclude` | none | Globs, relative to the working directory, of files no rule judges. |
826
+ | `overrides` | none | Settings for a rule by its id. See [Overrides](#overrides). |
827
+ | `includeComments` | `false` | Send every comment to Jev. See [Comments](#comments). |
828
+ | `reads` | `["workspacePackages"]` | Chooses workspace context only. `[]` omits it; native read entries do not enable type awareness. See [What Jev reads](#what-jev-reads). |
829
+ | `typeAware` | `false` | Opt in to both compiler `symbols` and declaration `references`, regardless of `reads`. Also enabled by `--type-aware`. |
830
+ | `maxSymbolDocumentationLength` | `256` | Maximum characters of each symbol's combined documentation and JSDoc tags, before `maxSymbolLength` applies. A non-negative integer; `0` omits them. |
831
+ | `maxSymbolLength` | `256` | Maximum characters of each complete `symbols[name]` string, including type signatures and documentation. A non-negative integer; `0` leaves names with empty content. |
832
+ | `provider` | TypeSafe's Jev | Where the questions go instead, with its own model. See [Providers](#providers). |
782
833
 
783
834
  - An invalid shape refuses the run.
784
835
  - A config can import other files by relative path, but no packages besides
@@ -866,9 +917,10 @@ export default defineConfig({ provider: mine });
866
917
  `choice`'s key. An id left out goes unanswered: its rule is not reported, and
867
918
  is asked again on the next run.
868
919
  - A rejection stops the run, but for three errors adhere exports:
869
- `ContextOverflow` skips the file, `RequestBlocked` reports it blocked, and
870
- `RequestFailed` is tried again, up to three times, when its `status` is 0,
871
- for no answer, or a 408, 429, or 5xx.
920
+ `ContextOverflow` gets one retry without `references` when that map is present;
921
+ if the request still overflows, the file is skipped. `RequestBlocked` reports
922
+ it blocked, and `RequestFailed` is tried again, up to three times, when its
923
+ `status` is 0, for no answer, or a 408, 429, or 5xx.
872
924
  - adhere paces calls with `--rpm`, aborts `signal` after 30 seconds, and splits
873
925
  requests to fit Jev's 64,000 tokens. A model that takes less splits further in
874
926
  its `ask`.
@@ -1086,6 +1138,7 @@ the default, `0.6`.
1086
1138
  | `--preset <names>` | Add built-in rule sets, or their topics. The config becomes optional. See [Presets](#presets). |
1087
1139
  | `--threshold <0 to 1>` | Replace the config's threshold. Per-rule thresholds still apply. |
1088
1140
  | `--sufficiency-threshold <0 to 1>` | Replace the config's `sufficiencyThreshold`: a finding warns when its `context` is below it. |
1141
+ | `--type-aware` | Enable both compiler `symbols` and declaration `references`; off by default. |
1089
1142
  | `--yes`, `-y` | Send the requests without asking first. |
1090
1143
  | `--limit <files>` | Send requests for at most that many files. See [Limiting a run](#limiting-a-run). |
1091
1144
  | `--rpm <requests>` | Send at most that many requests a minute. |
@@ -1141,8 +1194,9 @@ Estimates cover only code and workspace-package context; symbol/reference input,
1141
1194
  - The cost is adhere's estimate of the input tokens times the model's price. Jev
1142
1195
  charges only for input tokens: $0.042 a million for `jev-latest`, per
1143
1196
  [TypeSafe AI's models page](https://docs.typesafe.ai/models) in
1144
- September 2026. The estimate leaves out `symbols` and `references`, which
1145
- adhere reads as it sends each file, so a run can cost more than it says.
1197
+ September 2026. When type awareness is enabled, the estimate leaves out
1198
+ `symbols` and `references`, which adhere reads as it sends each file, so a run
1199
+ can cost more than it says.
1146
1200
  - A run that stops loses nothing: files finished before it stopped are cached,
1147
1201
  so running again continues from there.
1148
1202
 
@@ -1206,7 +1260,7 @@ it hashes or sends a file, or a declaration from
1206
1260
  [`references`](#what-jev-reads), blanking it so every line keeps its number.
1207
1261
  The report's excerpts still show them. Compiler-provided documentation and
1208
1262
  JSDoc tags still reach Jev in the type/docs strings [`symbols`](#what-jev-reads)
1209
- sends; these are not editor hovers.
1263
+ sends when type awareness is enabled; these are not editor hovers.
1210
1264
 
1211
1265
  Jev takes what comments claim at their word, which hid real violations in the
1212
1266
  studies: see [Writing good rules](#writing-good-rules).
@@ -1422,10 +1476,13 @@ about three bytes a token, and leaves 1k of room for what Jev wraps around it.
1422
1476
 
1423
1477
  - When a file's questions would not fit in one request, they are split across
1424
1478
  several.
1425
- - A file whose state and longest question would not fit together, or that has
1426
- more than 255 sections, is skipped and counted in the summary, and the rest of
1427
- the run goes on. What adhere reads is never cut short to fit, so large
1428
- `references` can skip a file.
1479
+ - If a file's state and longest question would not fit together, or a provider
1480
+ reports a context overflow, adhere retries once without `references` when that
1481
+ map is present. Target code, `symbols`, and other context remain intact; no
1482
+ declaration excerpt is shortened to fit. Removing references may still leave
1483
+ the request too large, in which case the file is skipped and counted in the
1484
+ summary. A file with more than 255 code sections is also skipped, and the rest
1485
+ of the run goes on.
1429
1486
  - So is a file Jev itself counts as over its context, which text denser than the
1430
1487
  estimate, such as CJK, can cause.
1431
1488
 
@@ -1435,17 +1492,21 @@ about three bytes a token, and leaves 1k of room for what Jev wraps around it.
1435
1492
 
1436
1493
  Names and layouts from older versions:
1437
1494
 
1438
- | Version | What it had | What happens now |
1439
- | ----------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1440
- | before 0.7 | A rule's examples were `reference` and `avoid` in a config, and a fence could be tagged `avoid`. | They still read as `must` and `never`. |
1441
- | through 0.7 | The `effect` preset checked seven conventions a linter checks exactly. | They are left to `@effect/tsgo`. The notes on `effect` under [Presets](#presets) say how to turn them on. |
1442
- | before 0.13 | A rule was any `*.md` file in `.adhere/`, as `.adhere/data/brand-ports.md`. | A `*.md` file outside every rule's directory, but a `README.md`, refuses the run. The refusal says where each such file goes to keep its id, so `adhere-ignore` comments and `overrides` still name it. |
1443
- | before 0.13 | `.adhere/tsconfig.json` included only `config.ts`. | Make its `include` `["**/*.ts"]` to give rules written in TypeScript their types. |
1444
- | 0.13.1 | The workspace's packages had a key of their own, `includeWorkspacePackages: true`. | adhere no longer reads it. Jev reads the workspace's packages by default. |
1445
- | 0.13.1 and before | Prose around a `RULE.md`'s code was ignored. | Jev reads it after the description, as the rule's details, so a rule with prose is judged again once. Keep prose about the rule: why it holds, or where it does not apply. |
1446
- | 0.15.0 and before | A rule named what Jev reads beside its code, in `reads`. | `reads` is the config's, for every rule, and a rule that has it refuses the run: delete it. Jev reads all three by default. See [What Jev reads](#what-jev-reads). |
1447
- | 0.15.0 and before | `--limit` counted rule checks. | It counts files. |
1448
- | 0.14.0 and before | The `effect` preset had `services/test-layers-are-in-memory` and `services/operations-have-no-requirements`. | They are gone, and an `overrides` entry naming either refuses the run: remove it. `@effect/tsgo`'s `leakingRequirements` checks the second. `adhere-ignore` comments naming them suppress nothing. |
1495
+ | Version | What it had | What happens now |
1496
+ | ----------------- | ------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
1497
+ | before 0.7 | A rule's examples were `reference` and `avoid` in a config, and a fence could be tagged `avoid`. | They still read as `must` and `never`. |
1498
+ | through 0.7 | The `effect` preset checked seven conventions a linter checks exactly. | They are left to `@effect/tsgo`. The notes on `effect` under [Presets](#presets) say how to turn them on. |
1499
+ | before 0.13 | A rule was any `*.md` file in `.adhere/`, as `.adhere/data/brand-ports.md`. | A `*.md` file outside every rule's directory, but a `README.md`, refuses the run. The refusal says where each such file goes to keep its id, so `adhere-ignore` comments and `overrides` still name it. |
1500
+ | before 0.13 | `.adhere/tsconfig.json` included only `config.ts`. | Make its `include` `["**/*.ts"]` to give rules written in TypeScript their types. |
1501
+ | 0.13.1 | The workspace's packages had a key of their own, `includeWorkspacePackages: true`. | adhere no longer reads it. Jev reads the workspace's packages by default. |
1502
+ | 0.13.1 and before | Prose around a `RULE.md`'s code was ignored. | Jev reads it after the description, as the rule's details, so a rule with prose is judged again once. Keep prose about the rule: why it holds, or where it does not apply. |
1503
+ | 0.15.0 and before | A rule named what Jev reads beside its code, in `reads`. | `reads` is the config's, for every rule, and a rule that has it refuses the run: delete it. Workspace context is on by default; compiler context requires `typeAware: true`. See [What Jev reads](#what-jev-reads). |
1504
+ | 0.15.0 and before | `--limit` counted rule checks. | It counts files. |
1505
+ | 0.14.0 and before | The `effect` preset had `services/test-layers-are-in-memory` and `services/operations-have-no-requirements`. | They are gone, and an `overrides` entry naming either refuses the run: remove it. `@effect/tsgo`'s `leakingRequirements` checks the second. `adhere-ignore` comments naming them suppress nothing. |
1506
+
1507
+ Configs that previously enabled compiler context with `reads: ["symbols", "references"]`
1508
+ must now opt in with `typeAware: true`, or use `adhere lint --type-aware`.
1509
+ That switch enables both maps; `reads` only controls workspace context.
1449
1510
 
1450
1511
  ## Development
1451
1512
 
@@ -1458,13 +1519,13 @@ adhere lint --preset effect
1458
1519
  ```
1459
1520
 
1460
1521
  - In a checkout no platform package is installed, so `bin/adhere.js` runs
1461
- `src/main.ts` with Bun instead, and `symbols` and `references` use the
1462
- checkout's own TypeScript.
1522
+ `src/main.ts` with Bun instead. Type-aware audits use the checkout's own
1523
+ TypeScript; the default audit does not start it.
1463
1524
  - `bun run typecheck` runs `tsc` and the linter.
1464
1525
  - `bun run test` runs the tests.
1465
1526
  - `bun scripts/verify-npm.ts`, after `bun run build:npm`, installs the built
1466
- packages in a scratch project and checks that they read `symbols` and
1467
- `references`. It needs Node 24 or later, and sends Jev nothing.
1527
+ packages in a scratch project and explicitly enables `typeAware: true` to
1528
+ check `symbols` and `references`. It needs Node 24 or later, and sends Jev nothing.
1468
1529
 
1469
1530
  ### Native executable
1470
1531
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drkmttr/adhere",
3
- "version": "0.17.5",
3
+ "version": "0.18.1",
4
4
  "private": false,
5
5
  "description": "Lints a repository against the rules in .adhere/, judged by Jev.",
6
6
  "license": "MIT",
@@ -90,10 +90,10 @@
90
90
  "--force"
91
91
  ],
92
92
  "optionalDependencies": {
93
- "@drkmttr/adhere-darwin-arm64": "0.17.5",
94
- "@drkmttr/adhere-darwin-x64": "0.17.5",
95
- "@drkmttr/adhere-linux-arm64": "0.17.5",
96
- "@drkmttr/adhere-linux-x64": "0.17.5",
97
- "@drkmttr/adhere-win32-x64": "0.17.5"
93
+ "@drkmttr/adhere-darwin-arm64": "0.18.1",
94
+ "@drkmttr/adhere-darwin-x64": "0.18.1",
95
+ "@drkmttr/adhere-linux-arm64": "0.18.1",
96
+ "@drkmttr/adhere-linux-x64": "0.18.1",
97
+ "@drkmttr/adhere-win32-x64": "0.18.1"
98
98
  }
99
99
  }
@@ -27,6 +27,7 @@ adhere lint # judge the working directory; exit 1 on an err
27
27
  adhere lint --limit 0 # compiler-free counts/cache plan; no budgeting
28
28
  adhere lint --limit 100 # first 100 files needing requests; all pending rules per file
29
29
  adhere lint --yes # send without asking, as in CI
30
+ adhere lint --type-aware # opt in to both compiler symbols and declaration references
30
31
  adhere lint --preset effect # add a built-in rule set; the config becomes optional
31
32
  adhere lint --filter 'src/**' # read only matching files; repeat, and ! to leave out
32
33
  adhere lint --threshold 0.9 # report at another threshold from the cache; judges nothing again
@@ -38,8 +39,9 @@ adhere skill [docs|setup|fix] # print a skill
38
39
 
39
40
  `adhere <command> --help` lists every flag. Version, help, skills, `validate`,
40
41
  and planning with `--limit 0` do not start the native compiler. Default `lint`
41
- starts it only during execution, after confirmation, for pending judgments or
42
- cached findings still needing location.
42
+ is compiler-free. With `typeAware: true` or `--type-aware`, it starts the compiler
43
+ only during execution, after confirmation, for pending judgments or cached
44
+ findings still needing location.
43
45
 
44
46
  `--limit` now counts files, not rule checks; use the same flag without an extra
45
47
  unit selector. Each request-bearing file consumes one slot for all its pending
@@ -127,7 +129,7 @@ rule takes:
127
129
  `description`, `must`, `never`, and the rest. Its `appendState(state, file, Bun)`
128
130
  runs right before each request for the rule, and what it returns is spread
129
131
  over the request's state: `code`, the file's sections as Jev reads them,
130
- plus the shared context selected by the config's `reads`. Use it to give Jev what the file cannot show, such
132
+ plus the shared context enabled by the config's `reads` and `typeAware`. Use it to give Jev what the file cannot show, such
131
133
  as a schema another file holds, and name the key it adds in the description.
132
134
  Nothing it returns is checked, so it can break its own rule. The rule gets
133
135
  requests of its own, repeating the shared context. Hook-owned external data
@@ -153,7 +155,8 @@ export default defineConfig({
153
155
  presets: ["typescript", "security"], // built-in rule sets, or topics such as "effect/basics"
154
156
  threshold: 0.8, // default 0.8
155
157
  sufficiencyThreshold: 0.6, // below it, a finding warns the file and shared context may not show enough
156
- reads: ["workspacePackages", "symbols", "references"], // default; omitting this field keeps all three
158
+ reads: ["workspacePackages"], // default; [] omits workspace context
159
+ typeAware: false, // default; true or --type-aware enables both symbols and references
157
160
  exclude: ["**/generated/**"], // files no rule judges
158
161
  includeComments: false, // true only for rules about comments
159
162
  overrides: {
@@ -163,14 +166,16 @@ export default defineConfig({
163
166
  });
164
167
  ```
165
168
 
166
- Top-level `reads` selects shared context for every audited file and all its
167
- rules, including presets. `resolveConfig` defaults to
168
- `["workspacePackages", "symbols", "references"]` when the field is omitted,
169
- even without a config file. An explicit array replaces the default: `reads: []`
170
- is the code-only opt-out, and a subset limits context to those readers. Presets
171
- do not own or override this selection. Rule-level `reads`, in Markdown front
172
- matter, `defineRule`, or inline rules, is rejected with guidance to move it to
173
- the config. The available names are:
169
+ Top-level `reads` chooses workspace context for every audited file and all its
170
+ rules, including presets. It defaults to `["workspacePackages"]`, even without
171
+ a config file; `reads: []` omits that map. `typeAware` defaults to `false`.
172
+ Opting in with `typeAware: true` or `--type-aware` enables both `symbols` and
173
+ `references`, regardless of `reads`. Legacy native-reader entries in `reads`
174
+ alone do not enable the compiler; leaving them out does not disable it when
175
+ type awareness is on. Code alone requires `reads: []` and type awareness off.
176
+ Presets do not own or override this selection. Rule-level `reads`, in Markdown
177
+ front matter, `defineRule`, or inline rules, is rejected with guidance to move
178
+ it to the config. The context maps are:
174
179
 
175
180
  - `workspacePackages`: only packages matched by this file's literal imports,
176
181
  as `{ canonicalPackageName: directory }`. Subpaths match the owning package;
@@ -184,10 +189,14 @@ the config. The available names are:
184
189
  and narrowing types stay distinct; docs/tags appear once per canonical symbol
185
190
  per file. This is not literal IDE hover text: there are no IDE labels or
186
191
  selected-call overload presentation. Unused local declarations may have type
187
- blocks too. Library types/docs can appear even when their source is excluded
188
- from snippets.
189
- - `references`: `{ Name: { pathname: declarationSnippet } }` for used symbols'
190
- canonical outgoing alias-target declarations. Each snippet is the smallest
192
+ blocks too. Standard-library and Node/Bun built-ins and their methods are
193
+ omitted; project and third-party symbols remain, including built-in-name
194
+ shadows. Built-in type names can still appear inside meaningful signatures.
195
+ - `references`: a flat `Record<string, string>`, as
196
+ `{ "Name:path/to/file.ts": "declarationSnippet" }`, for declarations of symbols
197
+ used by the target code, not incoming call sites. Keys retain names as used,
198
+ including import aliases, and repository-relative pathname casing; alias targets
199
+ are resolved canonically. Each snippet is the smallest
191
200
  complete AST declaration scope, with no extra surrounding lines: full function
192
201
  bodies; whole arrow/object initializer variable statements, including
193
202
  `export const` and semicolons; whole methods/getters/setters, not their classes;
@@ -201,8 +210,10 @@ the config. The available names are:
201
210
  exclusions remain. There are no counts, incoming callers, structured locations,
202
211
  unresolved lists, full-file collection, or completeness metadata.
203
212
 
204
- Default npm-installed lint uses `symbols` and `references` with adhere's pinned
205
- native TypeScript compiler through the npm/Bun launcher. No root `tsconfig.json`
213
+ When type awareness is enabled, npm-installed lint uses both `symbols` and
214
+ `references` with adhere's pinned native TypeScript compiler through the npm/Bun
215
+ launcher. Enabled context maps include a self-describing `__comment` in Jev's
216
+ state; top-level guidance identifies only `code` as the audit target. No root `tsconfig.json`
206
217
  or root file-list membership is required. During execution, native TypeScript
207
218
  opens files with pending judgments or cached findings needing location and
208
219
  discovers each file's configured project, including package
@@ -243,27 +254,32 @@ program graphs can still consume substantial time/memory. Bounding active
243
254
  documents/snapshots does not make total memory or model payload size constant,
244
255
  and oversized contexts are still possible. Context is queried just
245
256
  before judge/locate and reused locally. Planning never calls `SourceReads`.
246
- Source checkouts use their development compiler dependency. Raw GitHub
247
- binaries still have no compiler resources: their lint requires explicit config
248
- `reads: []` or `reads: ["workspacePackages"]` for execution; use the package
249
- launcher for the full default. Plan-only `--limit 0` needs no compiler or API key.
257
+ Type-aware source checkouts use their development compiler dependency. Raw
258
+ GitHub binaries have no compiler resources, but run the default compiler-free
259
+ audit with workspace context without special configuration. Use `reads: []`
260
+ for code alone, with type awareness off; use the package launcher or a checkout
261
+ for type-aware execution. Plan-only `--limit 0` needs no compiler or API key.
250
262
 
251
263
  Rules without `appendState` share requests and pay for shared input context
252
264
  once per request, not once per rule. Context repeats on request splitting,
253
265
  locating findings, and hook requests. Compiler documentation and complete declaration
254
- scopes add default token/privacy cost, including source from files not judged.
266
+ scopes add token/privacy cost only when type awareness is enabled, including
267
+ source from files not judged.
255
268
  Complete scopes may contain substantially more source/tokens than fixed-line
256
269
  excerpts; function bodies are not peeked or capped to seven lines.
257
270
  Compiler-provided docs and JSDoc tags can remain present with ordinary comments
258
- stripped. Omit `symbols` to disable type/docs context, `references` to disable
259
- snippets, or use `reads: []` for code-only built-in context.
271
+ stripped. Keep `typeAware` off to omit both native maps; `reads` controls only
272
+ workspace context. Use `reads: []` with type awareness off for code alone.
260
273
  Plan token/cost estimates include code and cheap workspace metadata only, not
261
274
  native context or hook-added data. Actual cost and request splits may therefore
262
275
  be higher. Shared state plus any one question must fit 32k tokens, and state
263
276
  plus all questions in a request must fit 64k, with 1k reserved for overhead.
264
- Execution splits question batches, checks full budgets before HTTP, and skips
265
- oversized files instead of silently truncating type/docs strings or complete scopes. Only
266
- `appendState` forces a private rule request group.
277
+ Execution splits question batches and checks full budgets before HTTP. On
278
+ context overflow, it retries once without `references` when that map is present,
279
+ keeping target code and `symbols` intact; a further overflow skips the file.
280
+ Complete declaration scopes are not shortened to fit. Symbol strings have
281
+ configurable `maxSymbolLength` and `maxSymbolDocumentationLength` limits, both
282
+ 256 by default. Only `appendState` forces a private rule request group.
267
283
 
268
284
  `overrides` changes any rule by the id the report shows, a preset's with the
269
285
  preset first, without copying it; an id no rule has refuses the run. `rules`
@@ -330,8 +346,8 @@ re-judges that rule; a threshold change re-judges nothing.
330
346
 
331
347
  Dependencies, related source, reader selection, shared read-context contents,
332
348
  and hook-owned external data are deliberately not fingerprinted. If `A.ts` imports
333
- `B.ts`, changing `B.ts` does not invalidate `A.ts`. Changing config `reads` does
334
- not refresh its cached answers either. This keeps planning cheap but accepts
349
+ `B.ts`, changing `B.ts` does not invalidate `A.ts`. Changing config `reads` or
350
+ `typeAware` does not refresh its cached answers either. This keeps planning cheap but accepts
335
351
  stale dependency/context judgments.
336
352
 
337
353
  `planAudit` reads/counts/hashes code, checks the cache, and makes code plus cheap
@@ -344,8 +360,8 @@ budgeting, native reads, and HTTP execution.
344
360
  Source reload/hash work is bounded to 8 files; plans retain compact metadata and
345
361
  estimates, not all file contents. Only sampled-linter files need a planning
346
362
  reread. After confirmation, execution reloads request-bearing files and cached
347
- finding excerpts, preparing full native context only for pending or
348
- cached-unlocated files just before judge/locate. Every reload validates normalized
363
+ finding excerpts, preparing native context only when type awareness is enabled,
364
+ for pending or cached-unlocated files just before judge/locate. Every reload validates normalized
349
365
  code and ignore directives against the active plan; changes refuse with rerun
350
366
  guidance, without adding persistent-cache keys. A fully cached and located run
351
367
  starts no compiler and needs no API key or Jev requests.
@@ -390,7 +406,8 @@ the file breaks the rule. On a terminal it is amber near its rule's
390
406
  threshold, within a quarter of the room above it (0.80 to 0.84 at a threshold
391
407
  of 0.80), and green above that: a rule whose findings are mostly amber turns
392
408
  on where its threshold sits. `context` is its probability that the file and
393
- shared context show enough to decide; all three readers are included by default.
409
+ shared context show enough to decide. Default context is `workspacePackages`;
410
+ `symbols` and `references` require `typeAware: true` or `--type-aware`.
394
411
  It is colored the same way around the sufficiency threshold, 0.6
395
412
  by default: amber from 0.50 to 0.69, red below. Below 0.6 the finding also
396
413
  carries `warning: this file may not show enough to check this rule`. It turns