ucn 4.2.2 → 4.2.3

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
@@ -34,7 +34,7 @@ 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 for **auditable trust**. grep hands you raw text matches to verify yourself; UCN separates target-backed edges from possible edges, explains exclusions, and reconciles its observed text set. It does not turn a zero into a deletion claim. CI re-derives answers from real compilers and language servers (ts-morph, pyright, gopls, rust-analyzer, jdtls). Publishing is gated on a representative five-repository board; the scheduled board covers nineteen plus rotating fresh repositories. See [Answers you can trust](#answers-you-can-trust).
37
+ And it's built for **auditable trust**. grep hands you raw text matches to verify yourself; UCN separates target-backed edges from possible edges, explains exclusions, and reconciles its observed text set. It does not turn a zero into a deletion claim. CI re-derives answers from real compilers and language servers (ts-morph, pyright, gopls, rust-analyzer, jdtls). Publishing is gated on a representative seven-repository board; the scheduled board covers nineteen pinned repositories plus rotating fresh repositories. See [Answers you can trust](#answers-you-can-trust).
38
38
 
39
39
  ### Same engine, different transport
40
40
 
@@ -175,19 +175,31 @@ This is a release gate, not a promise of universal program understanding. CI re-
175
175
 
176
176
  Current pinned release-board results:
177
177
 
178
- | Repository | Language oracle | Confirmed caller precision | Caller recall | Callee precision/recall | Command checks |
179
- |---|---|---:|---:|---:|---:|
180
- | preact-signals | ts-morph | 100% | 100% | 100% / 100% | 100% |
181
- | httpx | pyright | 100% | 100% | 100% / 100% | 100% |
182
- | cobra | gopls | 100% | 100% | 100% / 100% | 100% |
183
- | clap | rust-analyzer | 100% | 100% | 100% / 100% | 100% |
184
- | javapoet | jdtls | 100% | 100% | 100% / 100% | 100% |
178
+ | Repository | Pinned commit | Language oracle | Confirmed caller precision | Caller recall | Callee precision/recall | Command checks |
179
+ |---|---|---|---:|---:|---:|---:|
180
+ | [preact-signals](https://github.com/preactjs/signals) | [`e0ce9fdf`](https://github.com/preactjs/signals/commit/e0ce9fdf92df7f0ece2c89d44554c39f36dc6882) | ts-morph | 100% | 100% | 100% / 100% | 100% |
181
+ | [httpx](https://github.com/encode/httpx) | [`b5addb64`](https://github.com/encode/httpx/commit/b5addb64f0161ff6bfe94c124ef76f6a1fba5254) | pyright | 100% | 100% | 100% / 100% | 100% |
182
+ | [cobra](https://github.com/spf13/cobra) | [`ad460ea8`](https://github.com/spf13/cobra/commit/ad460ea8f249db69c943a365fb84f3a59042d54e) | gopls | 100% | 100% | 100% / 100% | 100% |
183
+ | [viper](https://github.com/spf13/viper) | [`528f7416`](https://github.com/spf13/viper/commit/528f7416c4b56a4948673984b190bf8713f0c3c4) | gopls | 100% | 100% | 100% / 100% | 100% |
184
+ | [ripgrep](https://github.com/BurntSushi/ripgrep) | [`82313cf9`](https://github.com/BurntSushi/ripgrep/commit/82313cf95849bfe425109ad9506a52154879b1b1) | rust-analyzer | 100% | 100% | 100% / 100% | 100% |
185
+ | [clap](https://github.com/clap-rs/clap) | [`d3e59a9a`](https://github.com/clap-rs/clap/commit/d3e59a9ab214910b9dad02921b7ef42c6400de9b) | rust-analyzer | 100% | 100% | 100% / 100% | 100% |
186
+ | [javapoet](https://github.com/square/javapoet) | [`b9017a95`](https://github.com/square/javapoet/commit/b9017a9503b76e11b4ad4c1a9f050e2d29112cb0) | jdtls | 100% | 100% | 100% / 100% | 100% |
185
187
 
186
- The command checks cover exact definition lookup, `find`, `fn`/`class`, `brief`, `typedef`, `usages`, `tests`, and `example` against the same external oracle population. The dead-code arm currently has zero false-dead claims on the release board. The semantic gate also caps configuration-unscored caller and callee evidence at 10%, so platform filtering cannot silently make a small scored subset look representative. The performance arm runs every repository in an isolated process, takes three fresh-cache startup samples, reports median and maximum first-query latency, and independently gates steady-state p50/p95 and peak memory.
188
+ Each semantic run draws a deterministic, reference-count-stratified sample of up to 50 compiler/LSP symbols per repository. The command checks cover exact definition lookup, `find`, `fn`/`class`, `brief`, `typedef`, `usages`, `tests`, and `example` against that same external-oracle population. The dead-code arm audits up to 100 claims per release repository and currently has zero false-dead claims. The semantic gate caps configuration-unscored confirmed caller and callee evidence at 10%, so platform filtering cannot silently make a small scored precision subset look representative. Configuration-gated unverified abstentions are reported separately and never presented as confirmed evidence. The performance arm runs every repository in an isolated process, takes three fresh-cache startup samples, reports median and maximum first-query latency, and independently gates steady-state p50/p95 and peak memory.
189
+
190
+ Evidence: [semantic rollup](eval/reports/oracle-eval-rollup-2026-07-20.md), [dead-code rollup](eval/reports/deadcode-eval-rollup-2026-07-20.md), and [performance rollup](eval/reports/performance-gate-2026-07-20.md). Reproduce all three release gates with `npm run trust:gate`; the pinned source manifest is [`eval/lib/repos.js`](eval/lib/repos.js).
187
191
 
188
192
  Unverified precision is reported separately and is intentionally much lower on dispatch-heavy code. Unverified entries are review candidates, not confirmed claims. Rust feature-gated sites that one compiler configuration cannot load are reported as unscored rather than counted as passes.
189
193
 
190
- The scheduled board covers nineteen pinned repositories, multiple sampling seeds, and a rotating fresh-repository arm. It is broader than the five-repository publish gate and is used to expose regressions and overfitting. The tree commands `trace`, `blast`, `reverse-trace`, and `affected-tests` follow the same evidence discipline. Run `ucn doctor --deep` for task-specific readiness on your repository.
194
+ The scheduled board covers nineteen pinned repositories, multiple sampling seeds, and a rotating fresh-repository arm. It is broader than the seven-repository publish gate and is used to expose regressions and overfitting:
195
+
196
+ - JavaScript and TypeScript: zod, preact-signals, express, hono, zustand, fastify
197
+ - Python: httpx, rich, click
198
+ - Go: cobra, grpc-go, viper, chi
199
+ - Rust: ripgrep, cursive, clap
200
+ - Java: gson, javapoet, jsoup
201
+
202
+ Repos that expose a gap remain on this scheduled board; they are not removed to preserve a perfect release table. HTML has parser, integration, and cross-surface regression coverage, but no compiler/LSP real-repository oracle is claimed. The tree commands `trace`, `blast`, `reverse-trace`, and `affected-tests` follow the same evidence discipline. Run `ucn doctor --deep` for task-specific readiness on your repository.
191
203
 
192
204
  ## Change code without breaking things
193
205
 
@@ -426,7 +438,7 @@ function compareNames(a, b) {
426
438
  - **Coverage** - every command, every supported language, every surface (CLI, MCP, interactive)
427
439
  - **Systematic** - a harness exercises all command and flag combinations against real multi-language fixtures
428
440
  - **Test types** - unit, integration, per-language regression, formatter, cache, MCP edge cases, architecture parity guards
429
- - **Ground truth** - caller, callee, and oracle-judgable command behavior is measured against ts-morph, pyright, gopls, rust-analyzer, and jdtls. The publish gate uses five representative repositories; the scheduled board uses nineteen plus a rotating fresh-repository arm. Gates track confirmed precision, semantic recall, conservation, observed-zero agreement, oracle configuration coverage, dead-code false positives, isolated startup latency, steady-state latency, and peak memory (see [Answers you can trust](#answers-you-can-trust))
441
+ - **Ground truth** - caller, callee, and oracle-judgable command behavior is measured against ts-morph, pyright, gopls, rust-analyzer, and jdtls. The publish gate uses seven representative repositories; the scheduled board uses nineteen pinned repositories plus a rotating fresh-repository arm. Gates track confirmed precision, semantic recall, conservation, observed-zero agreement, oracle configuration coverage, dead-code false positives, isolated startup latency, steady-state latency, and peak memory (see [Answers you can trust](#answers-you-can-trust))
430
442
 
431
443
  ---
432
444
 
@@ -49,12 +49,14 @@ function addSymbol(fileEntry, item, type) {
49
49
  if (item.implements) symbol.implements = item.implements;
50
50
  if (item.indent !== undefined) symbol.indent = item.indent;
51
51
  if (item.isNested) symbol.isNested = item.isNested;
52
+ if (item.enclosingType) symbol.enclosingType = item.enclosingType;
52
53
  if (item.isMethod) symbol.isMethod = item.isMethod;
53
54
  if (item.receiver) symbol.receiver = item.receiver;
54
55
  if (item.className) symbol.className = item.className;
55
56
  if (item.memberType) symbol.memberType = item.memberType;
56
57
  if (item.fieldType) symbol.fieldType = item.fieldType;
57
58
  if (item.aliasOf) symbol.aliasOf = item.aliasOf;
59
+ if (item.derefTarget) symbol.derefTarget = item.derefTarget;
58
60
  if (item.decorators && item.decorators.length > 0) symbol.decorators = item.decorators;
59
61
  if (item.decoratorsWithArgs && item.decoratorsWithArgs.length > 0) symbol.decoratorsWithArgs = item.decoratorsWithArgs;
60
62
  if (item.annotationsWithArgs && item.annotationsWithArgs.length > 0) symbol.annotationsWithArgs = item.annotationsWithArgs;
@@ -64,13 +66,15 @@ function addSymbol(fileEntry, item, type) {
64
66
  if (item.traitName) symbol.traitName = item.traitName;
65
67
  if (item.isSignature) symbol.isSignature = true;
66
68
  if (item.memberAssigned) symbol.memberAssigned = true;
69
+ if (item.bodyScopedName) symbol.bodyScopedName = true;
67
70
  if (item.registryMember) symbol.registryMember = true;
68
71
  if (item.registryContainer) symbol.registryContainer = item.registryContainer;
69
72
 
70
73
  fileEntry.symbols.push(symbol);
71
74
  // Property-assignment defs declare no lexical name (fix #269) — kept in
72
75
  // lockstep with project.js addSymbol (the parallel≡sequential guard).
73
- if (!item.memberAssigned) {
76
+ // Named function expressions bind only inside their own body.
77
+ if (!item.memberAssigned && !item.bodyScopedName) {
74
78
  fileEntry.bindings.push({
75
79
  id: symbol.bindingId,
76
80
  name: symbol.name,
@@ -165,7 +169,12 @@ function processFile(filePath) {
165
169
  .map(n => {
166
170
  // Rename pairing (fix #269) — lockstep with project.js.
167
171
  const rn = (i.renames || []).find(r => r.original === n);
168
- return { name: n, module: i.module, ...(rn && { alias: rn.local }) };
172
+ return {
173
+ name: n,
174
+ module: i.module,
175
+ ...(rn && { alias: rn.local }),
176
+ ...(i.defaultLike && { defaultLike: true }),
177
+ };
169
178
  })),
170
179
  exports: exports.map(e => e.name),
171
180
  exportDetails: exports,
package/core/cache.js CHANGED
@@ -164,7 +164,27 @@ const UCN_VERSION = require('../package.json').version;
164
164
  // (`m.get_many::<T>()`); v64 caches misclassified them as references.
165
165
  // v66: Rust call records preserve receiverFlowInvalidated after a non-call
166
166
  // lexical rebinding, preventing stale return types from excluding true calls.
167
- const CACHE_FORMAT_VERSION = 66;
167
+ // v67: JS/TS constructor calls preserve lexical-shadow evidence, and method
168
+ // calls on fresh constructions preserve the exact constructed receiver type.
169
+ // Both fields affect caller identity and must not be read from older shards.
170
+ // v68: unaliased dotted Python imports persist separate package and submodule
171
+ // ownership edges (`import pkg.sub` binds pkg and loads pkg.sub).
172
+ // v69: CommonJS simple-require bindings preserve defaultLike so callable
173
+ // module.exports values resolve exactly across caller and callee queries.
174
+ // v70: Python receiver records preserve exact constructor provenance and
175
+ // context-manager result bindings for conservative dispatch tiering.
176
+ // v71: structural method records preserve untyped local-receiver ownership;
177
+ // single-owner spelling alone cannot confirm a parameter/assigned value.
178
+ // v72: Rust type symbols preserve the compiler-declared Deref Target so
179
+ // wrapper receiver method lookup reaches the target type without guessing.
180
+ // v73: JS/TS call records preserve qualified-constructor provenance and bound
181
+ // local receivers; conditional reassignments no longer persist a definite
182
+ // inferred constructor type past a branch.
183
+ // Java nested type symbols preserve their enclosing type for exact constructor
184
+ // ownership across same-named top-level and inner classes, and cast receivers
185
+ // retain their compiler-declared type. Rust tuple fields are indexed by numeric
186
+ // position so `self.0.method()` participates in declared-field resolution.
187
+ const CACHE_FORMAT_VERSION = 73;
168
188
 
169
189
  /**
170
190
  * Save index to cache file