You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
v0.8.0: Jest test extraction, skip coverage artifacts, lower coupling threshold
- Extract Jest/Mocha/Vitest describe/it/test blocks as code units (test_suite/
test_case types). This unblocks the entire JS/TS test edge pipeline — require()
and import dep extraction already worked but was unreachable without test units.
- Add coverage/, .next/, .nuxt/ to _SKIP_DIRS to exclude build/test artifacts.
- Halve coupling threshold formula: max(2, int(log2(N)/2)+1). Small projects now
surface coupling signal (10 commits → threshold 2 vs 4 before).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy file name to clipboardExpand all lines: CLAUDE.md
+3-2Lines changed: 3 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -35,10 +35,11 @@ chisel/
35
35
-**Multi-agent safety**: `project.py` provides: (1) `detect_project_root()` canonicalizes via git common dir so worktrees share identity, (2) `normalize_path()` ensures consistent relative paths, (3) `resolve_storage_dir()` defaults to project-local `.chisel/` (priority: explicit > env > project-local > ~/.chisel/), (4) `ProcessLock` for cross-process coordination — shared locks for reads, exclusive for writes. Cross-platform: `fcntl.flock` on Unix, `LockFileEx` on Windows.
36
36
-**SQLite concurrency**: 30s `busy_timeout` + exponential-backoff retry on `_execute` for cross-process SQLITE_BUSY.
37
37
-**Ownership vs Reviewers**: `ownership` = blame-based (who wrote the code, `role: "original_author"`). `who_reviews` = commit-activity-based (who maintains it, `role: "suggested_reviewer"`).
38
-
-**Shared constants**: `_SKIP_DIRS` and `_EXTENSION_MAP` live in `ast_utils.py`. `_CODE_EXTENSIONS` in `engine.py` is derived from `_EXTENSION_MAP`.
38
+
-**Shared constants**: `_SKIP_DIRS` and `_EXTENSION_MAP` live in `ast_utils.py`. `_CODE_EXTENSIONS` in `engine.py` is derived from `_EXTENSION_MAP`.`_SKIP_DIRS` includes `coverage`, `.next`, `.nuxt` to exclude build/test output artifacts.
39
39
-**Shared dispatch**: `dispatch_tool()` in `mcp_server.py` is used by both HTTP and stdio servers. Tool schemas and dispatch tables live in `schemas.py`.
40
40
-**Edge weighting**: Test edges carry a weight (0.4-1.0) based on file proximity. Python import-path matching (`from myapp.utils import foo` → `myapp/utils.py:foo`) takes priority over name-only matching. `_compute_proximity_weight()` and `_matches_import_path()` in `test_mapper.py`.
41
41
-**AST regex improvements**: C#/Java support nested generics `<A<B>>` and annotations/attributes `@Override`/`[Test]`. Kotlin supports extension functions `fun String.foo()`. C++ supports template functions and destructors `~Foo()`. Swift supports `@objc`-style attributes. Dart supports factory constructors and getters/setters.
42
+
-**Jest/Mocha/Vitest test block extraction**: `_JS_JEST_BLOCK_RE` in `ast_utils.py` matches `describe('name', ...)`, `it('name', ...)`, `test('name', ...)` (plus `.only`/`.skip`/`.todo` modifiers) as code units with `unit_type` "test_suite" or "test_case". `_TEST_UNIT_TYPES` in `test_mapper.py` ensures these are recognized as test units regardless of `_is_test_name()`. This enables test edge building for JS/TS projects — the `require()`/`import` dep extraction already worked but was unreachable without test units.
42
43
-**Pluggable extractors**: `register_extractor(lang, fn)` in `ast_utils.py` lets users override built-in regex extractors with tree-sitter or LSP-backed ones. `_custom_extractors` checked before `_EXTRACTORS` in `extract_code_units()`. Zero-dep — the registry is just hooks.
43
44
-**Batch SQL queries**: `storage.py` provides `get_*_batch()` methods for edges, code units, co-changes, churn, and blame. `impact.get_risk_map()` uses these to compute all risk scores in ~5 queries total instead of N*5. `_chunked()` helper splits large batches to stay under SQLite's variable limit.
44
45
-**Process-level read locks**: All read tool methods in `engine.py` acquire `_process_lock.shared()` (outer) + `lock.read_lock()` (inner). Writes acquire `_process_lock.exclusive()` + `lock.write_lock()`. This allows concurrent reads from multiple processes while blocking during writes.
@@ -91,4 +92,4 @@ Each wired through: engine.tool_*() → CLI subcommand, HTTP POST /call, stdio M
91
92
-**`stats`**: Returns summary counts for all database tables plus `coupling_threshold` (when commits > 0) so LLM agents can diagnose coupling=0.0 results.
92
93
-**`triage`**: Combined risk_map + test_gaps + stale_tests for top-N riskiest files. Single command for pre-audit/refactor prioritization. Returns `{top_risk_files, test_gaps, stale_tests, summary}`.
93
94
-**`limit` parameter**: All list-returning tools accept `limit` to cap result size. Also applies to dict-wrapped responses with a `files` key (e.g. `risk_map`).
94
-
-**Adaptive coupling threshold**: `max(3, int(log2(commits)) + 1)` — logarithmic scaling. Previous `commits // 4` was too aggressive (400 commits → 100 threshold, killing all signal). New formula: 10→4, 50→6, 200→8, 1000→11, 10000→14. Defined in `_coupling_threshold()` in `engine.py`.
95
+
-**Adaptive coupling threshold**: `max(2, int(log2(commits) / 2) + 1)` — half-log scaling. Previous `max(3, int(log2(N)) + 1)` was too aggressive for small/medium projects (10 commits → threshold 4, killing all signal when max co-change is 2-3). Half-log with floor of 2 surfaces early coupling signal: 10→2, 50→3, 100→4, 200→4, 1000→5, 10000→7. Defined in `_coupling_threshold()` in `engine.py`.
0 commit comments