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
Copy file name to clipboardExpand all lines: CHANGELOG.md
+25Lines changed: 25 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,6 +5,31 @@ All notable changes to Chisel are documented in this file.
5
5
Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
6
This project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
8
+
## [0.8.0] - 2026-03-31
9
+
10
+
### Added
11
+
12
+
-**Variable taint tracking for JS/TS**: Regex-based tracking of `const/let/var X = './path'` assignments resolves `require(variable)` calls. Known variables upgrade to `tainted_import` (confidence=1.0); unknown variables remain `dynamic_import` (confidence=0.3). `test_mapper.py`: `_JS_VAR_ASSIGN_RE`, `_JS_SIMPLE_ASSIGN_RE`, updated `_extract_js_deps()`.
13
+
-**`shadow_graph` in `stats`**: `tool_stats()` now returns a `shadow_graph` dict with `total_edges`, `call_edges`, `import_edges`, `dynamic_import_edges`, `eval_import_edges`, `tainted_import_edges`, and `unknown_shadow_ratio`. `storage.py`: `get_edge_type_counts()`.
14
+
-**Per-file dynamic risk fields in `risk_map`**: Each entry now includes `shadow_edge_count`, `dynamic_edge_count`, `unknown_require_count` (via `new Function()` pattern scan in JS/TS files), and `hidden_risk_factor`. `impact.py`: updated `compute_risk_score()` and `get_risk_map()`.
15
+
-**`coverage_depth` in risk formula**: New 6th component — `min(distinct_covering_tests/5, 1.0)` — with weight 0.10. `test_instability` weight reduced from 0.10 to 0.05. Risk formula: `0.35*churn + 0.25*coupling + 0.15*coverage_gap + 0.10*coverage_depth + 0.10*author_concentration + 0.05*test_instability + hidden_risk_factor`.
16
+
-**`hidden_risk_factor`**: Additive uplift (0–0.15) from dynamic/eval import edge density: `min(dynamic_edge_count/20, 1.0) * 0.15`. Computed separately from the 6-component reweighting system.
17
+
-**Confidence-weighted edges**: Edge weights now blend `proximity * sqrt(confidence)` so low-confidence dynamic requires contribute proportionally less to impact scores. `test_mapper.py`: `build_test_edges()`.
18
+
-**`unknown_require_count`**: Count of `new Function(` patterns in JS/TS source files, indicating potential `eval`-based module loading. Surface-level heuristic for risk assessment.
-**Risk formula**: `0.35*churn + 0.25*coupling + 0.2*coverage_gap + 0.1*author_concentration + 0.1*test_instability`. Coupling uses `max(git co-change, static import-graph)` breadth. `coverage_gap` is graduated (quantized to 0.25 steps: 0.0/0.25/0.5/0.75/1.0). `get_risk_map` may reweight the composite when 3+ components are uniform across files. `proximity_adjustment` optionally reduces `coverage_gap` by import distance to tested code.
41
+
-**Risk formula**: `0.35*churn + 0.25*coupling + 0.15*coverage_gap + 0.10*coverage_depth + 0.10*author_concentration + 0.05*test_instability + hidden_risk_factor`. The first 6 components are reweighted when 3+ are uniform. `hidden_risk_factor` (0–0.15) is added separately from dynamic/eval import edge density. Coupling uses `max(git co-change, static import-graph)` breadth. `coverage_gap` is graduated (quantized to 0.25 steps: 0.0/0.25/0.5/0.75/1.0). `coverage_depth = min(distinct_covering_tests/5, 1.0)`. `get_risk_map` may reweight the composite when 3+ components are uniform across files. `proximity_adjustment` optionally reduces `coverage_gap` by import distance to tested code.
42
42
-**Co-change ingest**: `compute_co_changes` uses adaptive `min_count` from `coupling_threshold()`; queries use `meta.co_change_query_min` so stored pairs are visible. Branch-only pairs stored in `branch_co_changes` from `merge-base..HEAD`. Commits touching >50 files are skipped (bulk operations).
43
43
-**Blame caching**: Cached by file content hash, invalidated on change.
44
44
-**Incremental updates**: File content hashes tracked in `file_hashes` table.
@@ -48,9 +48,10 @@ chisel/
48
48
-**Ownership vs Reviewers**: `ownership` = blame-based (`role: "original_author"`). `who_reviews` = commit-activity-based (`role: "suggested_reviewer"`). Both are **git-derived signals** for agents (lineage, hot spots); they are not substitutes for team assignment in a solo workflow.
49
49
-**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.
50
50
-**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`.
51
-
-**Edge weighting**: Test edges carry a weight (0.4-1.0) based on file proximity. `_compute_proximity_weight()` in `test_mapper.py`.
51
+
-**Edge weighting**: Test edges carry a weight (0.4-1.0) based on file proximity, blended with `sqrt(confidence)` for dynamic requires: `weight = proximity * sqrt(confidence)`. `_compute_proximity_weight()` in `test_mapper.py`.
52
52
-**Three-tier edge matching** in `build_test_edges()`: (1) Python import-path matching (`from myapp.utils import foo` → `myapp/utils.py:foo`, requires both path and name match), (2) JS/TS path-based matching (`require('../../src/services/searchService')` → resolves relative path, matches ALL code units in the resolved file), (3) name-only matching (universal fallback). Priority chain ensures precise matching where possible with file-level fallback for JS.
53
53
-**JS/TS import binding extraction**: `_extract_js_deps()` extracts binding names from `const X = require('...')` (`_JS_CJS_DEFAULT_RE`), destructured requires `const { X, Y } = require('...')` (`_JS_CJS_DESTRUCTURED_RE`), and ESM defaults `import X from '...'` (`_JS_ESM_DEFAULT_RE`). All include `module_path` for path-based matching. Combined with `_JS_IMPORT_RE` (file-stem name) and `_JS_NAMED_IMPORT_RE` (ESM named imports), this covers CommonJS and ESM patterns.
54
+
-**Dynamic require() detection (DynamicRequireChainTracer)**: Chisel detects `require()` patterns invisible to naive static analysis: variable refs (`require(variable)`), template literals, string concatenation, conditionals, and eval-based loading. Variable taint tracking (`const MODULE = './foo'; require(MODULE)`) resolves known variables and upgrades them to `tainted_import` (confidence=1.0). Unknown variables produce `dynamic_import` (confidence=0.3). Confidence is blended into edge weights via `proximity * sqrt(confidence)`. Files with `dynamic_import`/`eval_import` edges accumulate `hidden_risk_factor` in risk scoring: `min(dynamic_edge_count/20, 1.0) * 0.15` added to the 5-component risk formula. `shadow_edge_count` and `dynamic_edge_count` are exposed in `risk_map` output.
54
55
-**JS path resolution**: `_resolve_js_module_path(test_file, module_path)` resolves relative imports against the test file's directory. `_matches_js_import_path(code_file, resolved)` strips JS/TS extensions and handles `index.js` barrel imports. `_strip_js_ext()` shared helper. `_JS_EXTENSIONS` frozenset in `test_mapper.py`.
55
56
-**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.
56
57
-**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.
0 commit comments