Dev.to WebDev 🛠 Dev 👁 1 📖 5 min read

NoWreck v0.17.0 — Nine Languages + Differential Audit

NoWreck v0.17.0 — Nine Languages + Differential Audit AstralXVoid / NoWreck A CLI tool that verifies AI coding assistant claims against actual struc

NoWreck v0.17.0 — Nine Languages + Differential Audit

NoWreck v0.17.0 — Nine Languages + Differential Audit

GitHub logo AstralXVoid / NoWreck

A CLI tool that verifies AI coding assistant claims against actual structural changes — catching hallucinated functions, fake calls, and missed modifications before they ship.

NoWreck

Deterministic AI Verifier — v0.17.0

tom
NoWreck is a deterministic structural verifier for AI-generated code-change claims.
When an AI describes a code change, NoWreck compares the claims against structural evidence derived by its own scanners — the verifier never asks another AI for an opinion.
Where the evidence comes from depends on the mode: in Pre/Post and Claims modes, from actual before/after repository snapshots; in Prompt Mode, from the model's own proposed diff.
ChatGPT Image Sep 10, 2026, 09_48_57 PM
$ nowreck fix "Add email validation to auth.py"

  Summary
  ────────────────────
  ● 3 claims total
  ● 2 confirmed
  ● 1 contradicted

  CONFIRMED
  ─────────
  ✓ ADD_FUNCTION validate_email → auth.py  (conf: 100%)
    Evidence: Function 'validate_email' was added in auth.py

  CONTRADICTED
  ────────────
  ✗ CALLS_FUNCTION validate_email → auth.py  (conf: 100%)
    Evidence: Function 'validate_email' was added in auth.py

What it catches

  • Hallucinated functions or classes — a claim that something was added when it isn't there
  • Fake internal API calls — a claim…

Release date: October 2026
Previous release: v0.16.0 (Verifiable Body Edits + Method Call Detection)
Focus: Prove the five existing parsers before extending them — a
differential audit against a deliberately dumb regex checker — then add four
new languages (Java, Kotlin, PHP, C++) under the same satisfaction bar.

What's new in v0.17.0
Differential audit — the parsers are now measured, not assumed ✅

Before a single new language landed, the five existing parsers were audited
against an independent oracle: a deliberately dumb regex checker
(tests/helpers/differential.py) run over a 60-file authored corpus
(12 files × 5 languages), compared through the real production pipeline
(RepositoryScanner → build_symbol_index → ChangeDetector._extract_calls)
— no mocks, no re-implementations. Every divergence was either a fixed
checker bug or a classified finding. The checker and the audit test are
permanent: they now cover all nine languages and run in the main suite
forever.

Result: 3 real gaps, all one defect, fixed.

Gap Fix

G1/G2 Calls inside anonymous arrows in argument/return position (this.enqueue(() => handler(p)), return () => this.unsubscribe(...)) were invisible — no caller to attribute them to The call walker now attributes an anonymous arrow's calls to the nearest enclosing named caller
G3 Calls inside JS/TS class-field arrow values (incrementBy = (step) => this.increment(step)) were never collected — tree-sitter models those as field definitions, not declarators Class-field arrows are collected as callers (named after the field)

Each shipped with the corpus file that caught it plus 23 pinning tests in
tests/test_call_edges.py that freeze every documented boundary, so an
accepted edge cannot drift silently. EXPECTED_DIVERGENCES is empty and
hygiene-enforced: a fixed gap's entry must be deleted, not left to rot.
Four new languages — nine total ✅
Language Extensions Grammar (installed) Symbols
Java .java tree-sitter-java 0.23.5 class / record → CLASS, interface / @interface → INTERFACE, enum → ENUM, methods → METHOD
Kotlin .kt, .kts tree-sitter-kotlin 1.1.0 class / data / sealed / value class / object → CLASS, interface / fun interface → INTERFACE, enum class → ENUM, annotation class → INTERFACE, typealias → TYPE_ALIAS
PHP .php tree-sitter-php 0.24.1 class → CLASS, interface → INTERFACE, enum → ENUM, trait → CLASS, functions and closures/arrows → FUNCTION, methods → METHOD
C++ .cpp, .cc, .cxx, .c++, .hpp, .hh, .hxx, .h++, .h tree-sitter-cpp 0.23.4 class / struct / union → CLASS, enum → ENUM, using / typedef → TYPE_ALIAS, methods, free functions, named lambdas

