ucn 5.4.1 → 5.5.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.
Files changed (87) hide show
  1. package/.claude/skills/ucn/SKILL.md +58 -236
  2. package/.claude/skills/ucn/references/commands.md +144 -68
  3. package/.claude/skills/ucn/references/resolution-rules.md +171 -0
  4. package/.claude/skills/ucn/references/trust-contract.md +27 -33
  5. package/README.md +18 -12
  6. package/cli/index.js +42 -16
  7. package/core/accessors.js +118 -3
  8. package/core/account.js +30 -0
  9. package/core/analysis.js +508 -264
  10. package/core/ast-analysis.js +76 -117
  11. package/core/async-producers.js +1729 -0
  12. package/core/bridge.js +1877 -268
  13. package/core/brief.js +6 -0
  14. package/core/build-worker.js +78 -14
  15. package/core/cache.js +522 -31
  16. package/core/callers.js +12053 -1047
  17. package/core/check.js +30 -38
  18. package/core/class-identity.js +1028 -0
  19. package/core/command-contracts.js +6 -6
  20. package/core/configuration-items.js +86 -0
  21. package/core/contract-membership.js +2262 -0
  22. package/core/cpp-scope.js +532 -0
  23. package/core/deadcode.js +171 -49
  24. package/core/decorator-binding.js +260 -0
  25. package/core/discovery.js +281 -164
  26. package/core/errors.js +52 -0
  27. package/core/execute.js +21 -9
  28. package/core/external-macros.js +326 -0
  29. package/core/graph-build.js +277 -8
  30. package/core/graph.js +35 -2
  31. package/core/ignore-rules.js +472 -0
  32. package/core/imports.js +504 -42
  33. package/core/index-ir.js +94 -11
  34. package/core/inprocess-clients.js +636 -0
  35. package/core/ir.js +87 -8
  36. package/core/macro-expansion.js +1416 -0
  37. package/core/output/analysis-ext.js +6 -6
  38. package/core/output/analysis.js +18 -2
  39. package/core/output/brief.js +3 -0
  40. package/core/output/doctor.js +4 -0
  41. package/core/output/endpoints.js +15 -6
  42. package/core/output/find.js +11 -2
  43. package/core/output/lines.js +8 -2
  44. package/core/output/refactoring.js +121 -14
  45. package/core/output/reporting.js +31 -3
  46. package/core/output/shared.js +14 -0
  47. package/core/output-budget.js +316 -122
  48. package/core/parallel-build.js +124 -47
  49. package/core/parser.js +3 -2
  50. package/core/project.js +457 -60
  51. package/core/provenance-facts.js +156 -12
  52. package/core/provenance-overload.js +30 -3
  53. package/core/provenance.js +104 -30
  54. package/core/pytest-fixtures.js +434 -0
  55. package/core/python-fixture-flow.js +17 -3
  56. package/core/python-modules.js +173 -0
  57. package/core/reflection.js +877 -0
  58. package/core/registry.js +1 -1
  59. package/core/reporting.js +234 -52
  60. package/core/request-helpers.js +561 -0
  61. package/core/route-graph.js +1922 -0
  62. package/core/route-lists.js +2414 -0
  63. package/core/rust-macro-expansion.js +2113 -0
  64. package/core/rust-modules.js +185 -0
  65. package/core/search.js +121 -29
  66. package/core/shared.js +19 -1
  67. package/core/test-name-bindings.js +256 -0
  68. package/core/type-denotation.js +1161 -0
  69. package/core/type-references.js +3229 -0
  70. package/core/verify.js +3360 -672
  71. package/languages/adapter.js +31 -5
  72. package/languages/c-family.js +4061 -212
  73. package/languages/c-macro-invocations.js +380 -0
  74. package/languages/c-preprocessor.js +254 -0
  75. package/languages/csharp.js +1406 -49
  76. package/languages/go.js +1243 -70
  77. package/languages/index.js +728 -6
  78. package/languages/java.js +473 -61
  79. package/languages/javascript.js +1270 -197
  80. package/languages/lexical-scope.js +1280 -0
  81. package/languages/python.js +1557 -72
  82. package/languages/rust-macro-rules.js +1020 -0
  83. package/languages/rust-value-flow.js +416 -0
  84. package/languages/rust.js +2237 -115
  85. package/languages/utils.js +298 -4
  86. package/mcp/server.js +25 -11
  87. package/package.json +1 -1
