feat(context): AI-readiness gate, doc-truth rules, and 30% faster scans (re-land #44)#46
Merged
Merged
Conversation
Adds three Agent Context rules: context.undocumented-commands (high-signal Makefile targets / npm scripts no agent doc or README mentions), context.oversized-agent-doc (agent instruction files over the max_agent_doc_lines budget, default 600), and context.doc-link-rot (markdown links in agent docs and the root README that resolve to nothing; external URLs and anchors exempt, no network I/O). Broadens context.readme-drift to the same full prose extraction agent docs get, and moves markdown-link checking out of the drift extractor so a broken link is reported once. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The broadened readme-drift and new doc-link-rot rules flagged our own README: 14 machine-absolute doc links and two search-path candidates written as repo paths that do not exist. Repoint the links relatively, reword the config-discovery sentence, and document make fmt in CLAUDE.md so the undocumented-commands rule passes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e components - context_rules.legibility_warn_threshold / legibility_fail_threshold gate the repo_legibility score via a new context.legibility-threshold rule (fires when the score falls BELOW the threshold, since legibility is good-high; 0 disables, fail must be <= warn) - agent_docs component now gated on substance (25 x min(non-blank,10)/10) and reduced -2 per unresolvable agent-doc reference (capped at 10) - doc_accuracy penalty is proportional: round(20 x broken/total refs) instead of a flat -4 that saturated at 5 references - context_economy ramps linearly to zero at 25% oversized instead of 10% - navigability ignores conventional basenames (index.ts, __init__.py, mod.rs, main.go, ...) for both the score and context.ambiguous-symbol findings; context_rules.ambiguous_symbol_ignore replaces the default set Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- trend persisted per target at <cache>.legibility-history.<ext> following the slop/perf history pattern; artifacts annotated with previous_score and delta on subsequent scans - context_rules.legibility_history toggles persistence (nil = enabled), legibility_history_limit caps retained entries (default 100) - codeguard report -legibility-history prints the recorded trend, mirroring -slop-history and -perf-history Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- threshold warn/fail/disabled/pass paths plus config validation ordering - history persistence, delta annotation, and toggle-off behavior - calibration proofs: substance-gated agent_docs, proportional doc_accuracy, softened context_economy curve, conventional-basename ignore list and its replace semantics - report -legibility-history CLI trend, empty-history, and mode-flag exclusivity - updated artifact expectations to the recalibrated formulas Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rmulas - rewrite the Agent Context section: new config keys, score-below-threshold semantics, history + report flag, recalibrated component formulas, and the conventional-basename ignore list with replace semantics - dogfood: warn threshold 85 in the self-scan config (repo scores 100) and exclude the legibility history file from scanning Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The quality AI checks bypassed the per-scan file corpus: they re-walked the target and re-read the full source corpus 4-5 times per scan (dominant test framework, error style, naming convention, plus the per-file pass), and re-parsed every Go file that the corpus had already parsed. This made the quality section the scan's wall-clock critical path, with syscalls at ~41% of warm CPU. - add ListTargetFiles/ReadTargetFile hooks to checks/support.Context, wired to the corpus (mirroring VisitTargetFiles); nil-safe fallbacks for unit-test contexts live in quality_ai_corpus.go - route every walk-enumerated AI-check read (Go/Python/script targets, workspace package.json discovery) through the hooks; fixed-filename reads (go.mod, root package.json) stay direct to preserve their uncapped-read semantics - replace the redundant parser.ParseFile(..., 0) with the shared ParseComments corpus parse (support.ParseGoSource); drop the fn.Doc "go:" directive exemption that the mode-0 parse had kept latent so findings stay byte-identical (see NOTE in quality_ai_dead_code.go) - collapse the three Go repo-dominant style signals into one corpus pass (goRepoStyleProfile); each signal is an independent per-file sum, so the fold is behavior-identical Differential check: old vs new binaries scanning an identical pristine tree produce byte-identical JSON findings (modulo generated_at). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The clone detector re-hashed every threshold-token window from scratch, converting each token to []byte twice per window (~226 MB of allocations per scan), and lowercased every token at tokenize time (~175 MB more). - cloneToken now stores the original-case source slice (no per-token ToLower copy; tokens are ASCII-only by the token regex) plus a FNV-1a hash of the ASCII-lowercased text computed once at tokenize time - window grouping uses a rolling polynomial hash over the per-token hashes: O(1) per slide instead of O(threshold) bytes hashed, and zero allocations - token equality folds ASCII case with a hash short-circuit, which is exactly the historical lowercased-value comparison The hash function is not behavior-bearing: every candidate bucket is verified token-by-token in sharedCloneLength, so equal windows always group and colliding unequal windows are discarded. The new differential test pins findings captured verbatim from the pre-rewrite algorithm on a fixture covering three-way clones, case normalization, overlapping-window merging, and below-threshold duplicates. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CountLines allocated a string copy of the file plus a split slice on every call (~17.6 MB per scan). Count newline bytes in place instead, preserving the exact legacy semantics (all trailing newlines trimmed, empty input is one line). The new unit test cross-checks every edge case against the legacy strings-based formula. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Note in the architecture doc that the per-scan file corpus memoizes walks, reads, and parses and that the quality AI checks now share it; record the corpus read-cap semantics, the latent fn.Doc dead-code exemption, and the clone-hash verification invariant in the knowledge base. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… rules (#44) ## Summary Stacked on #41. Three tracks, built by parallel agents and integrated sequentially: codeguard's own scan gets measurably faster, the `repo_legibility` score becomes an enforceable and trended **AI-readiness gate**, and four new rules keep a repo's docs truthful for both AI agents and humans. ## 1. Scan performance (behavior-preserving, measured) | | before | after | |---|---|---| | Cold scan (this repo) | ~0.69 s | **~0.49 s** (−30%) | | Warm scan | ~0.60 s | **~0.46 s** (−24%) | - Quality's AI checks previously bypassed the shared scan corpus — 4–5 redundant full-corpus reads per scan (syscalls were 41% of warm CPU). New `ListTargetFiles`/`ReadTargetFile` corpus hooks route them all through one cached read; the redundant mode-0 re-parse now reuses the shared ParseComments AST. - Clone detector: tokens hashed once at tokenize time + O(1) rolling window hash, zero per-window allocations (was ~226 MB churn/scan). Hash is not behavior-bearing — every bucket pairing is still verified token-by-token. - One-pass dominant-style profile (test framework + error style + naming) replaces three corpus sweeps; allocation-free `CountLines`. - **Proof of identical behavior**: old vs new binaries produce byte-identical findings JSON on the same tree; a differential clone test captures the OLD algorithm's output verbatim and asserts the new one reproduces it. One semantic trap was found and neutralized: a `fn.Doc` directive exemption that never fired under the old parse mode would have silently activated — removed with a NOTE. ## 2. Enforceable AI-readiness score `repo_legibility` (0–100, explainable components) previously could not gate a build or show a trend. Now: - `context_rules.legibility_warn_threshold` / `legibility_fail_threshold` — fires `context.legibility-threshold` when the score falls **below** the floor (legibility is good-high; semantics documented), message carries the component breakdown. - History at `<cache>.legibility-history.<ext>` with previous_score/delta, plus `codeguard report -legibility-history`. - **Calibration fixes**: an empty CLAUDE.md no longer scores the full 25 agent-docs points (substance-gated + drift-penalized); context-economy ramps linearly to zero at 25% oversized (was a cliff at 10%); doc-accuracy penalty is proportional (broken/total) instead of saturating at 5 refs; conventional basenames (`index.ts`, `__init__.py`, `mod.rs`, `types.go`, …) no longer count as ambiguous — configurable via `ambiguous_symbol_ignore`. - Dogfooded: this repo runs with `legibility_warn_threshold: 85` as a live gate. ## 3. Doc-truth rules (Agent Context) | Rule | What it catches | |---|---| | `context.undocumented-commands` | high-signal Makefile targets / npm scripts (build, test, lint, fmt, …) that no agent doc or README mentions | | `context.oversized-agent-doc` | agent docs larger than `max_agent_doc_lines` (600) — they consume the context budget they exist to save | | `context.doc-link-rot` | markdown links in agent docs/README pointing at nonexistent files (relative + repo-absolute; no network I/O) | | README drift parity | `context.readme-drift` now gets the same full prose extraction as agent docs, not just shell fences | **Dogfooding found 17 real defects in our own docs** — README links baked to absolute `/Users/...` machine paths, references to nonexistent config filenames, and `make fmt` documented nowhere. All fixed, none waived. ## Verification 774 tests / 9 packages, go vet, gofmt, golangci-lint 0 issues, cache-cleared self-scan 0 fail with the legibility gate active. Docs fully updated: Agent Context section rewritten (new rules, recalibrated formulas, threshold/history semantics), architecture doc gained a corpus paragraph, and three new gotchas captured in .claude/knowledge/. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Re-lands PR #44, which was stacked on feat/performance-category and merged into that branch instead of main. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
alxxjohn
added a commit
that referenced
this pull request
Jul 16, 2026
🤖 I have created a release *beep* *boop* --- ## [1.0.0](v0.8.3...v1.0.0) (2026-07-16) ### ⚠ BREAKING CHANGES * promote performance rules to their own opt-in check section ([#41](#41)) * the performance rules' ids renamed from quality.* to performance.* (quality.n-plus-one-query -> performance.n-plus-one-query, quality.go.alloc-in-loop -> performance.go.alloc-in-loop, quality.sync-io-in-request-path -> performance.sync-io-in-request-path, quality.unbounded-goroutines-in-loop -> performance.unbounded-goroutines-in-loop, plus the typescript/javascript mirrors and quality.python.sync-io-in-async). Their detect_* toggles moved from quality_rules to performance_rules, and the section is opt-in: set checks.performance: true to keep running these rules, and update any waivers or baselines that reference the old ids. ### Features * 30% faster scans, enforceable AI-readiness score, and doc-truth rules ([#44](#44)) ([718dd08](718dd08)) * **context:** add AI-and-human-readiness rules and broaden README drift ([6caac9a](6caac9a)) * **context:** AI-readiness gate, doc-truth rules, and 30% faster scans ([1f4f130](1f4f130)) * **context:** AI-readiness gate, doc-truth rules, and 30% faster scans (re-land [#44](#44)) ([#46](#46)) ([75b3f02](75b3f02)) * **context:** enforceable legibility threshold and recalibrated score components ([604dd52](604dd52)) * **context:** persist repo_legibility score history with report flag ([e54f643](e54f643)) * **parsers:** wire the Python tree-sitter grammar and upgrade Python N+1 detection ([07a0b24](07a0b24)) * **performance:** add AI-assisted semantic performance lens ([eabd7fe](eabd7fe)) * **performance:** add diff-only loop-nesting complexity regression rule ([2e8bcef](2e8bcef)) * **performance:** add framework-aware rules for Django, SQLAlchemy, React, and Express ([b49ce7b](b49ce7b)) * **performance:** add loop-hygiene, concurrency, and memory-pressure rules ([54bfca9](54bfca9)) * **performance:** add measured budgets and benchmark regression gates ([2c5e4ba](2c5e4ba)) * **performance:** publish a performance_score artifact with history and report flag ([5c5a738](5c5a738)) * promote performance rules to their own opt-in check section ([ede8b37](ede8b37)) * promote performance rules to their own opt-in check section ([#41](#41)) ([81a575b](81a575b)) * suggest enabling the performance section in scan output ([81d9d46](81d9d46)) ### Performance Improvements * **quality:** hash clone tokens once and roll the window hash ([bbf5b69](bbf5b69)) * **quality:** route AI check reads through the shared scan corpus ([b271cfb](b271cfb)) * **runner:** count lines by scanning bytes instead of allocating ([17a4593](17a4593)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Re-lands #44 against main. #44 was stacked on
feat/performance-categoryand its merge landed on that feature branch instead of main, so none of its changes made it into main or the 1.0.0 release PR (#45). This PR carries exactly that delta (63 files; full 774-test suite green; content identical to the reviewed #44 state).See #44 for the full description and review discussion. Highlights:
repo_legibilitywarn/fail thresholds, history +report -legibility-history, honest component calibration (dogfooded at warn-threshold 85)context.undocumented-commands,context.oversized-agent-doc,context.doc-link-rot, README drift parity; dogfooding fixed 17 real defects in our own docsMerging this will update release PR #45 so 1.0.0 includes these changes — merge this before accepting the release PR.
🤖 Generated with Claude Code