llmnav 0.7.3 → 0.8.0

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/CHANGELOG.md CHANGED
@@ -6,6 +6,18 @@ The npm package follows Semantic Versioning. The `llmnav/N` source protocol is v
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.8.0] — 2026-08-15
10
+
11
+ ### Added
12
+
13
+ * Added exact-path audit dispositions with mandatory review reasons, deterministic suppression, and stale-decision reporting so intentional non-cards do not reappear without becoming hidden permanent ignores.
14
+
15
+ ## [0.7.4] — 2026-08-14
16
+
17
+ ### Fixed
18
+
19
+ * Required npm provenance in package metadata, release validation, and the tag publication workflow so public Trusted Publisher releases fail closed if provenance is disabled.
20
+
9
21
  ## [0.7.3] — 2026-08-14
10
22
 
11
23
  ### Fixed
package/README.md CHANGED
@@ -47,7 +47,7 @@ npx llmnav init --agents all --package-scripts
47
47
 
48
48
  Initialization is explicit. LLMNav never edits a consumer repository from an npm `postinstall` script. Use `--agents none` when only the machine-readable control directory is desired.
49
49
 
50
- Before writing cards, run `npx llmnav audit`. It ranks likely architectural boundaries and explains each score. The command never edits source and remains advisory unless `--fail-on high`, `medium`, or `low` is selected. Review the candidates: a high score is evidence to inspect a file, not permission to generate semantic meaning automatically.
50
+ Before writing cards, run `npx llmnav audit`. It ranks likely architectural boundaries and explains each score. The command never edits source and remains advisory unless `--fail-on high`, `medium`, or `low` is selected. Review the candidates: a high score is evidence to inspect a file, not permission to generate semantic meaning automatically. For a reviewed false positive or implementation detail, add its exact path and a concrete reason to `audit.dispositions`; stale decisions remain visible instead of becoming permanent hidden ignores.
51
51
 
52
52
  ## Add the first card
53
53
 
@@ -253,7 +253,7 @@ Do not annotate trivial getters, generated files, obvious wrappers, every test f
253
253
 
254
254
  ## Current implementation boundary
255
255
 
256
- Version 0.6 adds a deterministic coverage audit that prioritizes root and nested-package entrypoints, structural boundaries, persistent artifact filename protocols, versioned schema literals, Rust/Tauri runtime signals, TypeScript Tauri invoke adapters, and high fan-in modules. It suppresses declaration files, dependency caches, test support code, simple barrels, and low-fan-in broad utilities. It suggests narrow coverage rules but never writes cards or invents semantic roles. Use `llmnav audit --summary --json` for a compact automation result or `llmnav audit --json --output .llmnav/audit.json` to keep the full candidate report out of captured stdout.
256
+ The deterministic coverage audit prioritizes root and nested-package entrypoints, structural boundaries, persistent artifact filename protocols, versioned schema literals, Rust/Tauri runtime signals, TypeScript Tauri invoke adapters, and high fan-in modules. It suppresses declaration files, dependency caches, test support code, simple barrels, and low-fan-in broad utilities. It suggests narrow coverage rules but never writes cards or invents semantic roles. Exact reviewed dispositions suppress known non-boundaries while stale dispositions expose obsolete decisions. Use `llmnav audit --summary --json` for a compact automation result or `llmnav audit --json --output .llmnav/audit.json` to keep the full candidate report out of captured stdout.
257
257
 
258
258
  LLMNav does not discover sibling repositories automatically and does not ship an MCP server, embedding database, hosted service, SCIP generator, or complete language-aware call graph. External tools may export the documented compact graph-input schema. Generated structure never writes derived edges into source cards.
259
259
 
@@ -294,7 +294,7 @@ The project uses the Node.js standard library and built-in test runner. There is
294
294
 
295
295
  ## Status
296
296
 
297
- LLMNav is an experimental protocol and a usable v0.7 CLI. The source format remains `llmnav/1`; npm package changes and source-grammar changes are versioned independently.
297
+ LLMNav is an experimental protocol and a usable v0.8 CLI. The source format remains `llmnav/1`; npm package changes and source-grammar changes are versioned independently.
298
298
 
299
299
  ## License
300
300
 