@@ -5,99 +5,22 @@ description: AST code intelligence for JavaScript/TypeScript, Python, Go, Rust,
5
5
 
6
6
  # UCN
7
7
 
8
- Use UCN to gather compact, auditable code evidence before reading large files or changing a symbol.
8
+ UCN answers semantic questions about a codebase from a tree-sitter index: where a symbol is defined, who calls it, what it calls, what a change touches, which tests reach it. Every answer labels its evidence and accounts for every line it looked at; nothing is silently dropped.
9
+
10
+ ## When to use it
11
+
12
+ - Semantic questions in a supported language (JavaScript/TypeScript/TSX, Python, Go, Rust, Java, C, C++, C#, HTML inline scripts): definitions, callers, callees, impact, tests, dependencies, public API, dead code.
13
+ - Use text search for literals, messages, configuration, filenames, Markdown, and unsupported languages. Below roughly 500 LOC, reading the files directly is usually faster.
14
+ - An empty UCN result is a statement about the indexed text, never proof that nothing reaches a symbol at runtime.
9
15
 
10
16
  ## Core workflow
11
17
 
12
- 1. Run `ucn repo` in an unfamiliar repository. Add `--deep` when readiness or index health matters. If it reports skipped unsupported source, use grep/ripgrep and a language-native analyzer for those files; never interpret an `UNSUPPORTED` or `PARTIAL` scope as a semantic zero.
13
- 2. Pin a symbol with `ucn find <name>`, then pass its `path:line:name` handle to later commands.
14
- 3. Run `ucn show <handle>` for the default summary, callers, and callees. Request extra projections with `--sections=source,tests,types,dependencies,example,related`.
15
- 4. Before a change, run `ucn impact <handle>` and `ucn tests <handle> --depth=3`.
16
- 5. After a signature change, run `ucn check <handle>`. Before committing, run target-less `ucn check`.
17
- 6. Read exact code with `ucn source <handle>` or `ucn source path/to/file:10-30` only when inspection is needed.
18
-
19
- Prefer `--json` for automation. Every CLI JSON response uses `{ meta, data }`;
20
- `meta.command` uses the native surface spelling and may include the internal
21
- `canonicalCommand`. MCP returns text through one `ucn` tool and keeps contract
22
- metadata visible when truncating results.
23
-
24
- ## One contract across surfaces
25
-
26
- CLI, MCP, and interactive mode resolve the same 18 public commands through one registry, execute the same handlers, and use the same public formatters. CLI spells multiword commands with hyphens; MCP uses snake case. For example, use `audit-async` in CLI and `audit_async` in MCP.
27
-
28
- The release board independently cross-checks overlapping stable-handle answers from `find`, `show`, `source`, `impact`, `tests`, `check`, and caller `trace`. Target identity, source and direct-test projections, caller tiers, evidence reasons, totals, and accounting must agree exactly; a mismatch is a failing witness rather than an interpretation left to an agent.
29
-
30
- Publish-blocking semantic gates also compare stratified samples from pinned real repositories with independent language-native oracles: ts-morph, Pyright, gopls, rust-analyzer, JDT LS, clangd, and Roslyn. This validates the measured static evidence classes; it does not turn dynamic dispatch, generated code, reflection, or external dependencies into complete runtime knowledge.
31
-
32
- MCP keeps its process and project index warm across calls. CLI and MCP share
33
- the same text budget: broad sweep commands (`repo`, `entrypoints`,
34
- `endpoints`, `deadcode`, `deps`, `check`, `audit-async`) default to 3K output
35
- characters, all other commands to 10K, with a 100K hard ceiling. Use CLI
36
- `--max-chars`, MCP `max_chars`, a narrower file/directory scope, or a smaller
37
- section projection when necessary. Truncated output keeps the head of the
38
- answer, a notice stating the full size and limit, and the accounting/contract
39
- lines needed to interpret what remains; the requested limit includes all
40
- three. The text block is the whole response on every surface.
41
-
42
- Persistent indexes live in a per-user, project-keyed cache rather than the analyzed repository. Set `UCN_CACHE_DIR` to override the cache root; CLI `--no-cache` bypasses persistence and `--clear-cache` removes the current project's cache. Legacy `<project>/.ucn-cache` directories are migrated on first use. Concurrent invocations on a cold cache share one build: the first process takes a build lock, the others wait for its cache (`Waiting for another ucn process building the index...` on stderr) instead of rebuilding; a lock left by a dead process is broken automatically.
43
-
44
- Files named `*.min.js`, `*.bundle.js`, and `*.map` are disclosed as skipped
45
- bundled sources; they make observed-text completeness partial. Pass
46
- `--include-bundled` (MCP `include_bundled=true`) to index the JavaScript files.
47
- This option bypasses the shared cache and still respects user exclusions.
48
- Source maps remain disclosed but unindexed; inspect them with text tools.
49
-
50
- Supported source families are JavaScript/TypeScript/TSX, Python, Go, Rust, Java, C, C++, C#, and HTML inline JavaScript/event handlers. C/C++ uses `compile_commands.json` when available to classify headers and resolve include paths. Recoverable preprocessor branches contribute AST-proven source facts, so a single selected configuration does not silently erase definitions or calls; disagreeing conditional macro identities stay visible as unverified. C++ resolution uses namespace ownership, static overload shape (including arrays), and macro-parameter requalification. C# resolution uses declared property/field receiver types plus overload and hiding discipline. This is portable AST analysis, not a compiler build; macros, templates, generated code, reflection, and external dependency semantics can remain unverified.
51
-
52
- `repo` refines its HOT list exactly for up to 400 candidate definitions per
53
- run; when a large repository exhausts that budget the HOT header says so and
54
- the ranking is approximate. `repo --sections=stats --hot` is always exact.
55
-
56
- `repo` readiness is task-specific. Its headline is navigation readiness;
57
- refactor, deletion, semantic recall, and the sampled evidence mix are separate
58
- dimensions. The confirmed/unverified percentage is a classification profile,
59
- not an accuracy grade.
60
-
61
- ## Interpret evidence correctly
62
-
63
- For caller-bearing `show`, `impact`, `trace`, `tests`, and `check` views:
64
-
65
- - `CONFIRMED` has binding, receiver, import, or ownership evidence for the pinned target.
66
- - `UNVERIFIED` is a possible target with insufficient identity evidence. Review it before a breaking change. When same-name definitions cause the ambiguity, `show` lists their stable handles once above the sites so the competing targets are explicit.
67
- - `ACCOUNT` partitions observed literal-name lines into confirmed, unverified, non-call, excluded, and unresolved buckets. In mixed-language repositories it also counts occurrences in unsupported-language source files.
68
- - `CONTRACT` states the scope and completeness of that observed-text partition. When unsupported-language files contain the name, it says so explicitly and the partition-complete claim is limited to supported languages.
69
- - `WARNING` identifies unreadable, unparsed, or partially indexed files, and lists unsupported-language occurrence sites (file:line plus the line text) so nothing grep would show is hidden. `usages` and `tests` carry the same disclosure as a note.
70
- - `FILTERED` means query options hid evidence.
71
-
72
- When the selected definition is a property/getter/setter, `impact` adds a
73
- separate `PROPERTY ACCESS SITES` band. Confirmed reads/writes have receiver
74
- identity; matching attribute syntax with an unresolved receiver stays
75
- unverified. These are change dependencies, not fabricated caller edges, so
76
- the caller `ACCOUNT` remains a call-shaped partition. Reads and writes include
77
- access kind and token column; getter/setter handles describe the same property.
78
- Unambiguous inherited properties share that owner evidence.
79
-
80
- When the selected definition is a type, interface, enum, trait, or record,
81
- `impact` adds a `TYPE REFERENCE SITES` band: annotation and reference sites
82
- confirmed by an import link to the definition's file (or package scope in
83
- Go/Java), the rest visible as unverified with a reason. `DEPENDENCY SITES`
84
- counts them; `CALL SITES` stays call-shaped.
85
-
86
- Target-less `impact` and `check` diff the working tree against `HEAD` AND
87
- include untracked, non-ignored source files as whole-file additions, so new
88
- modules are checked before `git add`. `--staged` keeps its index-only meaning.
89
- The changed-path note also counts untracked documentation and configuration.
90
- Classes, interfaces, types, and fields appear in separate declaration bands
91
- with their dependency sites. Modified/deleted declarations block `check` until
92
- reviewed with the language toolchain: arity checks cannot validate shape or
93
- inheritance compatibility.
94
-
95
- An observed-text zero is not semantic zero or safe-delete proof. Numeric evidence values are ordinal ranking weights, not probabilities.
96
-
97
- When a plain name selects more than one definition, action-oriented commands
98
- (`impact`, `tests`, `check`, and `plan`) carry the same ambiguity warning as
99
- `show`/`source`/`trace`. Prefer a stable handle; never treat the auto-selected
100
- definition as an implicit repository-wide target.
18
+ 1. `ucn repo` in an unfamiliar repository; `--deep` adds index health and readiness. Skipped unsupported source is listed with a handoff: use text search and a language-native tool for those files. An `UNSUPPORTED` or `PARTIAL` scope is never a semantic zero.
19
+ 2. `ucn find <name>` pins a definition. Pass its `path:line:name` handle to every later command. A plain name that matches several definitions carries an ambiguity warning in `show`, `source`, `trace`, `impact`, `tests`, `check` and `plan`; never treat the auto-selected definition as the repository-wide target.
20
+ 3. `ucn show <handle>` gives the summary, callers and callees. Add `--sections=source,tests,types,dependencies,example,related` for more.
21
+ 4. Before a change: `ucn impact <handle>` and `ucn tests <handle> --depth=3`.
22
+ 5. After a signature change: `ucn check <handle>`; before committing: target-less `ucn check`. Both compare a changed declaration with its parameters at `--base` (default `HEAD`), so the call sites bound to the old declaration are checked against the new one; a site that fits no remaining overload is a mismatch, never an excluded other-target line.
23
+ 6. `ucn source <handle>` or `ucn source path/to/file:10-30` for exact code, only when inspection is needed.
101
24
 
