ucn 4.0.2 → 4.1.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.
Files changed (46) hide show
  1. package/.claude/skills/ucn/SKILL.md +31 -7
  2. package/README.md +90 -51
  3. package/cli/index.js +199 -94
  4. package/core/account.js +3 -1
  5. package/core/analysis.js +322 -304
  6. package/core/bridge.js +13 -8
  7. package/core/cache.js +109 -19
  8. package/core/callers.js +969 -77
  9. package/core/check.js +19 -8
  10. package/core/deadcode.js +368 -40
  11. package/core/discovery.js +31 -11
  12. package/core/entrypoints.js +149 -17
  13. package/core/execute.js +330 -43
  14. package/core/graph-build.js +61 -10
  15. package/core/graph.js +282 -61
  16. package/core/imports.js +72 -3
  17. package/core/output/analysis-ext.js +70 -10
  18. package/core/output/analysis.js +52 -33
  19. package/core/output/check.js +4 -1
  20. package/core/output/endpoints.js +8 -3
  21. package/core/output/extraction.js +12 -1
  22. package/core/output/find.js +23 -9
  23. package/core/output/graph.js +32 -9
  24. package/core/output/refactoring.js +147 -49
  25. package/core/output/reporting.js +104 -5
  26. package/core/output/search.js +30 -3
  27. package/core/output/shared.js +31 -4
  28. package/core/output/tracing.js +22 -11
  29. package/core/parser.js +8 -6
  30. package/core/project.js +167 -7
  31. package/core/registry.js +20 -16
  32. package/core/reporting.js +131 -13
  33. package/core/search.js +270 -55
  34. package/core/shared.js +240 -1
  35. package/core/stacktrace.js +23 -1
  36. package/core/tracing.js +278 -36
  37. package/core/verify.js +352 -349
  38. package/languages/go.js +29 -17
  39. package/languages/index.js +56 -0
  40. package/languages/java.js +133 -16
  41. package/languages/javascript.js +215 -27
  42. package/languages/python.js +113 -47
  43. package/languages/rust.js +89 -26
  44. package/languages/utils.js +35 -7
  45. package/mcp/server.js +69 -30
  46. package/package.json +5 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: ucn
3
- description: "Code intelligence toolkit — extract functions, trace callers, analyze impact, detect dead code without reading whole files. PREFER over grep+read when you need: who calls a function, what breaks if you change it, or the full call chain of a pipeline. One `ucn about` replaces 3-4 grep+read cycles. One `ucn trace` maps an entire execution flow without reading any files. Works on JS/TS, Python, Go, Rust, Java, HTML. Skip for plain text search or codebases under 500 LOC."
3
+ description: "Code intelligence toolkit — extract functions, trace callers, analyze impact, detect dead code without reading whole files. PREFER over grep+read when you need: who calls a function, what breaks if you change it, or the full call chain of a pipeline. `ucn orient` gives a one-screen overview of any new repo. One `ucn about` replaces 3-4 grep+read cycles. One `ucn trace` maps an entire execution flow without reading any files. Works on JS/TS, Python, Go, Rust, Java, HTML. Skip for plain text search or codebases under 500 LOC."
4
4
  allowed-tools: Bash(ucn *), Bash(npx ucn *)
5
5
  argument-hint: "[command] [symbol-name] [--flags]"
6
6
  ---
@@ -13,6 +13,7 @@ Extract functions, trace call chains, find callers, and detect dead code — wit
13
13
 
14
14
  **Use UCN when the next action would be:**
15
15
 
16
+ - "I just opened this repo, where do I start?" → `ucn orient` — one screen: size, top dirs, hot functions, entry points, trust verdict
16
17
  - "Let me grep for all callers of this function" → `ucn impact <name>` — finds every call site, grouped by file, with args shown
17
18
  - "Let me read this 800-line file to find one function" → `ucn fn <name> --file=<hint>` — extracts just that function
