Releases: AstralXVoid/NoWreck
Release list
NoWreck v0.9.0 — Rust + Go Language Support
NoWreck v0.9.0 — Rust + Go Language Support
Release date: August 2026
Previous release: v0.8.0 (Type-Level Claim Types)
Focus: Rust and Go language support via tree-sitter grammars. Two new scanner modules, extended repository scanner, change detector, and symbol index — all following the existing architecture pattern exactly. Zero new claim types, zero changes to the verification engine, reporter, or JSON schema.
What's new in v0.9.0
Rust scanning ✅
Rust source files (.rs) are now parsed with the tree-sitter-rust grammar. The scanner extracts:
fn add(a: i32, b: i32) -> i32 { a + b } → FUNCTION "add"
pub fn connect(addr: &str) -> Result<()> { ... } → FUNCTION "connect"
struct User { name: String, age: u32 } → CLASS "User"
impl User { fn display(&self) { ... } } → METHOD "display" (parent_class: "User")
trait Display { fn fmt(&self); } → INTERFACE "Display"
impl Display for User { fn fmt(&self) { ... } } → METHOD "fmt" (parent_class: "User")
enum Role { Admin, Member, Guest } → ENUM "Role"
type Result<T> = std::result::Result<T, Error> → TYPE_ALIAS "Result"pub/pub(crate)visibility modifiers are unwrapped (likeexportin TS)moddeclarations are skipped (structural namespaces, not symbols)implblock methods are extracted withparent_classset to the impl targettraitmethods are NOT extracted as METHOD symbols (same one-level-deep philosophy)- Macro invocations (
println!,format!) are NOT treated as function calls
Go scanning ✅
Go source files (.go) are parsed with the tree-sitter-go grammar:
func Add(a, b int) int { return a + b } → FUNCTION "Add"
func (u *User) Display() { fmt.Println(u.Name) } → METHOD "Display" (parent_class: "User")
type User struct { Name string; Age int } → CLASS "User"
type Reader interface { Read(p []byte) (n int, err error) } → INTERFACE "Reader"
type Status string → TYPE_ALIAS "Status"type X struct→ CLASS (structs are Go's primary data-carrying type)type X interface→ INTERFACE (method sets)type X string→ TYPE_ALIAS (type renames)- Receiver types extracted from method declarations for
parent_class constandvardeclarations are skipped (value bindings, not symbols)- Selector expressions (
fmt.Println()) are NOT treated as simple function calls
Architecture
Both scanners follow the exact same pattern as the TypeScript scanner:
- Lazy-load grammar on first call (per-process singleton)
- Parse file with tree-sitter
- Walk CST, collect top-level declarations
- Return
Symbolobjects compatible with the shared pipeline - Call detection via
call_expressionwith simpleidentifiertargets
The repository scanner discovers .rs and .go files alongside .py, .js, .ts, and .tsx. The symbol index, change detector, and verification engine all work unchanged — they see Symbol objects and DetectedChange objects, never knowing which language produced them.
Scope boundary
.py/.js/.ts/.tsxexisting behaviour — byte-identical to v0.8.0 (hard gate)- Same 13 claim types — Rust/Go use the existing types
- No new SymbolType, ChangeType, or ClaimType members
- Verifier, reporter, prompts — zero changes
- JSON schema — zero changes (additive language support)
- 2 new dependencies:
tree-sitter-rust,tree-sitter-go
Test suite
| Suite | v0.8.0 | v0.9.0 | Growth |
|---|---|---|---|
| pytest (project unit tests) | 453 | 453 | — |
| Milestone 1 checkpoint | 60 tests | 80 tests | +20 |
| Change detector | 57 tests | 57 tests | — |
| Verifier | 55 tests | 55 tests | — |
| Terminal reporter | 45 tests | 45 tests | — |
| ruff | 0 issues | 0 issues | — |
| basedpyright | 0 errors | 0 errors | — |
+20 new milestone tests:
TestPureRustRepo(9 tests): file discovery, greeter symbols, calculator class+methods, models types (struct, trait, enum, type alias), symbol index counts, call detection, file changes, no-change determinism, cross-run determinismTestPureGoRepo(9 tests): file discovery, greeter symbols, calculator class+methods, models types (struct, interface, type alias), symbol index counts, call detection, file changes, no-change determinism, cross-run determinismTestAllReposDeterministicextended: Rust and Go repos added to cross-repo determinism parametrize (7 repos total)
File changes
New files
| File | What it covers |
|---|---|
nowreck/scanner/rust_scanner.py |
Rust scanner (lazy grammar, scan_rust_file, scan_rust_calls) |
nowreck/scanner/go_scanner.py |
Go scanner (lazy grammar, scan_go_file, scan_go_calls) |
test_milestone1/repos/pure-rust/src/ |
Milestone repo: greeter.rs, calculator.rs, models.rs |
test_milestone1/repos/pure-go/src/ |
Milestone repo: greeter.go, calculator.go, models.go |
docs/nowreck-v9-scope.md |
Full scope document |
docs/release9.md |
This release notes file |
Modified files
| File | What changed |
|---|---|
nowreck/scanner/repository_scanner.py |
Added rust_files/go_files to ScanResult; added _discover_rust_files, _discover_go_files, _parse_rust_file, _parse_go_file |
nowreck/scanner/symbol_index.py |
build_symbol_index now processes rust_files and go_files |
nowreck/detector/change_detector.py |
_detect_file_changes includes Rust/Go files; _extract_calls includes Rust/Go call detection |
test_milestone1/test_milestone1_checkpoint.py |
TestPureRustRepo, TestPureGoRepo classes; extended TestAllReposDeterministic |
pyproject.toml |
Dependencies: +tree-sitter-rust>=0.23, +tree-sitter-go>=0.25 |
Unchanged
nowreck/scanner/javascript_scanner.py— 0 changesnowreck/scanner/typescript_scanner.py— 0 changesnowreck/scanner/_tree_sitter_helpers.py— 0 changesnowreck/claims/— 0 changesnowreck/verifier/verifier.py— 0 changesnowreck/model/prompts.py— 0 changesnowreck/reporter/terminal_reporter.py— 0 changes (version bump only)nowreck/picker.py, CLI — 0 changes- JSON output schema — 0 changes
.py/.js/.ts/.tsxexisting scanning behaviour — byte-identical (hard gate)
Installing / upgrading
pipx install . # fresh install from repo
pip install -e . # or editable installRequires Python 3.10+. No new system dependencies (tree-sitter grammars ship as Python wheels).
nowreck --version
# → nowreck 0.9.0Definition of Done ✅
- A
.rsfile with functions, structs, impl methods, traits, enums, and type aliases scans to the correctSymbolTypes and line numbers — verified by hand — andnowreck fix --pre <empty> --post <pure-rust>detects expected changes matching reality. - A
.gofile with functions, methods, structs, interfaces, and type aliases scans to the correctSymbolTypes and line numbers — verified by hand — andnowreck fix --pre <empty> --post <pure-go>detects expected changes matching reality. .py/.js/.ts/.tsxrepos produce output byte-identical to v0.8.0 for all previously-supported symbols.- The full existing test battery passes, plus the new Rust/Go milestone tests.
- ruff: 0 issues, basedpyright: 0 errors.
Result (verified):
- Pure-Rust milestone repo: 3 files, 19 symbols detected (functions, structs, methods, trait, enum, type alias). CLI detects all 19 as ADD_FUNCTION/ADD_CLASS/ADD_INTERFACE/ADD_ENUM/ADD_TYPE_ALIAS changes.
- Pure-Go milestone repo: 3 files, 18 symbols detected (functions, methods, structs, interface, type alias). CLI detects all 18 as ADD_FUNCTION/ADD_CLASS/ADD_INTERFACE/ADD_TYPE_ALIAS changes.
- All existing repos (pure-python, pure-js, pure-ts, pure-tsx, mixed) produce identical output to v0.8.0.
- 453 pytest tests pass, 80 milestone tests pass, ruff clean, basedpyright clean.
What's next
The roadmap remains focused on narrow, testable increments, each with its own scope document and phase-by-phase build discipline.
explanationfield on claims — model + prompt change (README documents it, theClaimmodel doesn't have it yet) — deferred from v6- Scan-summary expansion in verbose mode (per-language file counts) — deferred from v6
- TS polish (from v5): abstract methods, constructor parameter properties, decorators — separate polish increment
- Interface method signatures / enum members as symbols — polish increment, not done yet
- Python type-level capture — Python's
Enum/TypeAlias/TypedDictmapping needs its own design conversation - Independent verification architecture (fix Prompt Mode circularity) 🗓 (planned for v0.10.0 — see
docs/nowreck-v10-scope.md) - Additional model providers (Anthropic, Gemini)
- Caching for large repositories
- CI/CD integration
NoWreck v0.8.0 — Type-Level Claim Types (Interfaces, Enums, Type Aliases)
NoWreck v0.8.0 — Type-Level Claim Types (Interfaces, Enums, Type Aliases)
Release date: August 2026
Previous release: v0.7.0 (TSX Support)
Focus: interface, enum, and type alias declarations as first-class claim types for the TS/TSX family. Six new claim types (ADD/REMOVE × INTERFACE/ENUM/TYPE_ALIAS), wired through scanner, change detector, claim parser, verifier, prompts, and reporter. Zero new dependencies. Zero changes to JS/Python behaviour.
What's new in v0.8.0
Type-level claim types ✅
TypeScript codebases define contracts at the type level (interface, enum, type aliases) that were invisible to Nowreck until now. The scanner ignored them, so they never appeared as symbols, changes, or claims. v0.8.0 makes them first-class — captured, detected, claimable, and verifiable — for the TS/TSX family.
What gets captured (TS/TSX only):
interface User { id: number; name: string } → INTERFACE "User"
enum Color { Red, Green, Blue } → ENUM "Color"
type Status = "active" | "inactive" → TYPE_ALIAS "Status"
export interface Props { ... } → (unwrapped, same as above)
export default interface Thing { ... } → (named, collected)What stays unchanged:
- Members are NOT captured — interface method signatures, enum members, and generic parameters remain structural detail, not symbols (same one-level-deep philosophy as class methods)
- Python's
class Color(Enum)staysADD_CLASS(byte-identity gate) .ts/.js/.pyexisting behaviour — byte-identical to v0.7.0 (hard gate)- No new dependencies, no JSON schema break (additive only)
The design decision: per-kind claim types
Three distinct pairs — ADD_INTERFACE/REMOVE_INTERFACE, ADD_ENUM/REMOVE_ENUM, ADD_TYPE_ALIAS/REMOVE_TYPE_ALIAS — rather than one folded ADD_TYPE/REMOVE_TYPE pair. The existing taxonomy is per-kind (FUNCTION ≠ CLASS), and the scanner knows the exact declaration kind from the CST node type. Folding into a single TYPE pair would blur interface-vs-alias in reports and make model mislabelling less detectable.
Pipeline wiring (8 touch points, mechanical additive changes)
| # | Location | Change |
|---|---|---|
| 1 | nowreck/scanner/symbol_index.py |
SymbolType: +INTERFACE, +ENUM, +TYPE_ALIAS; interfaces/enums/type_aliases properties |
| 2 | nowreck/scanner/_tree_sitter_helpers.py |
collect_top_level_symbols: collect interface_declaration, enum_declaration, type_alias_declaration |
| 3 | nowreck/detector/change_detector.py |
ChangeType: +6; _symbol_to_change mapping |
| 4 | nowreck/claims/models.py |
ClaimType: +6; CLAIM_TYPE_NAMES: +6 entries |
| 5 | nowreck/verifier/verifier.py |
_SAME_CHANGE: +6; _OPPOSITE_CHANGE: +6 |
| 6 | nowreck/model/prompts.py |
_CLAIM_TO_CHANGE_TYPE: +6; schema example + field notes |
| 7 | nowreck/reporter/terminal_reporter.py |
Labels + evidence lines for new kinds |
| 8 | nowreck/claims/parser.py |
Inherits CLAIM_TYPE_NAMES from models (no local copy) |
Scope boundary
- TS/TSX type-level scanning, symbol extraction, change detection, claims, and verification — in
.ts/.tsx/.js/.pyexisting behaviour — byte-identical to v0.7.0 (hard gate)- Python enums/typed-anything — out (stays
ADD_CLASS/uncaptured) - Interface members, enum members, generic parameters — out (polish increment later)
- No new dependencies, no caching, no new model providers, no reporter/CLI/picker feature changes beyond additive labels
Test suite growth
| Suite | v0.7.0 | v0.8.0 | Growth |
|---|---|---|---|
| pytest (project unit tests) | 469 | 453 | −16 (test__no_type_level tests removed as behaviour changed)* |
| Milestone 1 checkpoint (4 repos) | 57 tests | 60 tests | +3 |
| Change detector (incl. TSX + type-level) | 47 tests | 57 tests | +10 |
| Verifier (incl. type-level) | 39 tests | 55 tests | +16 |
| Terminal reporter (incl. type-level labels) | 34 tests | 45 tests | +11 |
| Model/prompt builder (incl. type-level) | 37 tests | 45 tests | +8 |
| Claims parser | 21 tests | 21 tests | — |
| ruff | 0 issues | 0 issues | — |
| basedpyright | 0 errors | 0 errors | — |
New test coverage added across:
tests/test_change_detector.py—TestDetectTypeLevelChanges(9 tests): interface add/remove, enum add/remove, type alias add/remove, type replaced in single file, multiple type-level changes, no changes when identicaltests/test_verifier.py—TestClaimVerifierTypeLevel*(15 tests): add/remove confirmed, add/remove contradicted, no changes / wrong name / wrong file unverifiable — for all three type-level kindstests/test_terminal_reporter.py— type-level labels and evidence (6 tests): add interface/enum/type alias evidence lines, remove interface/enum/type alias evidence lines, claim descriptionstests/test_model.py—claims_to_changesfor new types (6 tests): add/remove interface, enum, type alias mappingtest_milestone1/test_milestone1_checkpoint.py— type-level assertions (3 tests):test_type_level_symbols_captured(pure-ts + pure-tsx),test_type_level_change_detection(pure-ts)test_ts_samples/test_phase1_comprehensive.py— type-level positive tests: interface, type alias, enum captured with correct SymbolType and line numbers (previously negative tests asserting NOT captured)test_ts_samples/test_phase1_comprehensive_tsx.py— type-level positive tests: same for TSX samples (previously negative tests)test_ts_samples/test_phase1_multiround_tsx.py— type-level round check: ButtonProps interface now captured
File changes
Modified files
| File | What changed |
|---|---|
nowreck/scanner/symbol_index.py |
SymbolType: +INTERFACE, +ENUM, +TYPE_ALIAS; interfaces/enums/type_aliases properties |
nowreck/scanner/_tree_sitter_helpers.py |
collect_top_level_symbols: collect interface_declaration, enum_declaration, type_alias_declaration |
nowreck/detector/change_detector.py |
ChangeType: +6; _symbol_to_change mapping for INTERFACE/ENUM/TYPE_ALIAS |
nowreck/claims/models.py |
ClaimType: +6; CLAIM_TYPE_NAMES: +6 entries |
nowreck/claims/parser.py |
CLAIM_TYPE_NAMES now imported from models (no local copy) |
nowreck/verifier/verifier.py |
_SAME_CHANGE: +6; _OPPOSITE_CHANGE: +6 |
nowreck/model/prompts.py |
_CLAIM_TO_CHANGE_TYPE: +6; _CHANGE_LABELS: +6; JSON schema updated to 13 claim types |
nowreck/reporter/terminal_reporter.py |
_CLAIM_TYPE_LABELS: +6; _CHANGE_TYPE_LABELS: +6; evidence-line builders for new kinds |
test_milestone1/repos/pure-ts/src/models.ts |
Added interface (UserProfile), enum (Role), type alias (UserStatus) |
test_milestone1/repos/pure-tsx/src/models.tsx |
Added enum (ViewMode), type alias (SortOrder); UserProps interface already present |
test_milestone1/test_milestone1_checkpoint.py |
New test_type_level_symbols_captured, test_type_level_change_detection; pure-tsx test_type_level_symbols_captured |
tests/test_change_detector.py |
TestDetectTypeLevelChanges class (9 tests); test_values_are_distinct updated to len(ChangeType) |
tests/test_verifier.py |
TestClaimVerifierTypeLevelConfirmed (6), TestClaimVerifierTypeLevelContradicted (6), TestClaimVerifierTypeLevelUnverifiable (3) |
tests/test_terminal_reporter.py |
Type-level evidence line tests, claim description tests |
tests/test_model.py |
test_claims_to_changes_add_interface, remove_interface, add_enum, remove_enum, add_type_alias, remove_type_alias, test_prompt_renders_interface_change |
test_ts_samples/test_phase1_comprehensive.py |
Negative interface/type/enum tests → positive (now captured); added SymbolType + line number assertions |
test_ts_samples/test_phase1_comprehensive_tsx.py |
Negative interface/type/enum tests → positive (now captured); added SymbolType assertions |
test_ts_samples/test_phase1_multiround_tsx.py |
ButtonProps interface now captured |
test_ts_samples/edge_types_only.ts |
Comment updated: negative test → positive test since v0.8.0 |
Unchanged
nowreck/scanner/typescript_scanner.py— 0 changes (helpers are grammar-agnostic)nowreck/scanner/repository_scanner.py— 0 changesnowreck/scanner/javascript_scanner.py— 0 changesnowreck/picker.py, CLI, JSON schema structure — 0 changes.ts/.tsx/.js/.pyexisting scanning behaviour — byte-identical (hard gate)- Dependencies — 0 new packages
Installing / upgrading
pipx install . # fresh install from repo
pip install -e . # or editable installRequires Python 3.10+. No new dependencies.
nowreck --version
# → nowreck 0.8.0Claim types: 7 → 13
| Previous (7) | v0.8.0 adds (6) |
|---|---|
| ADD_FUNCTION | ADD_INTERFACE |
| REMOVE_FUNCTION | REMOVE_INTERFACE |
| ADD_CLASS | ADD_ENUM |
| REMOVE_CLASS | REMOVE_ENUM |
| FILE_CREATED | ADD_TYPE_ALIAS |
| FILE_DELETED | REMOVE_TYPE_ALIAS |
| CALLS_FUNCTION |
The type field in the JSON output gains six new allowed string values. Every existing value and field is unchanged. Additive, not breaking — old consumers keep working.
Definition of Done ✅
- A
.ts/.tsxfile with interfaces, enums, and type aliases scans to the correctSymbolTypes and line numbers — verified by hand against the source — andnowreck fix --pre <empty> --post <repo>detects the expectedADD_INTERFACE/ADD_ENUM/ADD_TYPE_ALIASchanges matching reality. .ts/.tsx/.js/.pyrepos produce output **byte-iden...
NoWreck v0.7.0 — TSX (`.tsx`) Support Release
NoWreck v0.7.0 — TSX (.tsx) Support Release
Release date: August 2026
Previous release: v0.6.0 (Verbose Mode)
Focus: .tsx files (TypeScript + JSX) scan, symbol-extract, call-extract, change-detect, and verify — folded into the existing TypeScript family. Zero new dependencies (the TSX grammar ships with the already-used tree-sitter-typescript package), zero changes to the verifier, reporter, claim types, or JSON schema.
What's new in v0.7.0
.tsx file support ✅
React components are ordinary functions, arrow-function consts, and classes — all already covered by the existing SymbolType set. The scanner now parses .tsx files with the TSX grammar (language_tsx(), from the same package v5 already depends on) and feeds the exact same symbols and calls through the existing pipeline:
function App() { return <div/> }→ FUNCTIONconst App = () => <div/>→ FUNCTION (arrow assignee)class App extends React.Component { render() { return <div/> } }→ CLASS + METHOD (render)onClick={() => doThing()}→ nested named arrows are collected as callers; identifier handlers (onClick={handleClick}) and member calls (this.toggle()) are ignored — same rules as.ts/.jsexport default function App() {...}→ collected; anonymousexport default () => <div/>→ ignored (no name)- Fragments, generics, interfaces, nested components — parsed, no crashes
JSX elements are expressions, not symbols or calls. <div>, <Component/>, and JSX attributes never become symbols or calls — verified by hand and by test.
The design decision: fold into the TS family
.tsx is the same language as .ts — same grammar package, same symbol shapes, same 7 claim types. So .tsx files fold into the existing ScanResult.ts_files field rather than getting a parallel tsx_files field. scan_ts_file() / scan_ts_calls() dispatch on file extension; _discover_ts_files() matches both *.ts and *.tsx; symbol_index, change_detector, picker, and the JSON schema needed zero changes.
Scope boundary
.ts/.js/.pybehaviour — byte-identical to v0.6.0 (hard gate)- Same 7 claim types — interfaces, enums, and type aliases in
.tsx/.tsremain uncaptured (they need new claim types first; still deferred) - No JSX-element symbols — markup is not a symbol
- No new dependencies, no verifier/reporter changes, no JSON schema changes
Test suite growth
| Suite | v0.6.0 | v0.7.0 | Growth |
|---|---|---|---|
| pytest (project unit tests) | 449 | 469 | +20 |
| TS comprehensive | 42 tests | 42 tests | — |
| TS multi-round | 29 tests | 29 tests | — |
| TSX comprehensive (new) | — | 54 tests | +54 |
| TSX multi-round (new, 7 rounds) | — | 36 tests | +36 |
| JS comprehensive | 101 tests | 101 tests | — |
| JS multi-round | 80 tests | 80 tests | — |
| Milestone 1 checkpoint (4 repos) | 45 tests | 57 tests | +12 |
| Milestone 1 demo (5 repos incl. pure-tsx) | Clean | Clean | — |
| Change detector (incl. new TSX class) | 39 tests | 47 tests | +8 |
| Live hallucination-catch tests (JS + TS + TSX) | PASS | PASS | — |
| ruff | 0 issues | 0 issues | — |
| basedpyright | 0 errors | 0 errors | — |
+20 new pytest tests, broken down as:
tests/test_change_detector.py—TestDetectTsxChanges(8 tests): component add →ADD_FUNCTION, component remove →REMOVE_FUNCTION, replace in single file → add + remove, class component →ADD_CLASS+ method (folds toADD_FUNCTIONwithparent_class, same as.ts/.js), TSX call detected,<Child/>usage NOT a call, identical pre/post → no changes, file create/deletetest_milestone1/test_milestone1_checkpoint.py—TestPureTsxRepo(12 tests): discovery (3 files), greeter components, calculator class + methods, models components, symbol counts, call detection,console.logexcluded, JSX-element-usage-not-a-call, file changes, no-change, determinism; pure-tsx added to cross-repo determinism and pre/post no-change loops
New sample suites (test_ts_samples/):
test_phase1_comprehensive_tsx.py— 54 tests: component shapes, handlers and nested arrows, exports/generics/interfaces, anonymous default exports, mixed edge cases (IIFE skip, interface/type/enum negatives, calls in JSX-in-body), error handling,repo_rootrelativisation, determinismtest_phase1_multiround_tsx.py— 36 tests across 7 rounds: symbol repeatability ×3, call repeatability ×3 + known-call set, 660-symbol stress file, path variants, real-world React patterns, line-number accuracy, chaos test
New sample files: edge_tsx_components.tsx, edge_tsx_handlers.tsx, edge_tsx_exports.tsx, edge_tsx_anon_default.tsx, edge_tsx_mixed.tsx.
File changes
Modified files
| File | What changed |
|---|---|
nowreck/scanner/typescript_scanner.py |
_get_tsx_language() (lazy language_tsx()); _new_parser(language); scan_ts_file / scan_ts_calls dispatch on .tsx extension; docstrings → TS family |
nowreck/scanner/repository_scanner.py |
_discover_ts_files() matches both *.ts and *.tsx (via itertools.chain); ScanResult.ts_files docstring → TS family |
test_milestone1/test_milestone1_checkpoint.py |
PURE_TSX_REPO, EXPECTED_TSX_FILES, fixture, TestPureTsxRepo class, added to cross-repo determinism + pre/post loops |
test_milestone1/demo_milestone1.py |
Pure TSX repo added to the demo list; TS print line relabeled TS files: |
tests/test_change_detector.py |
TestDetectTsxChanges class (8 tests) |
README.md |
Roadmap: TSX marked done in v0.7.0 |
docs/nowreck-v7-scope.md |
Full scope document tracing the increment |
docs/release7.md |
This release notes file |
New files
| File | What it covers |
|---|---|
test_milestone1/repos/pure-tsx/src/ |
New milestone repo: greeter.tsx, calculator.tsx, models.tsx (React-style equivalents of pure-ts) |
test_ts_samples/test_phase1_comprehensive_tsx.py |
54-test comprehensive TSX suite |
test_ts_samples/test_phase1_multiround_tsx.py |
36-test, 7-round TSX suite |
test_ts_samples/edge_tsx_*.tsx |
5 TSX sample files |
test_milestone1/live_tsx_hallucination_test.py |
Live-model TSX DoD test (Phase 4) |
docs/nowreck-v7-scope.md |
Full scope document |
docs/release7.md |
This release notes file |
Unchanged
_tree_sitter_helpers.py,symbol_index.py,change_detector.py— 0 changes- Claim parser, claim verifier, reporter, CLI, picker — 0 changes
- JSON output schema — 0 changes
- Claim types — exactly the same 7
.ts/.js/.pyscanning behaviour — byte-identical (hard gate)- Existing milestone repos (pure-python, pure-js, pure-ts, mixed) — 0 changes
- Dependencies — 0 new packages
Installing / upgrading
pipx install . # fresh install from repo
pip install -e . # or editable installRequires Python 3.10+. No new dependencies.
nowreck --version
# → nowreck 0.7.0Definition of Done ✅
- A
.tsxfile with JSX (function components, class components, arrow components, JSX-in-body, handlers) scans to the correct symbols and calls — verified by hand against the source, andnowreck fix --pre <empty> --post <pure-tsx repo>detects the expected changes matching reality. .ts-only repos produce output byte-identical to v0.6.0 for the same inputs.- The full existing test battery passes, plus the new TSX sample suites and milestone-checkpoint assertions.
- ruff: 0 issues, basedpyright: 0 errors.
- Live TSX DoD test (real model, induced false claim) passes at release time with the user's key.
Result (verified live): ran the real CLI against the pure-tsx milestone repo (empty pre → post with a real added component WelcomeBanner). 14 hand-written claims → 12 CONFIRMED / 1 CONTRADICTED (the induced false call Farewell → notify, which doesn't exist — correctly caught) / 1 UNVERIFIABLE (GhostComponent, which doesn't exist). Verbose output showed every Matched: block with line_number values cross-checked against the actual .tsx source — all 10 matched definitions exact (e.g. Greeting line 3, formatGreeting line 8, Farewell line 12, WelcomeBanner line 17 of greeter.tsx; Calculator line 3, computeAverage line 30 of calculator.tsx; UserCard line 8, AdminCard line 17, UserList line 31 of models.tsx). All 70 non-verbose output lines preserved verbatim in verbose mode (only the one-line Evidence: / unexplained summaries replaced by detail blocks, per v0.6.0 design). The .ts-only pure-ts repo scans identically (3 files, 16 symbols, 0 failures, extensions strictly .ts).
Live DoD (real model, user's key, nvidia/nemotron-3-ultra-550b-a55b:free): TSX live test PASS ×2 rounds — round 1: 18 claims → 17 CONFIRMED / 1 CONTRADICTED (induced false call caught) / 0 UNVERIFIABLE; round 2: 12 claims → 11/1/0. Identical catch both times.
What's next
The roadmap remains focused on narrow, testable increments, each with its own scope document and phase-by-phase build discipline.
explanationfield on claims — model + prompt change (README documents it, theClaimmodel doesn't have it yet) — deferred from v6- Scan-summary expansion in verbose mode (per-language file counts) — deferred from v6
- Interfaces / enums / type aliases as claim types (
ADD_INTERFACE/REMOVE_INTERFACE) — still deferred; needs new claim types first - TS polish (from v5): abstract methods, constructor parameter properties, decorators — separate polish increment
- Additional model providers (Anthropic, Gemini)
- Caching for large repositories
- CI/CD integration
NoWreck v0.6.0 — Verbose Mode Release
NoWreck v0.6.0 — Verbose Mode Release
Release date: August 2026
Previous release: v0.5.0 (TypeScript Support)
Focus: --verbose mode showing full deterministic evidence per claim — the oldest item on the roadmap. A reporter + CLI feature only: zero changes to scanners, the symbol index, the change detector, the claim parser, the verifier, the 7 claim types, or the JSON schema.
What's new in v0.6.0
--verbose mode ✅
The terminal report already showed, per claim, a one-line verdict and a
one-line Evidence: / Reason:. Verbose mode adds full deterministic
detail for every claim — the exact structural facts the verifier matched:
nowreck fix --pre <pre-snapshot> --post <post-snapshot> --claims '<json>' --verboseFor each CONFIRMED / CONTRADICTED claim, verbose mode shows:
Claim:— all eight claim identity fields exactly asreport_json
serializes them:type,symbol_name,file_path,parent_class,
line_number,caller_name,called_name,confidence(the model's
original value)Matched:— the completeDetectedChangefield dump that confirmed
or contradicted the claim, including the exactline_numberof the
matched symbol — a structural fact the one-line view hidesConfidence:— the display confidence with the same 100%-for-
structural-match rule as the claim line
For UNVERIFIABLE claims it shows the full claim dump plus the existing
Reason:. Unexplained changes get a full DetectedChange field dump
instead of the one-line summary.
Every field shown is already computed by the pipeline — verbose mode is
a presentation-layer change only. It proves why a verdict was reached by
printing the exact structural fact the verifier matched. Determinism is
unchanged: verbose mode shows more of the same deterministic facts, never
new judgment.
Scope boundary: JSON unchanged
nowreck fix --json already serializes the full matched_change for every
result — it was already "verbose" in machine-readable form. --verbose
does not change JSON output; the CI schema stays frozen. --verbose
and --json together simply behave like --json.
Non-verbose output: byte-identical
The default (non-verbose) rendering is pinned byte-for-byte to the v0.5.0
output. A golden regression test captures the v0.5.0 rendering and asserts
the current default matches it exactly — the hard gate that proves verbose
mode only adds detail.
Test suite growth
| Suite | v0.5.0 | v0.6.0 | Growth |
|---|---|---|---|
| pytest (project unit tests) | 433 | 449 | +16 |
| JS comprehensive | 101 tests | 101 tests | — |
| JS multi-round | 80 tests | 80 tests | — |
| TS comprehensive | 42 tests | 42 tests | — |
| TS multi-round | 29 tests | 29 tests | — |
| Milestone 1 checkpoint (4 repos) | Clean | Clean | — |
| Phase 4a demo (17 TS claims) | Clean | Clean | — |
| Live hallucination-catch tests (JS + TS) | PASS | PASS | — |
| ruff | 0 issues | 0 issues | — |
| basedpyright | 0 errors | 0 errors | — |
+16 new pytest tests, broken down as:
- Phase 1 (plumbing):
tests/test_cli.py—--verboseparses, defaults
toFalse, accepted in both prompt-mode and pre/post-mode paths;
tests/test_picker.py— both picker flows ask the verbose question,
answer Yes → fresh verbose reporter for that run only (shared reporter
never mutated), answer No → v0.5.0 rendering path;tests/test_picker_integration.py
— happy-path asserts the question is asked once with the right prompt - Phase 3 (rendering):
tests/test_terminal_reporter.py—TestReporterVerbose
class (10 tests): full claim field dump, full matched-change dump,
UNVERIFIABLE claim + reason, unexplained full change dump,None-field
omission, claim-line byte-identity across modes, Evidence-line
replacement (not duplication), non-verbose byte-identity to v0.5.0
(golden gate), determinism across runs, CONTRADICTED matched-change dump
File changes
Modified files
| File | What changed |
|---|---|
nowreck/cli.py |
--verbose flag on fix (store_true, default False, help notes no-op with --json) |
nowreck/reporter/terminal_reporter.py |
__init__(colour=True, verbose=False); claim/unverifiable/unexplained sections branch on verbose; new _append_verbose_claim_detail + _append_verbose_change_detail helpers |
nowreck/main.py |
Reporter constructed once as TerminalReporter(colour=colour, verbose=args.verbose) |
nowreck/picker.py |
_ask_verbose() helper; both flows (_run_verification, _run_pre_post) ask before rendering; Yes → fresh TerminalReporter(colour=True, verbose=True) per run |
tests/test_cli.py |
3 new flag tests |
tests/test_picker.py |
2 new verbose-choice test classes (3 tests) + confirm-mock on 8 existing tests |
tests/test_picker_integration.py |
Happy-path asserts verbose question; confirm-mock on 3 pre_post tests |
tests/test_terminal_reporter.py |
TestReporterVerbose class (10 tests) |
README.md |
Roadmap: --verbose marked done in v0.6.0; TSX marked v0.7.0 |
docs/nowreck-v6-scope.md |
Full scope document tracing the increment |
docs/release6.md |
This release notes file |
New files
| File | What it covers |
|---|---|
docs/nowreck-v6-scope.md |
Full scope document (Phase 4 output) |
docs/release6.md |
This release notes file |
Unchanged
- Python / JavaScript / TypeScript scanners — 0 changes
- Symbol index, change detector, claim parser, claim verifier — 0 changes
- JSON output schema — 0 changes
- Claim types — exactly the same 7
- Non-verbose terminal output — byte-identical (golden-tested)
- All milestone repos — 0 changes
- Dependencies — 0 new packages
Installing / upgrading
pipx install . # fresh install from repo
pip install -e . # or editable installRequires Python 3.10+. No new dependencies.
nowreck --version
# → nowreck 0.6.0Definition of Done ✅
nowreck fix --pre <empty> --post <pure-ts repo> --verboseshows, for a
hand-written claim set, the full claim identity and the exact
DetectedChangefields that confirmed/contradicted it — matching
reality.nowreck fix ...(without--verbose) output is byte-identical to
v0.5.0 for the same inputs.- The full existing test battery passes, plus the new verbose tests.
- ruff: 0 issues, basedpyright: 0 errors.
Result (verified live): ran the real CLI against the pure-ts milestone
repo (empty pre → full post, 17 hand-written claims covering all 7 claim
types). Verbose output showed every Matched: block with line_number
values cross-checked against the actual source — all 12 definitions
matched exactly (e.g. formatGreeting at line 9 of greeter.ts,
Calculator at line 3 of calculator.ts, AdminUser at line 20 of
models.ts). All 75 non-verbose output lines are preserved verbatim in
verbose mode (only the one-line Evidence: / unexplained summaries are
replaced by detail blocks, per design). Milestone demos pass on all 4
repos; 45/45 milestone checkpoint; full battery green.
What's next
The roadmap remains focused on narrow, testable increments, each with its
own scope document and phase-by-phase build discipline. v0.7.0 is TSX
(.tsx files) — decided during the v6 planning conversation; it gets its
own scope document when work begins.
- TSX (
.tsxfiles) — separate TSX grammar + JSX handling — v0.7.0 (decided) explanationfield on claims — model + prompt change (README documents
it, theClaimmodel doesn't have it yet) — deferred from v6- Scan-summary expansion in verbose mode (per-language file counts) —
deferred from v6; verbose is about claim evidence, not scan statistics - Additional model providers (Anthropic, Gemini)
- Caching for large repositories
- CI/CD integration
NoWreck v0.5.0 — TypeScript Support Release 🎉🎉
NoWreck v0.5.0 — TypeScript Support Release
Release date: August 2026
Previous release: v0.4.0 (JavaScript Polish)
Focus: Adding TypeScript as a first-class language alongside Python and JavaScript — same 7 claim types, same deterministic pipeline, zero changes to the verifier.
What's new in v0.5.0
TypeScript support ✅
NoWreck now scans .ts files with the same structural pipeline it uses for
Python and JavaScript. Everything that works for JS symbols works for TS
symbols — the verifier, change detector, and reporter never need to know
which language produced the data.
| Pattern | Captured as |
|---|---|
function foo() {} |
FUNCTION foo |
const foo = () => {} |
FUNCTION foo |
function* gen() {} |
FUNCTION gen |
async function foo() {} |
FUNCTION foo |
class Foo { bar() {} } |
CLASS Foo + METHOD bar |
export function foo() {} |
FUNCTION foo (export unwrapped) |
export default function foo() {} |
FUNCTION foo |
const x = (function() { ... })() (IIFE) |
⛔ Explicitly excluded |
Deferred (documented, not built): interfaces, type aliases, enums,
TSX (.tsx) files, decorators, and access modifiers — each has its own
reasoning in docs/nowreck-v5-scope.md.
Shared tree-sitter helpers
The JS scanner's helpers (_unwrap_parens, _is_iife, arrow-declarator
handling, call detection) were language-agnostic — the TypeScript grammar
uses identical node type names for every in-scope pattern. They were
extracted into nowreck/scanner/_tree_sitter_helpers.py and are now shared
by both the JS and TS scanners. This removes ~390 lines of duplication and
makes future language scanners (Rust, Go) even simpler to add.
New dependency
tree-sitter-typescript>=0.23.2
Test suite growth
| Suite | v0.4.0 | v0.5.0 | Growth |
|---|---|---|---|
| pytest (project unit tests) | 388 | 388 | — |
| JS comprehensive | 101 tests | 101 tests | — |
| JS multi-round | 80 tests | 80 tests | — |
| TS comprehensive (new) | — | 42 tests | +42 |
| TS multi-round (new) | — | 29 tests | +29 |
| Milestone 1 (4 repos: py + js + ts + mixed) | Clean | Clean | — |
| Phase 4a demo (17 TS claims) | — | Clean | — |
| Live hallucination-catch test (JS) | Clean | Clean | — |
| Live hallucination-catch test (TS, new) | — | PASS (Nemotron 3 Ultra, free) | — |
| ruff | 0 issues | 0 issues | — |
| basedpyright | 0 errors | 0 errors | — |
42 TS comprehensive tests — covering every TS pattern in scope with
positive and negative controls, including a negative test proving that
interfaces, type aliases, and enums are not captured.
29 TS multi-round tests — repeatability (3 identical runs), a 1100-symbol
stress file, path variants, real-world TS patterns, line-number accuracy,
JS regression, and chaos sampling.
File changes
Modified files
| File | What changed |
|---|---|
nowreck/scanner/javascript_scanner.py |
Import shared helpers from _tree_sitter_helpers.py; removed duplicated local copies |
nowreck/scanner/repository_scanner.py |
ScanResult.ts_files field, _discover_ts_files(), _parse_ts_file(), success_count includes TS |
nowreck/scanner/symbol_index.py |
build() processes ts_files alongside modules and js_files |
nowreck/detector/change_detector.py |
TS files included in file diffs + TS call re-read for CALL_DETECTED |
nowreck/picker.py |
Scan summary shows TS file counts |
test_milestone1/test_milestone1_checkpoint.py |
TestPureTsRepo class + TS in cross-repo determinism |
test_milestone1/demo_milestone1.py |
Shows .ts files in scan output |
pyproject.toml |
Version 0.5.0, new tree-sitter-typescript>=0.23.2 dependency |
nowreck/__init__.py |
Version bump to 0.5.0 |
nowreck/main.py |
Banner updated to v0.5.0 |
README.md |
Limitations + Roadmap + scan description updated for TS |
use.md |
Version + troubleshooting updated for TS |
New files
| File | What it covers |
|---|---|
nowreck/scanner/typescript_scanner.py |
The TS scanner (scan_ts_file, scan_ts_calls) |
nowreck/scanner/_tree_sitter_helpers.py |
Shared tree-sitter helpers (symbol collection, IIFE detection, call extraction) |
test_ts_samples/edge_basic.ts |
Basic function, arrow, class, method |
test_ts_samples/edge_export.ts |
Export function/class/const-arrow, export default |
test_ts_samples/edge_generators.ts |
Generator/async-generator patterns |
test_ts_samples/edge_iife.ts |
IIFE exclusion patterns |
test_ts_samples/edge_types_only.ts |
Negative test — interfaces/types/enums NOT captured |
test_ts_samples/test_phase1_comprehensive.py |
42-test comprehensive suite |
test_ts_samples/test_phase1_multiround.py |
29-test multi-round/stress suite |
test_milestone1/repos/pure-ts/ |
Pure-TypeScript milestone repo (3 files) |
test_milestone1/demo_phase4a_ts.py |
End-to-end pipeline demo on pure-ts repo |
test_milestone1/live_ts_hallucination_test.py |
Definition-of-Done live-model test (needs API key) |
docs/nowreck-v5-scope.md |
Full scope document tracing the increment |
docs/release5.md |
This release notes file |
Unchanged
- Python scanner — 0 changes
- Claim verifier — 0 changes
- Claim parser — 0 changes
- Claim types — exactly the same 7
- CLI interface, interactive picker structure, configuration
- All existing milestone repos (
pure-python,pure-js,mixed)
Installing / upgrading
pipx install . # fresh install from repo
pip install -e . # or editable installRequires Python 3.10+. TypeScript scanning requires tree-sitter-typescript
(installed automatically with the package).
nowreck --version
# → nowreck 0.5.0Definition of Done ✅
The v5 Definition of Done — the same live-model hallucination-catch test
used for Python and JS, now on a TypeScript test file — is at
test_milestone1/live_ts_hallucination_test.py. It deliberately induces a
false CALLS_FUNCTION claim (farewell() -> notify(), where notify does
not exist) and expects the verifier to catch it as CONTRADICTED while real
TS symbols confirm.
Result (verified live): run against OpenRouter with the free
nvidia/nemotron-3-ultra-550b-a55b:free model — 20 claims, 19 CONFIRMED,
1 CONTRADICTED, 0 UNVERIFIABLE. Real TS symbols confirmed; the induced
false call was caught. The JS DoD test passes on the same model, confirming
the shared-helper refactor did not regress v4.
NOWRECK_API_KEY=your-key python test_milestone1/live_ts_hallucination_test.pyWhat's next
The roadmap remains focused on narrow, testable increments, each with its
own scope document and phase-by-phase build discipline:
- TSX (
.tsxfiles) — separate TSX grammar + JSX handling --verbosemode showing full deterministic evidence per claim- Additional model providers (Anthropic, Gemini)
- Caching for large repositories
- CI/CD integration
NoWreck v0.4.0 — JavaScript Polish Release
NoWreck v0.4.0 — JavaScript Polish Release
Release date: July 2026
Previous release: v0.3.0 (JavaScript Core)
Focus: Closing three deferred JavaScript gaps: generator functions, export default patterns, and IIFE awareness.
What's new in v0.4.0
Gap 1: Export default patterns ✅
Named default exports (export default function foo() {}, export default class Foo {}) were already working in v3 — the tree-sitter grammar provides a declaration field for these. The original scope doc's assumption that they were dropped was wrong. v0.4.0 adds proper test coverage and fixes a misleading comment that claimed they weren't captured.
No code logic changes were needed — just tests and documentation.
Gap 2: Generator functions ✅
All function* generator patterns are now captured:
| Pattern | Captured as | Previously |
|---|---|---|
function* foo() {} |
FUNCTION foo |
❌ Dropped |
async function* bar() {} |
FUNCTION bar |
❌ Dropped |
const baz = function*() {} |
FUNCTION baz |
❌ Dropped |
export function* qux() {} |
FUNCTION qux |
❌ Dropped |
export default function* gen() {} |
FUNCTION gen |
❌ Dropped |
What changed: Added generator_function_declaration (for declarations) and generator_function (for expressions) alongside the existing function_declaration and function_expression checks in 6 sites across the scanner.
Gap 3: IIFE awareness ✅
Immediately-invoked function expressions are now explicitly excluded from being captured as symbols, with debug logging so you can see why they were skipped:
| Pattern | Before v4 | After v4 |
|---|---|---|
const x = (function() { ... })() |
❌ Silently excluded | ✅ Explicitly excluded + tested |
const x = (() => { ... })() |
❌ Silently excluded | ✅ Explicitly excluded + tested |
(function() { ... })() |
❌ Silently excluded | ✅ Explicitly excluded + tested |
void function() { ... }() |
❌ Silently excluded | ✅ Explicitly excluded + tested |
const normal = () => {} (positive control) |
✅ Captured | ✅ Still captured |
What changed: A new _is_iife() helper, explicit skip logic in both _collect_top_level_symbols and _maybe_arrow_function_declarator, and a latent bug fix in _unwrap_parens where child(0) returned the ( token instead of the inner expression.
Bonus fix: _unwrap_parens latent bug
Found and fixed a bug dating back to v3's JS scanner: child(0) on a parenthesized_expression node returned the ( syntactic token — not the inner expression. Changed to named_child(0), which correctly skips syntactic tokens. The old code worked by accident because ( doesn't match any function type check, but it would have failed for genuinely parenthesized arrow functions like const x = (() => 1).
Test suite growth
| Suite | v0.3.0 | v0.4.0 | Growth |
|---|---|---|---|
| pytest (project unit tests) | 388 | 388 | — |
| JS comprehensive | 78 tests | 101 tests | +23 |
| JS multi-round | 80 tests | 80 tests | — |
| Milestone 1 (3 repos) | Clean | Clean | — |
| Phase 4a demo (14 claims) | Clean | Clean | — |
| Live hallucination-catch test | Clean | Clean | — |
| ruff | 0 issues | 0 issues | — |
| basedpyright | 0 errors | 0 errors | — |
101 comprehensive tests — covering every JS pattern NoWreck can parse, with positive and negative controls for each.
File changes
Modified files
| File | What changed |
|---|---|
nowreck/scanner/javascript_scanner.py |
Added generator types (6 sites), _is_iife helper, _unwrap_parens latent bug fix, explicit IIFE skip logic |
test_js_samples/edge_export_default.js |
Updated comments, added export default class Bar with method |
test_js_samples/edge_async_generators.js |
Added generator expression pattern, updated comments |
test_js_samples/test_phase1_comprehensive.py |
+23 tests — export default, generators, IIFEs |
test_js_samples/test_phase1_multiround.py |
Updated round 4 generator assertion |
README.md |
Updated Limitations and Roadmap for v0.4.0 |
nowreck/__init__.py |
Version bump to 0.4.0 |
pyproject.toml |
Version bump to 0.4.0 |
nowreck/main.py |
Banner updated to v0.4.0 |
nowreck/reporter/terminal_reporter.py |
Docstring updated to v0.4.0 |
New files
| File | What it covers |
|---|---|
test_js_samples/edge_generators.js |
All generator patterns (declaration, async, expression, export, export default, positive/negative controls) |
test_js_samples/edge_iife.js |
All IIFE patterns (const, arrow, standalone, void, var, positive controls) |
docs/release4.md |
This release notes file |
docs/nowreck-v4-scope.md |
Full scope document tracing the increment |
Unchanged
- All milestone repos (
test_milestone1/) - Symbol index, change detector, claim parser, claim verifier, reporter
- CLI interface, interactive picker, configuration
- Python scanner — 0 changes
- No new dependencies
Installing / upgrading
pipx install . # fresh install from repo
pip install -e . # or editable installRequires Python 3.10+. JavaScript scanning requires tree-sitter-javascript (installed automatically with the package via optional dependency).
nowreck --version
# → nowreck 0.4.0What's next
The roadmap remains focused on narrow, testable increments:
--verbosemode showing full deterministic evidence per claim- Additional model providers (Anthropic, Gemini)
- Caching for large repositories
- TypeScript support — likely the next major language increment
- CI/CD integration
Each increment gets its own scope document, its own phase-by-phase build discipline, and its own human-checked checkpoints.
NoWreck v0.3.0 — JavaScript Support 🎉
NoWreck v0.3.0 — JavaScript Support 🎉
Deterministic verification for AI code changes — now for JavaScript too.
What's new in v0.3.0
The headline feature is JavaScript support — NoWreck can now scan, parse, and verify JavaScript files alongside Python files in the same repository. This is the first time the pipeline has been extended beyond Python, and it's designed so that adding future languages follows the same pattern.
JavaScript scanning via Tree-sitter
JavaScript files (.js) are now parsed using Tree-sitter with the tree-sitter-javascript grammar, producing the same Symbol / SymbolType data shapes as the Python parser. The rest of the pipeline — change detection, claim verification, and reporting — never knows or cares which language produced the data.
What the JS scanner captures:
| Pattern | Example | Status |
|---|---|---|
| Function declarations | function greet() {} |
✅ |
| Arrow functions (assigned) | const greet = () => {} |
✅ |
| Classes | class Calculator {} |
✅ |
| Class methods | add(a, b) { ... } |
✅ |
export function |
export function greet() {} |
✅ |
export class |
export class Calculator {} |
✅ |
export const (arrow) |
export const greet = () => {} |
✅ |
| Function calls | greet() in function bodies |
✅ (simple calls only) |
Mixed-language repos
NoWreck handles repositories with both .py and .js files in a single scan. The pre/post summaries show separate file counts for each language:
Scan Summary
────────────
Python: 5 files (3 success, 0 failed)
JavaScript: 3 files (3 success, 0 failed)
Symbols: 22 total (12 functions, 4 classes, 6 methods)
Same 7 claim types — unchanged
No new claim types were added. The same 7 deterministic claims work across both languages:
ADD_FUNCTION/REMOVE_FUNCTIONADD_CLASS/REMOVE_CLASSFILE_CREATED/FILE_DELETEDCALLS_FUNCTION
A claim about a Python function and a claim about a JavaScript function are verified identically — the verifier doesn't need to know which language produced the data.
Lazy dependency loading
The tree-sitter-javascript dependency is loaded lazily — it's only imported when a JavaScript file is actually scanned. This means:
- Pure-Python repos work without
tree-sitter-javascriptinstalled - No cascading import failures in the Python-only test suite
- All 388 existing pytest tests pass without the JS grammar
Full changelog
Added
- New module:
nowreck/scanner/javascript_scanner.py— Tree-sitter-based JavaScript parser with lazy grammar loadingscan_js_file(path)— parses a.jsfile and returnslist[Symbol]scan_js_calls(source_code, symbols)— extractscall_expressionnodes and returnslist[DetectedChange]forCALL_DETECTED_get_js_language()— lazy-loadstree-sitter-javascriptwith double-checked caching
SymbolIndex.js_symbolsproperty — returns only JavaScript symbols (those without anastmodule origin)SymbolIndex.by_name(name)— language-agnostic lookup (finds symbols across both languages)RepositoryScannerextended — discovers.jsfiles, routes them tojavascript_scanner, populatesScanResult.js_filesChangeDetector.detect()extended — extracts JScall_expressionnodes alongside Pythonast.CallwalkingTerminalReporterextended — shows Python vs JS file counts and language-specific symbol breakdowns in scan summaries_strip_markdown_fence()inclaims/parser.py— handles```json...```from model output
Changed
- Bumped version from v0.2.0 → v0.3.0
- Updated
pyproject.toml— addedtree-sitter-javascript>=0.25dependency - Updated
.gitignore— added_binary_test.binunder test artifacts - Updated
README.md— JS integration documented in scan stage, limitations, roadmap, troubleshooting, and tips - Updated
use.md— version references, JSON schema examples - Fixed pre-existing ruff issues in
tests/test_picker.pyandtests/test_picker_integration.py(unused imports, line lengths) - Fixed pre-existing type errors in
nowreck/picker.py(missingquestionarystub) - Fixed ordering-sensitive flaky test (
test_empty_prompt_flow) intest_picker_integration.py
Known limitations (v0.3.0)
- Generator functions (
function*) — not captured (deferred) export default— not captured (deferred)- IIFEs — not captured (deferred)
- TypeScript — not yet supported (separate scope, deferred)
- Attribute calls (e.g.,
console.log(),obj.method()) — excluded fromCALLS_FUNCTIONdetection; only simplename()calls are tracked - All existing Python limitations still apply (no dynamic behavior, no cross-file resolution beyond direct name matching, no semantic analysis)
Test statistics
| Suite | Tests | Result |
|---|---|---|
| Python unit tests (pytest) | 388 | ✅ 388/388 pass |
| JS multi-round (repeatability, stress, chaos) | 80 | ✅ 80/80 pass |
| JS comprehensive (core, edge cases, negatives, error handling) | 78 | ✅ 78/78 pass |
| Milestone 1 — pure Python repo | 10 | ✅ Deterministic (3x) |
| Milestone 1 — pure JS repo | 10 | ✅ Deterministic (3x) |
| Milestone 1 — mixed repo | 10 | ✅ Deterministic (3x) |
| Full pipeline determinism (mixed repo, 5 runs) | 1 | ✅ Identical every run |
| Phase 4a end-to-end demo (14 hand-written claims) | 14 | ✅ Pipeline clean |
| Phase 4d live-model hallucination-catch (real API) | 1 | ✅ Hallucination caught |
| Total | ~590 | ✅ All pass |
| Linting (ruff) | — | ✅ 0 issues |
| Type checking (basedpyright) | — | ✅ 0 errors, 0 warnings, 0 notes |
How it works
┌─────────────────────────────────────────────────────────┐
│ Prompt mode │
│ │
│ Your prompt ──► AI model ──► diff + claims │
│ │ │
│ ▼ │
│ Pre-scan ──► Symbol index ──► Change Detector │
│ Post-scan ──► Symbol index ────────┘ │
│ │ │
│ Claims ──► Claim Verifier ◄────────────┘ │
│ │ pure comparison — no AI judgment │
│ ▼ │
│ Verification Report │
│ ✓ CONFIRMED ✗ CONTRADICTED ? UNVERIFIABLE │
└─────────────────────────────────────────────────────────┘
Scan stage (now with dual-language support)
- Discover — recursively finds
.pyand.jsfiles in both snapshots - Parse — routes each file to the correct parser:
.py→ Python's built-inastmodule.js→ Tree-sitter withtree-sitter-javascriptgrammar
- Index — builds a unified
SymbolIndexfrom both languages
Both parsers produce identical Symbol / SymbolType data shapes (using LanguageAdapter patterns anticipated in earlier architecture). The rest of the pipeline is language-agnostic.
Quick start with JavaScript
# Create a JS test repo
mkdir -p /tmp/js-app/pre /tmp/js-app/post
cat > /tmp/js-app/pre/greeter.js << 'EOF'
function greet(name) {
return "Hello, " + name + "!";
}
EOF
cat > /tmp/js-app/post/greeter.js << 'EOF'
function greet(name) {
return "Hello, " + name + "!";
}
const farewell = (name) => "Goodbye, " + name + "!";
EOF
# Detect changes
nowreck fix --pre /tmp/js-app/pre --post /tmp/js-app/post
# Or with claims that include a hallucinated call
nowreck fix \
--pre /tmp/js-app/pre \
--post /tmp/js-app/post \
--claims '{
"claims": [
{
"type": "ADD_FUNCTION",
"symbol_name": "farewell",
"file_path": "greeter.js",
"confidence": 0.99,
"explanation": "Added farewell arrow function."
},
{
"type": "CALLS_FUNCTION",
"symbol_name": "farewell",
"file_path": "greeter.js",
"caller_name": "farewell",
"called_name": "notify",
"confidence": 0.85,
"explanation": "farewell calls notify to send the message."
}
]
}'
# Expected: ADD_FUNCTION CONFIRMED, CALLS_FUNCTION CONTRADICTED
# (farewell exists, but it doesn't call notify)Mixed Python + JavaScript
nowreck fix --pre ./before --post ./after
# → Shows Python: 3 files, JavaScript: 2 files in scan summaryDesign decisions
Why Tree-sitter?
JavaScript has no equivalent of Python's built-in ast module, so an external parser was required. Tree-sitter was chosen because:
- Mature JS grammar — well-maintained
tree-sitter-javascriptwith broad coverage - Reusable pattern — same parser family would be used for Go, Rust, etc.
- Concrete syntax trees — provides real source positions for accurate claim-to-diff line mapping
Why lazy imports?
The tree-sitter-javascript grammar is imported lazily (only when a .js file is actually scanned). This ensures:
- The Python-only test suite doesn't cascade-fail on import
- Pure-Python repos work without the JS grammar installed
- The dependency is a hard install requirement (in
pyproject.toml) but a soft runtime requirement
Why no new claim types?
The existing 7 claim types (ADD_FUNCTION, REMOVE_FUNCTION, ADD_CLASS, REMOVE_CLASS, FILE_CREATED, FILE_DELETED, CALLS_FUNCTION) are language-agnosti...
v0.2.0 - Interactive Terminal Picker
What's new
- Added
nowreck --interactive— a menu-driven interface for setting up config, running verification, and viewing reports without typing full commands and flags. - Existing CLI commands (
nowreck fix,nowreck config) are unchanged and remain the primary interface — the picker is an additional entry point, not a replacement.
Notes
- No changes to core verification logic — the picker calls the exact same pipeline as the CLI.
- Full v2 design rationale: see
docs/nowreck-v2-scope.md