102
25
  ## Choose a command
103
26
 
@@ -122,53 +45,57 @@ definition as an implicit repository-wide target.
122
45
  | Generate review candidates | `ucn deadcode`; `ucn audit-async` |
123
46
  | Resolve runtime frames | `ucn stacktrace <text>` |
124
47
 
125
- ## In a shell, next to grep
48
+ ## Read the evidence
49
+
50
+ Caller-bearing views (`show`, `impact`, `trace`, `tests`, `check`) tier every candidate:
51
+
52
+ - `CONFIRMED`: binding, receiver, import, or ownership evidence for the pinned target.
53
+ - `UNVERIFIED`: call syntax that may reach the target, with the reason identity could not be established. Review it before a breaking change. When same-name definitions compete, `show` lists their stable handles once above the sites.
54
+ - Excluded sites (another definition's caller, an incompatible receiver, an external package, an arity mismatch) are counted as other-target lines in `ACCOUNT`, each with its reason in JSON.
55
+
56
+ Trust lines close every answer and survive truncation:
57
+
58
+ - `ACCOUNT` partitions every line where the name occurs: confirmed, unverified, non-call (definition, import, reference, other text), other-target, unaccounted. In mixed-language repositories it also counts occurrences in unsupported-language source files.
59
+ - `CONTRACT` states what that partition covers. Semantic completeness is never claimed: aliases, generated code, reflection and runtime dispatch may exist.
60
+ - `WARNING` lists unreadable, unparsed or partially indexed files and unsupported-language occurrence sites with their line text, so nothing text search would show is hidden. `usages` and `tests` carry the same disclosure as a note.
61
+ - `FILTERED` means query options hid evidence. `CALLEE ACCOUNT` and `TREE ACCOUNT` do the same for callees and `trace` trees.
62
+
63
+ A property/getter/setter target adds `PROPERTY ACCESS SITES` to `impact` (reads and writes with access kind; receiver identity confirms, an unresolved receiver stays unverified). A type target adds `TYPE REFERENCE SITES` (confirmed by an import link to the definition's file, or package scope in Go/Java). `DEPENDENCY SITES` counts them; `CALL SITES` stays call-shaped. Target-less `impact` and `check` diff the working tree against `HEAD` (`--staged` for the index), include untracked non-ignored source as whole-file additions, and put classes, interfaces, types and fields in declaration bands; a modified or deleted declaration makes `check` `BLOCKED` until reviewed with the language toolchain.
64
+
65
+ Numeric evidence values are ordinal ranking weights, not probabilities. An observed-text zero is not a semantic zero or safe-delete proof.
66
+
67
+ ## In a shell
126
68
 
127
- `ucn` is a Bash tool as much as an MCP tool. Two flags make it compose like
128
- `grep -n` so a shell-first agent can keep its reflexes and still get symbol
129
- answers:
69
+ `--lines` and `--raw` make `ucn` compose like `grep -n`:
130
70
 
131
71
  ```bash
132
72
  ucn find handleRequest --lines # path:line:signature # kind
133
73
  ucn show handleRequest --lines # callers as path:line:text; unverified ones end in "\t# unverified: <reason>"
134
74
  ucn show handleRequest --lines --sections=callees
135
- ucn usages handleRequest --lines # every literal-name occurrence; non-call kinds tagged "# import" / "# definition"
75
+ ucn usages handleRequest --lines # every literal-name line; kinds tagged "# import" / "# definition" / "# reference"
136
76
  ucn search 'retry(' --lines # grep -n output, code-aware scope
137
77
  ucn impact handleRequest --lines
138
78
  ucn source handleRequest --raw # the code and nothing else, ready for an exact-string edit
139
79
  ucn source src/server.js:40-80 --raw
140
80
  ```
141
81
 
142
- Records go to stdout; the `ACCOUNT` / `CONTRACT` lines, notes, and the
143
- same-name disambiguation go to stderr prefixed `# ` (MCP keeps them in the one
144
- text block, and `--raw` appends its note as one trailing `# ` line there).
145
- `usages --lines` emits one record per source line, combining occurrence kinds
146
- and disclosing repeated occurrences (including JSX open/close tags). JSON keeps
147
- the individual occurrence records. Definition handles start at decorators when
148
- present, while usages point at token lines (`nameLine` identifies the declaration
149
- token when it differs from `startLine`). Structural `search --unused` keeps its
150
- safety note and decorator tags in shell output; runtime registrations can appear
151
- and zero call edges do not prove a symbol is safe to delete.
152
- `--lines` lists the whole band without default row/character caps, so pipe through
153
- `grep -v '# unverified'` for the confirmed tier. To count distinct source lines
154
- per file, use `cut -d: -f1,2 | sort -u | cut -d: -f1 | sort | uniq -c`;
155
- JSON usage records can count a source line more than once.
156
- Nothing to list prints nothing and exits 1, grep's
157
- contract; errors exit 2. Explicit `--top`/`--limit` still apply and disclose
158
- omissions. `show --lines` accepts only callers/callees sections; target-less
159
- `impact --lines` lists Git-diff callers with per-target accounting. Closing a
160
- pipe with `head` is supported. `source --raw` extracts full large classes too;
161
- `--max-lines` truncation is disclosed on stderr. An explicit `--max-chars`
162
- fails before stdout if the complete shell output exceeds it. Unusual path
163
- characters (backslash/tab/CR/LF) are escaped; use JSON for exact filenames.
164
- `trace` and `tests` scripting uses `--json`. Use `grep` for literals, messages, configuration, and unsupported
165
- languages; use `ucn ... --lines` when the question is a symbol, a caller, or a
166
- definition, and `--raw` when the next step is an edit.
167
-
168
- Command errors exit 2 in ordinary text mode as well. CLI JSON preserves its
169
- own contract: successful empty results exit 0; command errors exit 1 with
170
- `meta.ok: false` and an `error` field. A target-less `check` exits 1 when
171
- `TRUST` is `BLOCKED`, 0 otherwise; a check that could not run exits 2.
82
+ Records go to stdout; `ACCOUNT`/`CONTRACT`, notes and same-name disambiguation go to stderr as `# ` lines (MCP keeps them in the one text block; `--raw` appends its note as one trailing `# ` line there). `--lines` has no default row cap; explicit `--top`/`--limit` disclose what they omit; an explicit `--max-chars` fails before any output instead of truncating records. `grep -v '# unverified'` keeps the confirmed tier. `usages --lines` emits one record per source line and tags combined kinds; JSON keeps individual occurrences. `show --lines` accepts only the callers/callees sections (default callers); target-less `impact --lines` lists Git-diff callers with per-target accounting. `source --raw` extracts whole functions and large classes; `--max-lines` truncation is disclosed on stderr. Unusual path characters (backslash, tab, CR, LF) are escaped; use `--json` for exact filenames, and for `trace`/`tests` scripting. Closing the pipe with `head` is supported.
83
+
84
+ Exit codes: 0 success; 1 for an empty `--lines` listing, a blocking `check` (target-less `check` with `TRUST: BLOCKED`, or `check <handle>` reporting a mismatch or an unverified call site), or a JSON command error (`meta.ok: false` plus `error`); 2 for a text-mode command error or a `check` that could not run. An exception inside UCN prints `Internal error: ...` on every surface (CLI JSON adds `meta.internalError: true`); it says nothing about the code, so rerun with a narrower target or report it.
85
+
86
+ ## Surfaces, JSON and output budgets
87
+
88
+ CLI, MCP and interactive mode run the same 18 commands through one registry, the same handlers and the same formatters. CLI spells multiword commands with hyphens (`audit-async`), MCP uses snake case (`audit_async`) through one `ucn` tool. `--json` returns `{ meta, data }`: `meta.command` keeps the surface spelling and may add `canonicalCommand`, `meta.contract` carries the truth boundary, and public `file` paths are relative to `meta.pathBase`. Definition handles start at a decorator when present; `nameLine` is the declaration token's line.
89
+
90
+ Text output has a character budget on both CLI and MCP: 3K for broad sweeps (`repo`, `entrypoints`, `endpoints`, `deadcode`, `deps`, `check`, `audit-async`), 10K for every other command, 100K ceiling (`--max-chars=N` / `max_chars`; `--all` lifts caps where a command supports it). Room for every trust line is reserved before any body text. A truncated answer keeps its head, a notice with the full size and the limit, and the trust lines; `show` and `impact` keep a head of every tier with a `+N more` line each, so a long confirmed list never hides the unverified band. A budget too small for the trust lines withholds the answer and names the budget that would carry them (`answer withheld; 0 of 3 trust line(s) shown. Raise --max-chars to at least 498.`). Narrow with a handle, `--file`, `--in` or `--sections` before raising the budget.
91
+
92
+ ## Index and discovery
93
+
94
+ Indexes live in a per-user, project-keyed cache outside the repository (`UCN_CACHE_DIR` overrides the root; `--no-cache` bypasses it; `--clear-cache` removes the project's cache; a `.ucn-cache` directory left in a project is migrated on first use). MCP keeps the process and index warm across calls. Concurrent cold starts share one build: the first process takes a build lock and the others wait for its cache (`Waiting for another ucn process building the index...` on stderr); a lock left by a dead process is broken automatically.
95
+
96
+ Discovery applies the project's `.gitignore` files (root and nested) with git's own matching rules; git-tracked files are indexed even when a rule matches them, and a failing `git ls-files` is disclosed as a partial index (`git-listing-failed` in `repo --sections=health` and in caller contracts), never a silently smaller one. `*.min.js`, `*.bundle.js` and `*.map` are skipped and disclosed, which makes observed-text completeness partial; `--include-bundled` (MCP `include_bundled=true`) indexes the JavaScript bundles, respecting user exclusions and bypassing the shared cache. Source maps stay unindexed; inspect them with text tools.
97
+
98
+ C/C++ uses `compile_commands.json` when present for header classification and include paths. Project C/C++ function-like macros and Rust `macro_rules!` invocations are expanded, and what they generate is indexed at the invocation (`[via macro NAME]`). This is portable AST analysis, not a compiler build: macros, templates, generated code, reflection and external dependency semantics can stay unverified, and no conditional branch is asserted as the one a build activates.
172
99
 
173
100
  ## Breaking-change protocol
174
101
 
@@ -182,94 +109,7 @@ own contract: successful empty results exit 0; command errors exit 1 with
182
109
 
183
110
  ## Deletion protocol
184
111
 
185
- Treat `deadcode` as a candidate generator. Before deletion, inspect `usages`, `impact`, `entrypoints`, `api`, and `repo --sections=health --deep`; then corroborate with the compiler/type checker and tests. Computed dispatch such as `handlers[key]()` is a reported blind spot; registry members reached by a modeled computed receiver are withheld. Statically named reflection such as `getattr(obj, "run")` is positive liveness evidence, so every matching member spelling is withheld; recognized dynamic reflection is counted and warned because it cannot be attributed to one member. Unknown decorators/annotations and member-assigned event handlers are also withheld by default because they can be the registration itself. All remaining candidates are still review-only. Never delete solely from `deadcode` or an observed-text-zero result.
186
-
187
- `usages` includes comment/string/docstring occurrences and non-code text
188
- (JSX children, HTML markup and attributes) in an `OTHER TEXT` section unless
189
- `--code-only` is set, so it lists every line the `ACCOUNT` counts. This is a
190
- literal-name inventory, not exact target binding. Identifier boundaries are
191
- Unicode-aware and match `grep -w`: `hit` never matches inside `hitΔ`, while
192
- `$` is a boundary (`buy${...}`, `$fail`, `ws$close()` all count).
193
-
194
- Aliased and qualified calls resolve in every language: Rust `use m::f as g; g()`
195
- is a caller of `f` (listed as a beyond-text caller, since the line holds no
196
- target token); Java `pkg.Type.method()` and C# `Ns.Type.Method()` /
197
- `using T = Ns.Type; T.Method()` pick the type the qualifier names when several
198
- same-name types exist. A qualifier the resolver cannot place stays visible as
199
- `method-ambiguous`, never confirmed by first-definition order.
200
-
201
- `endpoints` labels test routes and requests with `[test]` (JSON `isTest`).
202
- Use `--exclude-tests` for a production inventory or `--in=api/` for a directory.
203
-
204
- `endpoints` recognizes client receivers by evidence (a receiver typed to an
205
- HTTP client class, or bound to a pytest fixture that constructs one), not only
206
- by name. Request-shaped calls with a path literal on an unrecognized receiver
207
- are listed under `Possible client requests` (JSON `uncertainRequests`),
208
- counted in `meta`, never in the inventory. `search` treats its term literally by default; pass `--regex` only
209
- when regular-expression semantics are intended. Ordinary regex patterns run
210
- through an RE2-compatible linear-time engine; unsafe nested repetition is
211
- rejected, and unsupported advanced syntax should be handed to ripgrep.
212
-
213
- `find` activity counts are definition-pinned: confirmed plus visible unverified
214
- call candidates. Calls proved to belong to another same-name target are
215
- disclosed separately and excluded from the activity total.
216
- Broad queries rank candidates by inexpensive approximate usage totals before
217
- applying the row limit; only returned definitions receive caller adjudication.
218
- The selection note discloses that approximation. `find`, text `search`,
219
- `deadcode`, `api`, and `repo --sections=files` default to at most 500 results
220
- (structural `search`: 50). Use an explicit `--limit=N` to request more;
221
- `usages` and `--lines` have no default row cap.
222
-
223
- Automatic test filtering follows the language's conventions: Python `spec.py`
224
- and `chart_spec.py` are production paths; `test_*.py`, `*_test.py`, and test
225
- directories remain test paths. Structural search discloses hidden test files,
226
- including empty results; `--include-tests` gives the full indexed inventory.
227
- Explicit `--exclude=spec` still means the requested path exclusion.
228
-
229
- Public JSON source `file` fields are relative to `meta.pathBase` (the absolute
230
- project root). Dependency edge paths use the same base. Both absolute and
231
- relative indexed-file handles are accepted. Definition handles retain their
232
- decorator span; use `nameLine` for the name token rather than joining usages
233
- to a handle's start line.
234
-
235
- Callable references passed to another function remain visible when a project
236
- method or function could be their target. An ordinary attribute read with no
237
- callable member candidate stays a non-call reference in ACCOUNT and `usages`.
238
- The caller model includes callback dependencies; it does not prove that the
239
- receiving function invokes every passed callable.
240
-
241
- `audit-async` checks recognized async producers. In JS/TS/HTML it also checks
242
- captured promises used in arithmetic, conditions, or resolved-value member
243
- access within the same lexical scope. Awaiting, returning, promise handlers,
244
- reassignment, and shadowed bindings are distinguished. It is a bounded AST
245
- audit, not a compiler-wide proof that every missing await has been found.
246
-
247
- For `plan --rename-to`, the selected declaration is only the starting point.
248
- When the index proves the relationship, the rename unit closes over
249
- overload/signature groups, base and override declarations, Rust trait slots,
250
- Go interface slots and their satisfiers, exact call and value-reference tokens,
251
- imports/exports, Python `__all__` strings, and module-attribute references.
252
- Exact token/expression spans keep a foreign same-named occurrence on the same
253
- line unchanged. Open external interfaces, incomplete ownership, unresolved
254
- dispatch, or an inexact token route to `needsReview` instead of a synthesized
255
- edit. Comment/string occurrences in indexed source appear in `reviewItems` and
256
- are never rewritten automatically; the result also tells you to search
257
- documentation, configuration, generated files, and unsupported languages for
258
- the old spelling. Read `changeSummary` and every review item. `plan` previews
259
- only: it does not modify files, run a compiler, or prove runtime compatibility.
260
-
261
- For `deps --cycles`, `eager` means every edge executes at module scope.
262
- `deferred` means at least one edge does not: a function-local import (Python
263
- `def`/`lambda` bodies; JS/TS `require()`/`import()` inside any function,
264
- including `() => require()` thunks), a Python `if TYPE_CHECKING:` import, or a
265
- TypeScript type-only import. Each deferred edge names its reason. A deferred
266
- chain is not an unconditional import-time cycle; function-local chains stay
267
- visible because invoking that function during initialization can still matter.
268
- Cycles are enumerated completely and independently of build history (capped at
269
- 500 with a disclosed truncation; groups above 2000 files skip enumeration);
270
- `CYCLE GROUPS` and the files-in-cycles count remain complete even when the
271
- enumerated cycle counts are lower bounds. `CYCLE GROUPS` lists each strongly connected
272
- file set, the unit a refactor has to break.
112
+ `deadcode` is a candidate generator, never deletion proof. Before deleting, inspect `usages`, `impact`, `entrypoints`, `api`, and `repo --sections=health --deep`, then corroborate with the compiler/type checker and tests. Members that reflection (exact names or literal-fragment patterns), computed dispatch, runtime protocols (Python dunders, Java serialization callbacks, C# pattern members, JS `toJSON`/`then`), unknown decorators, event-handler assignment, an outside base class, or macro expansion may reach are withheld or warned; the `deadcode` notes in the command reference list them. Never delete solely from `deadcode` or an observed-text-zero result.
273
113
 
274
114
  ## Efficient use
275
115
 
@@ -279,26 +119,8 @@ file set, the unit a refactor has to break.
279
119
  - Use `--all` only when that command's output reports a supported cap; otherwise narrow the query or raise `--max-chars`.
280
120
  - Use `search` or ordinary repository search for text, filenames, configuration, and unsupported syntax.
281
121
 
282
- Read [references/commands.md](references/commands.md) for all public commands and flags. Read [references/trust-contract.md](references/trust-contract.md) before building automation that gates changes on UCN output.
283
-
284
-
285
- ### Inspect confirmation provenance
286
-
287
- Caller and callee JSON carries compact `provenance`: `rule`, contributing `rules`
288
- when there is more than one, `validation`, and the receiver's source and origin
289
- line when recorded. Incomplete proofs include a `diagnostic`, also shown in text.
290
- Callees retain compact `siteProvenance` for each distinct occurrence; their summary
291
- uses the weakest confirmed site's rule. Exclusions expose counts by rule and
292
- validation under `account.excluded.evidenceSummary`. Full declaration, import,
293
- and member-lookup facts remain on engine results and in oracle reports.
294
-
295
- A lone project owner of a method name does not identify an untyped receiver.
296
- Such candidates stay unverified with `single-owner`; importing the class does not
297
- change that. `provenance-incomplete` means the available facts cannot establish
298
- this declaration. Inspect the site and diagnostic before editing it. Neither
299
- reason is permission to discard a possible caller. `validation: unsupported`
300
- means the witness collector does not yet cover that path (for example a wildcard
301
- re-export or an external inherited member). Its existing classification is kept
302
- in report-only mode; it is not a validated proof. Missing or inconsistent facts
303
- on a supported lookup still route unverified. Full rule migration is tracked as
304
- #356. Ordinal evidence weights are not probabilities.
122
+ ## References
123
+
124
+ - [references/commands.md](references/commands.md): every command, flag and default, exit codes, and per-command notes (`find` activity counts, `usages` inventory, `plan` rename closure, `endpoints` matching, `deadcode` withholding, `audit-async` findings, `deps --cycles`).
125
+ - [references/trust-contract.md](references/trust-contract.md): evidence classes, trust lines, account fields, provenance, truncation metadata, and a machine policy for automation that gates changes on UCN output.
126
+ - [references/resolution-rules.md](references/resolution-rules.md): how UCN decides identity per language (what confirms, what stays unverified with which reason, what is excluded).