18
19
  - "Let me trace through this code to understand the flow" → `ucn trace <name> --depth=3` — shows the full call tree without reading any files
@@ -88,7 +89,7 @@ ucn class MarketDataFetcher
88
89
 
89
90
  ### 6. `deadcode` — Find unused code
90
91
 
91
- Lists all functions and classes with zero callers across the project. Framework entry points (Express routes, Spring controllers, Celery tasks, etc.) and exported/public API symbols — including methods of exported classes in JS/TS/Python — are automatically excluded (`--include-exported` audits them). Interface/trait method declarations are labeled `[declared on interface X — contract surface, not executable code]`: unreferenced is true, but deleting one changes the API contract, not dead logic.
92
+ Lists all functions and classes with zero callers across the project — class-like symbols (classes, structs, interfaces, traits, enums, namespaces) are audited alongside functions. Framework entry points (Express routes, Spring controllers, Celery tasks, etc.) and exported/public API symbols — including methods of exported classes in JS/TS/Python — are automatically excluded (`--include-exported` audits them). Interface/trait method declarations are labeled `[declared on interface X — contract surface, not executable code]`: unreferenced is true, but deleting one changes the API contract, not dead logic. Symbols whose only call sites sit inside their own same-name definitions are claimed and marked `[only self-references — recursive]` — the group is unreachable from outside.
92
93
 
93
94
  ```bash
94
95
  ucn deadcode # Everything
@@ -149,6 +150,17 @@ ucn entrypoints --file=routes/ # Scoped to files
149
150
  ucn entrypoints --exclude-tests # Hide test fixtures (JUnit @Test, pytest, Rust #[test], etc.)
150
151
  ```
151
152
 
153
+ ### 11. `orient` — First command in a new repo
154
+
155
+ One screen: size + language mix, densest directories, most-called production functions, entry-point counts, and the trust verdict. Composes what would otherwise take four calls (`toc` + `stats --hot` + `entrypoints` + `doctor`).
156
+
157
+ ```bash
158
+ ucn orient # run this before anything else in an unfamiliar codebase
159
+ ucn orient --top=15 # longer dir/hot lists
160
+ ```
161
+
162
+ The `Next:` line suggests concrete follow-ups, starting with `about` on the hottest production function.
163
+
152
164
  ## When to Use the Other Commands
153
165
 
154
166
  | Situation | Command | What it does |
@@ -164,6 +176,7 @@ ucn entrypoints --exclude-tests # Hide test fixtures (JUnit @Test, pyte
164
176
  | Understanding who depends on a file | `ucn exporters <file>` | Which files import it |
165
177
  | See what a file exports | `ucn file-exports <file>` | All exported functions, classes, variables with signatures |
166
178
  | Quick project overview | `ucn toc` | Every file with function/class counts and line counts |
179
+ | Just entered an unfamiliar repo | `ucn orient` | One screen: size, top dirs, hot functions, entry points, trust verdict. Run it first |
167
180
  | Project complexity stats | `ucn stats` | File counts, symbol counts, lines by language. `--functions` for per-function line counts. `--hot --top=N` for the most-called functions (orientation primitive on a new repo) |
168
181
  | Find by glob pattern | `ucn find "handle*"` | Locate definitions matching a glob (supports * and ?) |
169
182
  | Text search with context | `ucn search term --context=3` | Like grep -C 3, shows surrounding lines |
@@ -217,7 +230,7 @@ ucn entrypoints --exclude-tests # Hide test fixtures (JUnit @Test, pyte
217
230
 
218
231
  `audit-async` is the focused tool for the `awaited=false` case across an entire async function body.
219
232
 
220
- ## Reading Tiered Output (about / context / impact / trace / blast / reverse-trace / affected-tests)
233
+ ## Reading Tiered Output (about / context / impact / trace / blast / reverse-trace / affected-tests / diff-impact / verify / plan / check)
221
234
 
