P2:
- WASM dual-ownership invariant documented on ASTCache dispose:
a Tree must live in AT MOST ONE disposing ASTCache. Native
tree-sitter today is unaffected; WASM adoption would require
tree.copy() or a non-disposing secondary cache.
- mro-processor C3 ordering test: pins EXTENDS-before-IMPLEMENTS
parent grouping for classes with interleaved edge additions.
Asserts exact MRO ['Base', 'Iface'] — a revert to single-loop
insertion-order iteration would produce ['Iface', 'Base'] and
fail loudly.
- cached-tree parity test: emitPythonScopeCaptures(src, path, T)
returns identical CaptureMatch[] to emitPythonScopeCaptures(src,
path). Pins the cache-hit path's correctness so a regression
that silently returns stale captures would break the test.
P3:
- Dev-mode cache counters moved from captures.ts to cache-stats.ts.
Production hot-path module no longer carries the module-global
export surface; PROF gating behavior preserved.
- ParseOutput field rename astCache → scopeTreeCache. Clarifies
that the surfaced cache is the persistent cross-phase one, not
the chunk-local astCache parse-impl clears between chunks.
Single consumer (scopeResolutionPhase) updated; no other readers.
- ASTCacheReader interface extracted. scopeResolutionPhase now
reads the phase dep via a shared type instead of a hand-rolled
inline structural shape that could drift from ASTCache's contract.
- graph.ts dual-index invariant enforced through writeRel/deleteRel
private helpers instead of duplicated add/delete at 3 mutation
sites. Adding a new mutation method only needs to call the
helpers — forgetting to update one index becomes structurally
impossible.
Tests: 382/382 unit (incl. 2 new), 191/191 python integration both
flag paths. tsc clean.