package/docs/api.md CHANGED
@@ -75,7 +75,7 @@ for (const candidate of result.candidates) {
75
75
  if (auditHasFindings(result, "high")) process.exitCode = 1;
76
76
  ```
77
77
 
78
- `auditProject` is read-only and returns schemaVersion 1 data with repository-relative paths and deterministic ordering. Candidate signals are structural heuristics, not generated semantic meaning. Consumers should review high and medium candidates before adding a card and should never turn the suggested coverage rule into automatic source annotation.
78
+ `auditProject` is read-only and returns schemaVersion 1 data with repository-relative paths and deterministic ordering. Candidate signals are structural heuristics, not generated semantic meaning. Exact reviewed decisions from `audit.dispositions` are returned separately with `suppressed` or `stale` status; `auditHasFindings` considers only active candidates. Consumers should review high and medium candidates before adding a card and should never turn the suggested coverage rule into automatic source annotation.
79
79
 
80
80
  ## Generate incrementally and transactionally
81
81
 
package/docs/cli.md CHANGED
@@ -39,7 +39,7 @@ Reads the selected source set and ranks files that lack file or module cards. Si
39
39
 
40
40
  The command never modifies source, configuration, registries, or generated caches. Its output is advisory and exits with status 0 by default. `--fail-on high` fails only for high candidates; `medium` fails for high or medium; `low` fails for any candidate. Invalid thresholds exit with status 2.
41
41
 
42
- JSON output uses schemaVersion 1, repository-relative paths, deterministic ordering, explainable `reasons` and `signals`, and a path-specific `suggestedCoverageRule` for high and medium candidates. `--summary` omits candidate details. `--output <path>` writes the selected report inside the repository and emits only a compact confirmation envelope to stdout; escaping paths and symbolic-link traversal are rejected. Suggestions require human or agent review: LLMNav cannot infer a durable role, ownership boundary, invariant, or semantic ID from structure alone.
42
+ JSON output uses schemaVersion 1, repository-relative paths, deterministic ordering, explainable `reasons` and `signals`, and a path-specific `suggestedCoverageRule` for high and medium candidates. Reviewed `audit.dispositions` appear separately as `suppressed` or `stale`; only active candidates participate in `--fail-on`. Stale reasons are `file-not-scanned`, `already-carded`, or `not-a-candidate`. `--summary` omits candidate and disposition details but retains their counters. `--output <path>` writes the selected report inside the repository and emits only a compact confirmation envelope to stdout; escaping paths and symbolic-link traversal are rejected. Suggestions require human or agent review: LLMNav cannot infer a durable role, ownership boundary, invariant, or semantic ID from structure alone.
43
43
 
44
44
  ## `llmnav check`
45
45
 
@@ -14,6 +14,9 @@
14
14
  "excludeDirectories": ["node_modules", "dist", "target"],
15
15
  "excludeFiles": ["*.generated.*", "*.gen.*"],
16
16
  "coverageRules": [],
17
+ "audit": {
18
+ "dispositions": []
19
+ },
17
20
  "graph": {
18
21
  "indexFiles": []
19
22
  },
@@ -90,6 +93,25 @@ A coverage rule checks files already selected by `sourceRoots` and extension fil
90
93
 
91
94
  Run `llmnav audit` to obtain path-specific candidate rules. A suggestion is not applied automatically and should be accepted only after the file's durable responsibility is confirmed. This separation prevents structural heuristics from creating vague or stale semantic cards.
92
95
 
96
+ ## Audit dispositions
97
+
98
+ When a candidate has been reviewed and intentionally does not need a semantic card, record that decision instead of repeatedly ignoring it:
99
+
100
+ ```json
101
+ {
102
+ "audit": {
103
+ "dispositions": [
104
+ {
105
+ "path": "src/adapters/local-cache.ts",
106
+ "reason": "This private adapter mirrors its carded module contract and owns no durable policy."
107
+ }
108
+ ]
109
+ }
110
+ }
111
+ ```
112
+
113
+ Each disposition targets one exact normalized repository-relative path. Globs, trailing slashes, backslashes, duplicate paths, and reasons shorter than 12 characters are rejected. A matching candidate is omitted from the active queue and reported as `suppressed`. If the file disappears, gains card coverage, or stops qualifying as a candidate, the disposition is reported as `stale` with a machine-readable reason so obsolete decisions remain visible.
114
+
93
115
  ## Lint profile
94
116
 
95
117
  Byte and field-count limits prevent semantic cards from becoming mini-documents. `maxSemanticRatio` produces a warning after the scanned source exceeds `minimumSourceBytesForRatio`.
@@ -31,7 +31,7 @@ npm run release:check
31
31
 
32
32
  ## 3. Configure npm authentication
33
33
 
34
- The supplied release workflow uses GitHub's OIDC token through npm Trusted Publishers. The GitHub source repository is private, so the workflow explicitly disables provenance; npm accepts provenance only from public source repositories. If the repository becomes public, enable provenance in both `package.json` and the workflow after a successful release check. The same tag workflow creates an idempotent GitHub Release only after the npm registry check or publication succeeds.
34
+ The supplied release workflow uses GitHub's OIDC token through npm Trusted Publishers. The public GitHub source repository enables provenance in both `package.json` and the workflow, and the release check fails if either surface disables it. The same tag workflow creates an idempotent GitHub Release only after the npm registry check or publication succeeds.
35
35
 
36
36
  The workflow references a GitHub environment named `npm`. Create that environment for release protection, or remove the `environment` line when no environment gate is desired.
37
37
 
@@ -55,14 +55,14 @@ Manual publication:
55
55
 
56
56
  ```sh
57
57
  npm login
58
- npm publish --provenance=false --access public
58
+ npm publish --provenance --access public
59
59
  ```
60
60
 
61
61
  Automated publication:
62
62
 
63
63
  ```sh
64
- git tag v0.6.0
65
- git push origin v0.6.0
64
+ git tag vX.Y.Z
65
+ git push origin vX.Y.Z
66
66
  ```
67
67
 
68
68
  The release workflow rejects a tag that does not match `package.json`. If the exact version is already present in npm, the workflow succeeds only when the registry tarball integrity matches the tagged package; a mismatched package fails closed. It then reuses an existing GitHub Release for the tag or creates one with generated release notes. Registry, GitHub API, and Release creation errors other than an expected missing Release fail the workflow.
@@ -23,7 +23,7 @@ Start with high and medium candidates. The audit explains whether a file is a pa
23
23
 
24
24
  In Go repositories, candidates represent packages. Full imports below a repository-contained `go.mod` contribute package fan-in, `cmd/*/main.go` is treated as a command entrypoint, and `_test.go` files do not create separate production candidates. Put one `module` card on a durable package representative; do not repeat the same package role on every Go file.
25
25
 
26
- After accepting a candidate, write its durable meaning by inspecting the source, add a narrow `coverageRules` entry for that exact boundary, and add a real task-language query to `.llmnav/eval/queries.jsonl`. Use `npx llmnav audit --fail-on high` in CI only after the initial review.
26
+ After accepting a candidate, write its durable meaning by inspecting the source, add a narrow `coverageRules` entry for that exact boundary, and add a real task-language query to `.llmnav/eval/queries.jsonl`. If review confirms that a candidate owns no durable navigation responsibility, add its exact path and a concrete reason to `audit.dispositions`. Never use a glob to dismiss a directory. The audit suppresses the reviewed candidate but reports the entry as stale when the file or its classification changes. Use `npx llmnav audit --fail-on high` in CI only after the initial review.
27
27
 
28
28
  ## Annotate a module boundary
29
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "llmnav",
3
- "version": "0.7.3",
3
+ "version": "0.8.0",
4
4
  "description": "A deterministic semantic navigation layer for LLM coding agents.",
5
5
  "type": "module",
6
6
  "bin": {
@@ -74,6 +74,6 @@
74
74
  "types": "./src/index.d.ts",
75
75
  "publishConfig": {
76
76
  "access": "public",
77
- "provenance": false
77
+ "provenance": true
78
78
  }
79
79
  }
@@ -101,6 +101,34 @@
101
101
  }
102
102
  }
103
103
  },
104
+ "audit": {
105
+ "type": "object",
106
+ "additionalProperties": false,
107
+ "properties": {
108
+ "dispositions": {
109
+ "type": "array",
110
+ "items": {
111
+ "type": "object",
112
+ "required": [
113
+ "path",
114
+ "reason"
115
+ ],
116
+ "additionalProperties": false,
117
+ "properties": {
118
+ "path": {
119
+ "type": "string",
120
+ "pattern": "^(?!/|[A-Za-z]:|.*(?:^|/)\\.\\.(?:/|$)|.*[\\\\*?\\[\\]{}])[^/]+(?:/[^/]+)*$"
121
+ },
122
+ "reason": {
123
+ "type": "string",
124
+ "minLength": 12,
125
+ "maxLength": 280
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }
131
+ },
104
132
  "graph": {
105
133
  "type": "object",
106
134
  "additionalProperties": false,
package/src/agents.js CHANGED
@@ -30,7 +30,7 @@ Keep an existing LLMNav ID when a symbol or file is renamed or moved. Change \`r
30
30
 
31
31
  Do not add hand-maintained \`calls\`, \`imports\`, \`references\`, \`implements\`, \`exports\`, or \`overrides\` relations. Do not put paths, line numbers, commit hashes, timestamps, callers, or current signatures in LLMNav source comments.
32
32
 
33
- After initialization and whenever public entrypoints, commands, routes, schemas, migrations, or high fan-in modules change, run \`npm exec -- llmnav audit\`. Review high and medium candidates; never add cards automatically. Add a module card only after confirming a durable responsibility, then encode the accepted boundary in a path-specific \`coverageRules\` entry and add a representative retrieval query.
33
+ After initialization and whenever public entrypoints, commands, routes, schemas, migrations, or high fan-in modules change, run \`npm exec -- llmnav audit\`. Review high and medium candidates; never add cards automatically. Add a module card only after confirming a durable responsibility, then encode the accepted boundary in a path-specific \`coverageRules\` entry and add a representative retrieval query. When a reviewed candidate has no durable navigation responsibility, record its exact path and a concrete reason in \`audit.dispositions\`; never use a glob or broad directory suppression.
34
34
 
35
35
  After semantic changes, run \`npm exec -- llmnav format\`, \`npm exec -- llmnav check\`, and \`npm exec -- llmnav generate\`. Use broad text search only when LLMNav returns no credible candidate.
36
36
  ${END}`;
package/src/audit.js CHANGED
@@ -162,24 +162,56 @@ export async function auditProject(root) {
162
162
  priorityRank(left.priority) - priorityRank(right.priority) ||
163
163
  right.score - left.score ||
164
164
  compareText(left.path, right.path));
165
+ const candidateByPath = new Map(candidates.map((candidate) => [candidate.path, candidate]));
166
+ const dispositions = [...project.config.audit.dispositions]
167
+ .sort((left, right) => compareText(left.path, right.path))
168
+ .map((disposition) => {
169
+ const candidate = candidateByPath.get(disposition.path);
170
+ if (candidate) {
171
+ candidateByPath.delete(disposition.path);
172
+ return {
173
+ path: disposition.path,
174
+ reason: disposition.reason,
175
+ status: "suppressed",
176
+ priority: candidate.priority,
177
+ score: candidate.score,
178
+ };
179
+ }
180
+ return {
181
+ path: disposition.path,
182
+ reason: disposition.reason,
183
+ status: "stale",
184
+ staleReason: classifyStaleDisposition(disposition.path, fileByPath, exactCardPaths, coveredModules),
185
+ };
186
+ });
187
+ const activeCandidates = candidates.filter((candidate) => candidateByPath.has(candidate.path));
165
188
  const summary = {
166
189
  analyzedFiles: fileByPath.size,
167
190
  cardedFiles: cardedFilePaths.size,
168
191
  filesWithoutModuleCards: fileByPath.size - cardedFilePaths.size,
169
- candidates: candidates.length,
170
- high: candidates.filter((candidate) => candidate.priority === "high").length,
171
- medium: candidates.filter((candidate) => candidate.priority === "medium").length,
172
- low: candidates.filter((candidate) => candidate.priority === "low").length,
173
- coverageSuggestions: candidates.filter((candidate) => candidate.suggestedCoverageRule !== null).length,
192
+ candidates: activeCandidates.length,
193
+ high: activeCandidates.filter((candidate) => candidate.priority === "high").length,
194
+ medium: activeCandidates.filter((candidate) => candidate.priority === "medium").length,
195
+ low: activeCandidates.filter((candidate) => candidate.priority === "low").length,
196
+ coverageSuggestions: activeCandidates.filter((candidate) => candidate.suggestedCoverageRule !== null).length,
197
+ suppressedCandidates: dispositions.filter((disposition) => disposition.status === "suppressed").length,
198
+ staleDispositions: dispositions.filter((disposition) => disposition.status === "stale").length,
174
199
  };
175
200
  return {
176
201
  schemaVersion: AUDIT_SCHEMA_VERSION,
177
202
  repositoryId: project.config.repositoryId,
178
203
  summary,
179
- candidates,
204
+ candidates: activeCandidates,
205
+ dispositions,
180
206
  };
181
207
  }
182
208
 
209
+ function classifyStaleDisposition(file, fileByPath, exactCardPaths, coveredModules) {
210
+ if (!fileByPath.has(file)) return "file-not-scanned";
211
+ if (exactCardPaths.has(file) || coveredModules.has(moduleKeyForFile(file))) return "already-carded";
212
+ return "not-a-candidate";
213
+ }
214
+
183
215
  function groupFilesByModule(fileByPath) {
184
216
  const output = new Map();
185
217
  for (const [file, record] of fileByPath) {
package/src/cli.js CHANGED
@@ -349,12 +349,16 @@ async function runAudit(root, args, json) {
349
349
  const { summary } = result;
350
350
  console.log(
351
351
  `audit files=${summary.analyzedFiles} carded=${summary.cardedFiles} candidates=${summary.candidates} ` +
352
- `high=${summary.high} medium=${summary.medium} low=${summary.low}`,
352
+ `high=${summary.high} medium=${summary.medium} low=${summary.low} ` +
353
+ `suppressed=${summary.suppressedCandidates} stale-dispositions=${summary.staleDispositions}`,
353
354
  );
354
355
  for (const candidate of result.candidates.filter((item) => item.priority !== "low")) {
355
356
  console.log(`${candidate.priority} ${candidate.path} score=${candidate.score} ${candidate.reasons.join(",")}`);
356
357
  }
357
358
  if (summary.low > 0) console.log(`${summary.low} low-priority candidate(s) are available in --json output.`);
359
+ for (const disposition of result.dispositions.filter((item) => item.status === "stale")) {
360
+ console.log(`stale ${disposition.path} ${disposition.staleReason}: ${disposition.reason}`);
361
+ }
358
362
  if (outputPath) console.log(`wrote ${relativePosix(root, outputPath)}`);
359
363
  }
360
364
  return auditHasFindings(result, failOn) ? 1 : 0;
package/src/config.js CHANGED
@@ -30,7 +30,9 @@ const LINT_KEYS = new Set(Object.keys(DEFAULT_CONFIG.lint));
30
30
  const GENERATION_KEYS = new Set(Object.keys(DEFAULT_CONFIG.generation));
31
31
  const EVALUATION_KEYS = new Set(Object.keys(DEFAULT_CONFIG.evaluation));
32
32
  const GRAPH_KEYS = new Set(Object.keys(DEFAULT_CONFIG.graph));
33
+ const AUDIT_KEYS = new Set(Object.keys(DEFAULT_CONFIG.audit));
33
34
  const COVERAGE_KEYS = new Set(["name", "match", "scope", "requiredFields"]);
35
+ const AUDIT_DISPOSITION_KEYS = new Set(["path", "reason"]);
34
36
 
35
37
  export async function loadConfig(root) {
36
38
  const configPath = path.join(root, ".llmnav", "config.json");
@@ -72,6 +74,7 @@ export function validateConfig(config, configPath = ".llmnav/config.json") {
72
74
  validateStringArray(config.excludeDirectories, "excludeDirectories", problems, { unique: true });
73
75
  validateStringArray(config.excludeFiles, "excludeFiles", problems, { unique: true });
74
76
  validateCoverageRules(config.coverageRules, problems);
77
+ validateAudit(config.audit, problems);
75
78
  validateGraph(config.graph, problems);
76
79
 
77
80
  validateLint(config.lint, problems);
@@ -83,6 +86,44 @@ export function validateConfig(config, configPath = ".llmnav/config.json") {
83
86
  }
84
87
  }
85
88
 
89
+ function validateAudit(audit, problems) {
90
+ if (!isObject(audit)) {
91
+ problems.push("audit must be an object");
92
+ return;
93
+ }
94
+ validateObjectKeys(audit, AUDIT_KEYS, "audit", problems);
95
+ if (!Array.isArray(audit.dispositions)) {
96
+ problems.push("audit.dispositions must be an array");
97
+ return;
98
+ }
99
+ const seenPaths = new Set();
100
+ for (const [index, disposition] of audit.dispositions.entries()) {
101
+ const name = `audit.dispositions[${index}]`;
102
+ if (!isObject(disposition)) {
103
+ problems.push(`${name} must be an object`);
104
+ continue;
105
+ }
106
+ validateObjectKeys(disposition, AUDIT_DISPOSITION_KEYS, name, problems);
107
+ const pathProblem = validateProjectRelativePath(disposition.path);
108
+ if (pathProblem) {
109
+ problems.push(`${name}.path ${pathProblem}`);
110
+ } else {
111
+ const normalizedPath = path.posix.normalize(disposition.path);
112
+ if (normalizedPath !== disposition.path || disposition.path.endsWith("/") || /[*?[\]{}]/u.test(disposition.path)) {
113
+ problems.push(`${name}.path must be one exact normalized repository-relative path without glob syntax`);
114
+ }
115
+ const comparisonPath = normalizedPath.normalize("NFKC").toLocaleLowerCase("en-US");
116
+ if (seenPaths.has(comparisonPath)) problems.push(`${name}.path duplicates an earlier disposition`);
117
+ seenPaths.add(comparisonPath);
118
+ }
119
+ if (typeof disposition.reason !== "string" || disposition.reason.trim().length < 12) {
120
+ problems.push(`${name}.reason must explain the review decision in at least 12 characters`);
121
+ } else if (disposition.reason.length > 280) {
122
+ problems.push(`${name}.reason must not exceed 280 characters`);
123
+ }
124
+ }
125
+ }
126
+
86
127
  function validateGraph(graph, problems) {
87
128
  if (!isObject(graph)) {
88
129
  problems.push("graph must be an object");
package/src/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export type LlmnavScope = "file" | "module" | "symbol";
2
2
  export type LlmnavStability = "architecture" | "contract" | "implementation";
3
3
  export type DiagnosticSeverity = "error" | "warning" | "info";
4
4
  export type AuditPriority = "high" | "medium" | "low";
5
+ export type AuditDispositionStaleReason = "file-not-scanned" | "already-carded" | "not-a-candidate";
5
6
 
6
7
  export interface LlmnavCard {
7
8
  scope: LlmnavScope;
@@ -108,8 +109,14 @@ export interface AuditResult {
108
109
  medium: number;
109
110
  low: number;
110
111
  coverageSuggestions: number;
112
+ suppressedCandidates: number;
113
+ staleDispositions: number;
111
114
  };
112
115
  candidates: AuditCandidate[];
116
+ dispositions: Array<
117
+ | { path: string; reason: string; status: "suppressed"; priority: AuditPriority; score: number }
118
+ | { path: string; reason: string; status: "stale"; staleReason: AuditDispositionStaleReason }
119
+ >;
113
120
  }
114
121
 
115
122
  export interface IndexedLocation {
@@ -247,6 +254,9 @@ export interface LlmnavConfig {
247
254
  excludeDirectories: string[];
248
255
  excludeFiles: string[];
249
256
  coverageRules: Array<Record<string, unknown>>;
257
+ audit: {
258
+ dispositions: Array<{ path: string; reason: string }>;
259
+ };
250
260
  graph: {
251
261
  indexFiles: string[];
252
262
  };
package/src/spec.js CHANGED
@@ -10,7 +10,7 @@ rel=workflow>llmnav.rules.validate
10
10
  stability=contract
11
11
  */
12
12
 
13
- export const PACKAGE_VERSION = "0.7.3";
13
+ export const PACKAGE_VERSION = "0.8.0";
14
14
  export const SPEC_VERSION = "1";
15
15
 
16
16
  export const SCOPES = Object.freeze(["file", "module", "symbol"]);
@@ -208,6 +208,9 @@ export const DEFAULT_CONFIG = Object.freeze({
208
208
  excludeDirectories: [...DEFAULT_EXCLUDED_DIRECTORIES],
209
209
  excludeFiles: ["*.min.js", "*.bundle.js", "*.generated.*", "*.gen.*"],
210
210
  coverageRules: [],
211
+ audit: {
212
+ dispositions: [],
213
+ },
211
214
  graph: {
212
215
  indexFiles: [],
213
216
  },