222
235
  Caller answers are a **partition of every text occurrence** of the symbol — nothing is silently hidden. Sections:
223
236
 
@@ -232,7 +245,18 @@ Caller answers are a **partition of every text occurrence** of the symbol — no
232
245
 
233
246
  Resolution labels in `evidence:` lines (high to low): `exact-binding` (0.98, import/binding evidence) · `same-class` (0.92) · `receiver-hint` (0.80, inferred receiver type) · `scope-match` (0.65, import/receiver-binding scope evidence) · `name-only` (0.40) · `uncertain` (0.25). Confirmed tier = scope-match and above. JSON output keeps per-edge decimals plus `tier`.
234
247
 
235
- Flags: `--min-confidence=0.7` filters confirmed edges (hidden count appears in FILTERED). `--include-uncertain` is an **implied no-op** for about/context/impact/trace/blast/reverse-trace/affected-tests (everything is shown, tiered); it keeps its meaning for `smart`/`verify`. `--include-methods` is an implied no-op for about/context/impact.
248
+ Flags: `--min-confidence=0.7` filters confirmed edges (hidden count appears in FILTERED). `--include-uncertain` and `--include-methods` have **no effect** on tiered commands (about/context/impact/trace/blast/reverse-trace/affected-tests/diff-impact/verify/plan/smart) everything is always shown, tiered by evidence.
249
+
250
+ ### Refactor commands run the same contract (v4)
251
+
252
+ - `verify` arg-checks the **confirmed** band only; candidates without evidence render in `UNVERIFIED CALL SITES (N)` with reasons and are NOT arg-checked (they may target another symbol). A wrong-arity method call with binding evidence is flagged **by default** now. The `ACCOUNT:` line reconciles.
253
+ - `plan` plans changes for confirmed sites; `UNVERIFIED CALL SITES` lists sites that MAY also need the change — review them before refactoring. Plan and verify agree by construction.
254
+ - `diff-impact` reports per-changed-function confirmed `Callers` + `Unverified call sites` + a per-symbol `ACCOUNT:` line. `check` shows `N callers (+M unverified)` per changed function; ORPHAN requires zero candidates in BOTH tiers.
255
+ - `context`/`smart` also account the **callee** side: `CALLEES — UNVERIFIED (N)` entries + a `CALLEE ACCOUNT:` arithmetic line.
256
+
257
+ ### Advisory commands self-label
258
+
259
+ `related`, `example`, `stacktrace`, and `endpoints --bridge` print an `Advisory:` line (and carry an `advisory` field in JSON): their answers are ranked heuristics, not verified claims. Contracted commands carry accounts; advisory commands say so — there is no third category.
236
260
 
237
261
  ### Tree commands (trace / blast / reverse-trace / affected-tests)
238
262
 
@@ -281,7 +305,7 @@ ucn [target] <command> [name] [--flags]
281
305
  | `--expand-unverified` | `blast`/`reverse-trace`: follow unverified caller edges in the tree. Downstream nodes are marked as unverified chains — possible, not confirmed, impact |
282
306
  | `--include-tests` | Include test files in usage counts (`about`) and results (`find`, `usages`, `deadcode`). Callers always include tests. |
283
307
  | `--exclude-tests` | Exclude test entries from `entrypoints` (tests are included by default since they ARE entry points). |
284
- | `--include-methods` | Include `obj.method()` calls in caller/callee analysis. Implied (no-op) for `about`/`context`/`impact` — method calls are always analyzed and tiered by receiver evidence. Applies to `verify`, `blast`, `smart`, `trace`, `reverse-trace`, `affected-tests` |
308
+ | `--include-methods` | Include `obj.method()` callee expansion in `trace`/`smart`. No effect on caller-direction commands (`about`/`context`/`impact`/`verify`/`blast`/`reverse-trace`/`affected-tests`) — method calls are always analyzed and tiered by receiver evidence |
285
309
  | `--base=<ref>` | Git ref for diff-impact (default: HEAD) |
