# NoWreck v0.12.0 — Provider Consolidation + Scan Caching

> Source: <https://dev.to/astralxvoid/nowreck-v0120-provider-consolidation-scan-caching-49ne>
> Published: 2026-08-28 14:00:34+00:00

**NoWreck v0.12.0 — Provider Consolidation + Scan Caching**

**Deterministic AI Verifier** — v0.12.0

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.

``` bash
$ 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
```

Release date: August 2026

Previous release: v0.11.1 (Bugfix Release)

Focus: Two infrastructure improvements — consolidate provider resolution

into a single function and add file-level scan caching for large repositories.

What's new in v0.12.0

**Provider consolidation ✅**

Provider detection was split between two independent functions —

_auth_header() in provider.py and detect_adapter() in adapters.py —

both doing URL-matching independently. A new provider required updating both,

and they had to agree.

Now a single resolve_provider(base_url, override) function returns both

the adapter and the auth header type in one call:

ModelProvider._default_http_call()

│

└── resolve_provider(base_url, provider) → ProviderInfo

Single URL matching in adapters.py:

"api.anthropic.com" → (AnthropicAdapter, x-api-key)

"generativelanguage.googleapis.com" → (GeminiAdapter, x-goog-api-key)

else → (OpenAIAdapter, Authorization: Bearer)

One call. One URL match. Adapter and auth header always agree.

New: ProviderInfo dataclass, resolve_provider() function.

Removed: _auth_header() standalone function (replaced by _auth_header_from_type()).

Deprecated: detect_adapter() (still works, delegates to resolve_provider()).

**Scan caching ✅**

Every nowreck fix run re-scans every file in the repository from scratch.

For a repository with 500+ source files, this means 500+ parse operations

per run.

Now RepositoryScanner.scan() caches per-file results in .nowreck/cache/.

On subsequent runs, only files that actually changed are re-parsed:

RepositoryScanner.scan()

→ ScanCache.get(file_path, mtime, size, content_hash)

→ If hit: use cached result (no parse needed)

→ If miss: parse, then cache result

→ ScanCache.save() (atomic write to .nowreck/cache/scan_cache.json)

Cache key: (path, mtime, size, content_hash) — MD5 of file contents

catches same-size rewrites within the same filesystem timestamp quantum.

Cache format:

```
Python files: source text stored; ast.Module reconstructed via ast.parse() on load
JS/TS/Rust/Go files: symbol lists stored directly
```

Invalidation: mtime, size, content hash, or version mismatch → re-parse.

Version bump forces full re-parse. Cache is gitignored by .nowreck/.

New: ScanCache, CacheEntry, file_content_hash() in scanner/scan_cache.py.

Modified: RepositoryScanner.scan() integrates cache transparently.

New: Symbol.to_dict() / Symbol.from_dict() for JSON round-tripping.