All four go through the same gates the first five did — grammar probes
resolved before any collector code, a scanner, full pipeline wiring
(scanner → index → detector → verifier counts → prompts), a differential
corpus, a change-detector matrix, a sample suite, and a milestone repo:
Language Probes pinned Corpus files Milestone repo
Java 33 (J1–J12) 15 pure-java
Kotlin 86 (K1–K16) 15 pure-kotlin
PHP 74 (PH1–PH12) 18 pure-php
C++ 78 (E1–E18) 17 pure-cpp

No new claim types and no schema change. ClaimType stays at 15 types
and CACHE_VERSION stays 2 — the four languages produce the same
ADD / REMOVE / CHANGED / CALLS_FUNCTION / CALL_REMOVED facts through the
existing taxonomy. C++ and Go are the two languages where INTERFACE never
fires; PHP is the one where TYPE_ALIAS never fires.
Awkward grammars, handled honestly

Adopting four grammars surfaced real parser defects, not just missing
features. The notable ones, each probed, fixed and pinned:

Kotlin silently loses declarations (D7). With two or more stacked
annotations, a plain top-level class / interface / annotation class
following any sibling declaration is destroyed — class is read as an
infix operator, the symbol vanishes and has_error stays False. Rather
than pattern-matching damage shapes (which grow with the grammar), the
scanner blanks annotation spans, re-parses the blinded source, then folds
each annotation back onto the declaration it owns via a positional
ownership map. Files with no annotations take the original path byte for
byte.
Kotlin's 7 confirmed misparses on ordinary source — only three of which
set has_error (D1–D7 in the audit report). The accepted edges are
documented next to the ones that were recovered.
Rust impl Trait for Type mis-attribution — methods in a trait impl
were parented to the trait instead of the implementing type (a
pre-existing v16-era defect found by the full-repo checkup). Fixed to read
the grammar's type field.
C++ header/impl split — a declaration and its out-of-line definition
are two independent per-file facts by design (no #include resolution); a
declaration-only member carries body_hash=None and can never fire
CHANGED_FUNCTION.
PHP string semantics — PHP is the one language where quote style
selects escape rules, so it has a dedicated normaliser; heredoc and nowdoc
stay distinct.

Phase 5 adversarial review — 19 defects found and fixed ✅

A second-pass review of the C++ surface (54-case divergence probe plus CST
dumps of every ambiguous shape) surfaced 21 divergences. All were
root-caused, fixed and pinned — 9 scanner defects (tagged/nested type
declarations, extern "C" single-declaration form, reference declarators,
conversion operators, class-field lambdas, member-template call targets,
grammar-error recovery inventing calls), 6 checker defects, and 11
end-to-end detector tests. Final state: 0 unexpected divergences.
Cross-language hardening ✅

Nine-language determinism sweep — the all-repos sweep had silently
lagged the four new repos, and had never compared the two identity-exempt
fields (line_number, body_hash), so a run-to-run hash difference could
have survived a "byte-identical" gate. It now spans 11 repos × nine
language maps and compares explicit
(name, type, path, line, parent_class, body_hash) tuples.
Picker summary knew only three languages — six of the nine were
invisible in the picker's pre/post scan output. Fixed with one loop over
all nine language maps; the Python/JS/TS lines stay byte-identical.
Cache round-trips closed for TypeScript / Rust / Go, plus an
all-nine stale-cache rebuild test (a v1 cache is rewritten hash-less and
re-scanned; every language is asserted to rebuild fresh, hash-carrying,
warm-honest entries).
📰 Read the original article on Dev.to WebDev

Originally published by Dev.to WebDev. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.