286
310
  | `--staged` | Analyze staged changes (diff-impact) |
287
311
  | `--no-cache` | Force re-index after editing files |
@@ -292,7 +316,7 @@ ucn [target] <command> [name] [--flags]
292
316
  | `--hot` | List top N most-called functions in `stats` (use with `--top=N`, default 10). Best orientation primitive when entering a new repo |
293
317
  | `--diverse` | Cluster `example` call sites by argument shape and return one representative per cluster (use with `--top=N`, default 3) |
294
318
  | `--git` | Attach git enrichment to `about` / `brief`: last commit (ISO + author) and recent change count (last 30 days). Skipped silently when not a git repo |
295
- | `--json` | Machine-readable JSON output. Some commands wrap in `{meta, data}` (e.g., `find`, `deadcode`); others return flat objects (e.g., `about`, `impact`, `verify`, `plan`, `imports`) — check each command's output shape |
319
+ | `--json` | Machine-readable JSON output. Most commands wrap in `{meta, data}` (e.g., `find`, `deadcode`, `context`, `verify`, `plan`, `diff-impact` — completeness signals and the ACCOUNT live in `meta`); `about` and `impact` return their full result object flat — check each command's output shape |
296
320
  | `--code-only` | Exclude matches in comments and strings (`search`/`usages`) |
297
321
  | `--with-types` | Include related type definitions in `smart`/`about` output |
298
322
  | `--detailed` | Show full symbol listing per file in `toc` |
@@ -303,7 +327,7 @@ ucn [target] <command> [name] [--flags]
303
327
  | `--max-lines=N` | Max source lines for `class` (large classes show summary by default) |
304
328
  | `--case-sensitive` | Case-sensitive text search (default: case-insensitive) |
305
329
  | `--exact` | Exact name match only in `find`/`typedef` (no substring) |
306
- | `--include-uncertain` | Include ambiguous/uncertain matches. Implied (no-op) for `about`/`context`/`impact` — unverified callers are always shown in their own tier. Applies to `blast`, `smart`, `trace`, `reverse-trace`, `affected-tests` |
330
+ | `--include-uncertain` | No effect on tiered commands — unverified candidates are always shown in their own section with reasons |
307
331
  | `--hide-confidence` | Hide confidence scores (shown by default) in `context`/`about` |
308
332
  | `--min-confidence=N` | Filter edges below confidence threshold (e.g., `--min-confidence=0.7` keeps only high-confidence edges) |
309
333
  | `--calls-only` | Only show call/test-case matches in `tests` (skip file-level results) |
package/README.md CHANGED
@@ -34,13 +34,14 @@ UCN is deliberately lightweight:
34
34
  - **No language servers** - tree-sitter does the parsing, no compilation needed
35
35
  - **MCP is optional** - only needed if you connect UCN to an AI agent, the CLI and Skill work on their own
36
36
 
37
- And it's built to be **trusted**: every "who calls this?" splits into what UCN can prove and what it can't — each flagged with a reason, nothing silently dropped, [measured in CI against real compilers and language servers](#answers-you-can-trust).
37
+ And it's built to be **trusted**. grep hands you raw text matches to verify yourself; UCN splits every "who calls this?" into what it can prove and what it can't — each flagged with a reason, nothing silently dropped. That claim is measured, not promised: CI re-derives UCN's answers from the real compilers and language servers (ts-morph, pyright, gopls, rust-analyzer, jdtls) across ten production repos — **96.6–100% confirmed-tier precision, zero unexplained call edges, [or the build fails](#answers-you-can-trust)**.
38
38
 
39
39
  ---
40
40
 
41
41
  ```bash
42
- npm install -g ucn
42
+ npm install -g ucn # Node.js 20+
43
43
 
44
+ ucn orient # first look at any repo: size, hot spots, trust
44
45
  ucn trace main --depth=3 # full execution flow
45
46
  ucn about handleRequest # definition + callers + callees + tests
46
47
  ucn impact handleRequest # every call site with arguments
@@ -53,28 +54,28 @@ ucn deadcode --exclude=test # unused code, AST-verified
53
54
  $ ucn trace build --depth=2
54
55
 
55
56
  build
56
- ├── detectProjectPattern (core/discovery.js:431) 1x
57
+ ├── detectProjectPattern (core/discovery.js:450) 1x
57
58
  ├── parseGitignore (core/discovery.js:131) 1x
58
- ├── expandGlob (core/discovery.js:191) 1x
59
- │ ├── parseGlobPattern (core/discovery.js:227) 1x
60
- │ ├── walkDir (core/discovery.js:284) 1x
61
- │ └── compareNames (core/discovery.js:170) 1x
59
+ ├── expandGlob (core/discovery.js:199) 1x
60
+ │ ├── parseGlobPattern (core/discovery.js:238) 1x
61
+ │ ├── walkDir (core/discovery.js:295) 1x
62
+ │ └── compareNames (core/discovery.js:178) 1x
62
63
  ├── parallelBuild (core/parallel-build.js:25) 1x
63
- ├── indexFile (core/project.js:310) 1x
64
- │ ├── addSymbol (core/project.js:410) 4x
65
- │ ├── detectLanguage (languages/index.js:288) 1x
64
+ ├── indexFile (core/project.js:397) 1x
65
+ │ ├── addSymbol (core/project.js:502) 4x
66
+ │ ├── detectLanguage (languages/index.js:344) 1x
66
67
  │ ├── parse (core/parser.js:69) 1x
67
68
  │ ├── extractImports (core/imports.js:19) 1x
68
69
  │ └── extractExports (core/imports.js:44) 1x
69
- ├── buildImportGraph (core/project.js:648) 1x
70
- └── buildInheritanceGraph (core/project.js:653) 1x
70
+ ├── buildImportGraph (core/project.js:798) 1x
71
+ └── buildInheritanceGraph (core/project.js:803) 1x
71
72
  … calls UCN can't prove a receiver for (arr.push(), obj.get()) show as
72
73
  [unverified] leaves — abridged here
73
74
 
74
- CALLEE ACCOUNT: 23 nodes · 329 call sites = 43 confirmed + 151 unverified + 34 builtin + 101 excluded
75
+ CALLEE ACCOUNT: 26 nodes expanded · 394 call sites = 61 confirmed + 162 unverified (162 uncertain-receiver) + 68 external/builtin + 103 excluded
75
76
  ```
76
77
 
77
- One command, no files opened — and the `CALLEE ACCOUNT:` line proves all 329 calls were sorted, nothing dropped.
78
+ One command, no files opened — and the `CALLEE ACCOUNT:` line proves all 394 calls were sorted, nothing dropped.
78
79
 
79
80
  ---
80
81
 
@@ -87,19 +88,19 @@ $ ucn about expandGlob
87
88
 
88
89
  expandGlob (function)
89
90
  ════════════════════════════════════════════════════════════
90
- core/discovery.js:191-222 → core/discovery.js:191:expandGlob
91
+ core/discovery.js:199-233 → core/discovery.js:199:expandGlob
91
92
  expandGlob (pattern: string, options: number = {}) : string[]
92
93
 
93
- USAGES: 6 total
94
- 3 calls, 3 imports, 0 references
94
+ USAGES: 8 total
95
+ 3 calls, 3 imports, 2 references
95
96
 
96
97
  CALLERS — CONFIRMED (7, 3 prod + 4 test):
97
98
  evidence: scope-match (all)
98
- cli/index.js:1201 [runGlobCommand]
99
+ cli/index.js:1267 [runGlobCommand]
99
100
  const files = expandGlob(pattern);
100
- core/cache.js:466 [isCacheStale]
101
+ core/cache.js:548 [isCacheStale] [unreachable]
101
102
  const currentFiles = expandGlob(pattern, globOpts);
102
- core/project.js:192 [build]
103
+ core/project.js:257 [build]
103
104
  files = expandGlob(pattern, globOpts);
104
105
  test callers:
105
106
  test/integration.test.js:167
@@ -108,12 +109,12 @@ CALLERS — CONFIRMED (7, 3 prod + 4 test):
108
109
 
109
110
  CALLEES (3):
110
111
  evidence: exact-binding (all)
111
- parseGlobPattern [utility] - core/discovery.js:227 (1x)
112
- walkDir [utility] {fs} - core/discovery.js:284 (1x)
113
- compareNames [utility] - core/discovery.js:170 (1x)
112
+ parseGlobPattern [utility] - core/discovery.js:238 (1x)
113
+ walkDir [utility] {fs} - core/discovery.js:295 (1x)
114
+ compareNames [utility] - core/discovery.js:178 (1x)
114
115
 
115
116
  ACCOUNT: "expandGlob" occurs on 14 lines in 6 files: 7 confirmed, 0 unverified,
116
- 7 non-call (4 import, 1 definition, 1 reference, 1 other-text), 0 other-target, 0 unaccounted
117
+ 7 non-call (4 import, 1 definition, 2 reference, 0 other-text), 0 other-target, 0 unaccounted
117
118
 
118
119
  TESTS: 5 matches in 1 file(s)
119
120
  ```
@@ -127,30 +128,31 @@ UCN doesn't just find a name — it tells you how sure it is. Every answer from
127
128
  ```
128
129
  $ ucn impact saveCache
129
130
 
130
- CALL SITES: 2 confirmed + 9 unverified
131
+ CALL SITES: 2 confirmed + 11 unverified
131
132
 
132
133
  test/regression-go.test.js (2 calls)
133
- :2004
134
+ :2007
134
135
  saveCache(index, cachePath);
135
136
 
136
- UNVERIFIED CALL SITES (9) — call syntax, no binding/receiver evidence:
137
- mcp/server.js:779: index.saveCache(); (method-ambiguous)
138
- test/cache.test.js:1779: index.saveCache(); (method-ambiguous)
139
- ... (7 more)
137
+ UNVERIFIED CALL SITES (11) — call syntax, no binding/receiver evidence:
138
+ core/project.js:2126: saveCache(cachePath) { ... } (call-not-resolved)
139
+ mcp/server.js:810: try { index.saveCache(); } catch (_) ... (method-ambiguous)
140
+ test/cache.test.js:1804: index.saveCache(); (method-ambiguous)
141
+ ... (8 more)
140
142
 
141
- ACCOUNT: "saveCache" occurs on 47 lines in 8 files: 2 confirmed, 9 unverified,
142
- 9 non-call (2 import, 1 definition, 0 reference, 6 other-text), 27 other-target, 0 unaccounted
143
+ ACCOUNT: "saveCache" occurs on 55 lines in 8 files: 2 confirmed, 11 unverified,
144
+ 11 non-call (2 import, 1 definition, 1 reference, 7 other-text), 31 other-target, 0 unaccounted
143
145
  ```
144
146
 
145
- UCN sorts every one of the 47 places the name appears:
147
+ UCN sorts every one of the 55 places the name appears:
146
148
 
147
149
  - **2 confirmed** — call sites it can prove resolve to *this* `saveCache`.
148
- - **9 unverified** — real call sites it found but won't claim. `index.saveCache()` has an untyped receiver, so UCN can't prove which `saveCache` runs; it shows the site and the reason (`method-ambiguous`) instead of guessing.
149
- - **27 other-target** — occurrences that belong to a *different* `saveCache`, kept separate so they never pollute the answer.
150
- - **9 non-call** — imports, the definition, plain text.
150
+ - **11 unverified** — real call sites it found but won't claim. `index.saveCache()` has an untyped receiver, so UCN can't prove which `saveCache` runs; it shows the site and the reason (`method-ambiguous`) instead of guessing.
151
+ - **31 other-target** — occurrences that belong to a *different* `saveCache`, kept separate so they never pollute the answer.
152
+ - **11 non-call** — imports, the definition, plain text.
151
153
  - **`0 unaccounted`** — the partition is complete. Nothing was dropped on the floor.
152
154
 
153
- The payoff: a **confirmed** answer is safe to refactor against, and an empty result with `0 unaccounted` means the symbol truly has no callers. UCN never hides a callerand never invents one.
155
+ The payoff: a **confirmed** answer is safe to refactor against, and a clean zero no confirmed, no unverified, `0 unaccounted` is a trustworthy zero (measured: 68 of 69 clean-zero samples across the 10-repo board agree with the compiler oracles; the one disagreement is a `new X()` on an old-style constructor function, which lands in the non-call counts, still visible). One caveat before deleting anything: callers aren't the only usages if the NON-CALL counts are nonzero, run `ucn usages` to see what they are.
154
156
 
155
157
  ### Measured against ground truth
156
158
 
@@ -161,10 +163,10 @@ This isn't a promise — it's a gate. CI re-derives UCN's caller answers from re
161
163
  | TypeScript / JavaScript | ts-morph | 99.4–100% |
162
164
  | Python | pyright (LSP) | 97.7–99.9% |
163
165
  | Go | gopls | 99.9–100% |
164
- | Rust | rust-analyzer | 98.9–100% |
165
- | Java | jdtls | 96.2% |
166
+ | Rust | rust-analyzer | 99.0–100% |
167
+ | Java | jdtls | 96.6% |
166
168
 
167
- Ten pinned real-world repos (zod, express, httpx, rich, cobra, grpc-go, ripgrep, cursive, gson, preact-signals), three sampling seeds, every run gated at `missing-unexplained = 0`. The tree commands — `trace`, `blast`, `reverse-trace`, `affected-tests` — follow the same rule: confirmed trunk, uncertain branches flagged (`--expand-unverified` to follow). Run `ucn doctor` for the trust report on *your* repo.
169
+ Ten pinned real-world repos (zod, express, httpx, rich, cobra, grpc-go, ripgrep, cursive, gson, preact-signals), three sampling seeds, every run gated at `missing-unexplained = 0` — plus a weekly fresh-repo arm: two unpinned repos the engine was never tuned on, same gate. The tree commands — `trace`, `blast`, `reverse-trace`, `affected-tests` — follow the same rule: confirmed trunk, uncertain branches flagged (`--expand-unverified` to follow). Run `ucn doctor` for the trust report on *your* repo.
168
170
 
169
171
  ## Change code without breaking things
170
172
 
@@ -237,6 +239,36 @@ Changed: 3 functions
237
239
 
238
240
  ## Get the lay of the land in a new repo
239
241
 
242
+ One command answers "what is this codebase?" — size and language mix, where the code lives, the most-called production functions, entry points, and how far to trust the index:
243
+
244
+ ```
245
+ $ ucn orient
246
+
247
+ PROJECT ORIENTATION — /path/to/project
248
+ ════════════════════════════════════════════════════════════
249
+ 169 files · 2111 symbols · javascript 67%, rust 8%, typescript 8%, java 7%, go 5%, python 5%
250
+
251
+ TOP DIRS (by symbols):
252
+ core 516 symbols · 29 file(s)
253
+ languages 282 symbols · 8 file(s)
254
+ test 209 symbols · 29 file(s)
255
+ core/output 142 symbols · 14 file(s)
256
+ ...
257
+
258
+ HOT (most-called production functions, top 8 of 1028):
259
+ execute — 1124 call(s) · core/execute.js:1608
260
+ ProjectIndex.build — 340 call(s) · core/project.js:221
261
+ getParser — 150 call(s) · languages/index.js:312
262
+ ...
263
+
264
+ ENTRY POINTS: 389 — test 284, runtime 72, http 32, di 1
265
+ TRUST: MEDIUM — 41 dynamic import(s), 13 eval, 6 reflection (ucn doctor for detail)
266
+
267
+ Next: ucn about execute · ucn toc --detailed · ucn stats --hot --top=20 · ucn doctor --deep
268
+ ```
269
+
270
+ Then drill in:
271
+
240
272
  ```
241
273
  $ ucn brief fetch_user
242
274
  fetch_user(user_id: int): dict
@@ -251,9 +283,9 @@ fetch_user(user_id: int): dict
251
283
  $ ucn doctor
252
284
 
253
285
  UCN Trust Report — /path/to/project
254
- Index: 144 files, 1569 symbols
255
- Languages: javascript (74%), typescript (13%), java (4%), python (3%), rust (3%), go (3%)
256
- Cache: fresh, 221ms build
286
+ Index: 169 files, 2104 symbols
287
+ Languages: javascript (72%), typescript (14%), java (4%), python (4%), rust (4%), go (3%)
288
+ Cache: fresh, 344ms build
257
289
  ...
258
290
  Trust level: HIGH
259
291
  ```
@@ -289,10 +321,10 @@ Test files to run (20):
289
321
  POSSIBLY AFFECTED (1) — reachable only through unverified call edges:
290
322
  doctor
291
323
 
292
- Uncovered (10): runGlobCommand, main, runProjectCommand, runFileCommand, evaluateRepo, ...
324
+ Uncovered (12): runGlobCommand, main, isCacheStale, runProjectCommand, runFileCommand, ...
293
325
  ⚠ These affected functions have no test references
294
326
 
295
- Summary: 15 affected → 20 test files, 5/15 functions covered (33%) · 1 possibly affected (unverified chains)
327
+ Summary: 15 affected → 20 test files, 3/15 functions covered (20%) · 1 possibly affected (unverified chains)
296
328
  ```
297
329
 
298
330
  The confirmed closure is what you run; `POSSIBLY AFFECTED` lists functions reached only through unverified edges — extra tests worth a look, kept separate.
@@ -300,17 +332,24 @@ The confirmed closure is what you run; `POSSIBLY AFFECTED` lists functions reach
300
332
  ## Find unused code
301
333
 
302
334
  ```
303
- $ ucn deadcode --exclude=test
335
+ $ ucn deadcode --exclude=test # run on ripgrep
304
336
 
305
- Dead code: 2 unused symbol(s)
337
+ Dead code: 8 unused symbol(s)
306
338
 
307
- core/output/analysis.js
308
- [ 29- 32] formatHistogramLine (function)
309
- [ 41- 44] shouldShowReachability (function)
339
+ crates/globset/src/serde_impl.rs
340
+ [ 38- 42] Glob.deserialize (method)
341
+ [ 70- 74] GlobSet.deserialize (method)
342
+ crates/matcher/src/lib.rs
343
+ [ 397- 399] Captures.as_match (method)
344
+ [ 669- 678] Matcher.try_find_iter (method) [only self-references — recursive]
345
+ [ 796- 806] Matcher.try_captures_iter (method) [only self-references — recursive]
346
+ ...
310
347
 
311
- 353 exported symbol(s) excluded (all have callers). Use --include-exported to audit them.
348
+ 921 exported symbol(s) excluded from the audit (public API may have external callers). Use --include-exported to audit them.
312
349
  ```
313
350
 
351
+ Classes, structs, traits, and enums are audited alongside functions. Symbols whose only call sites live inside their own definitions are claimed too, marked `[only self-references — recursive]`. Deadcode claims are re-derived against compiler/LSP ground truth in CI — a default-audit claim with an oracle-visible reference fails the build.
352
+
314
353
  Find missing-await bugs:
315
354
 
316
355
  ```