Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 30 additions & 30 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,44 +7,44 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added — Deeper, token-economical cross-file review context
## [0.7.0] - 2026-07-16

- **Inbound caller (blast-radius) resolution.** Reviews now also resolve **who calls the changed code**, not just what the changed code calls. A changed function/type signature surfaces its call-sites across the repo so breaking changes can be flagged. Gated by new `review.context_chain.include_callers` (default `true`); uses gitignore-aware walking and is bounded (≤400 files, ≤3 call-sites/symbol), injecting only the call line + 1 line of context to stay cheap.
- **Definition extraction** (`extract_definitions_from_diff`) for Rust/Python/JS-TS/Go/Java-Kotlin — detects functions/types *declared* in the diff, which feed caller resolution.
- **Signature-only budget fallback.** When the token budget can't fit a full function/type body, a thin signature slice is injected instead of skipping the entry entirely (~3-5× more symbols under the same budget).
### Highlights

### Fixed — Cross-file context correctness & defaults
- **Deeper, token-economical cross-file review.** Reviews now resolve **who calls the changed code** (inbound / blast-radius), not just what the changed code calls — so breaking signature/type changes can be flagged. Bounded scanning + thin slices + a signature-only budget fallback keep token cost low.
- **Config is now validated at load time.** Out-of-range values (e.g. `temperature: 5`) and misspelled keys (`quailty_gate`) fail loudly instead of being silently ignored.
- **Markdown false positives suppressed.** Findings inside fenced code blocks (a `git push` in a fenced `bash` block flagged as SQL injection) are now dropped across all finding sources.
- **Performance, security, and correctness fixes** across the scan/review pipeline (10 perf bottlenecks, 2 CVE bumps, 8+ silent-corruption and best-practice bugs).

- **`review.rs` passed the wrong ignore list** to the context resolver (`ignore.rules` — finding-type strings — instead of `ignore.files` globs). The resolver could inject code from `node_modules/`/`target/`. Now uses `ignore.files`.
- **`context_chain.max_context_tokens` default raised 3000 → 5000**, and the resolver never scans gitignored build artifacts (caller scan uses the `ignore` crate).

### Fixed — Minor Best-Practice Items (#334)

- **Test-file detection no longer over-matches (#87).** `is_test_file` now uses path-segment awareness, so common words like `latest`, `aspect`, `attestation`, `protest` are no longer mistaken for test files.
- **Directory glob excludes are segment-boundary aware (#66).** A `src/` exclude no longer catches `mysrc/` or `docs/src-guide/`.
- **`max_findings` cutoff keeps the worst findings (#88).** Findings are sorted by severity before capping (Critical-first), so truncation drops the least important, not the highest severity.
- **Debt snapshot save failures are surfaced (#30).** Write failures emit a `warn!`-level log instead of being swallowed silently.
- **Token estimation no longer returns 0 for short content (#68).** Non-empty content estimates at least 1 token (was 0 under integer division).
- **Java wildcard imports preserved (#72).** `import com.example.*` keeps the `*` instead of truncating to `com.example`.
- **Rust module declarations extracted (#73).** `mod foo;` is now treated as a dependency symbol, matching the documented behavior.
- **DB size uses the real SQLite page size (#23).** `index_stats` queries `PRAGMA page_size` instead of assuming 4096 bytes.
- **`issue_type` serializes consistently (#48).** Serialized as `issue_type` (matching the field name); `type` kept as a deserialize alias.
- **Severity parsing avoids an allocation (#10).** `from_str_lossy` uses `eq_ignore_ascii_case`.

### Fixed — Markdown False Positives (#329)
### Added

- **Findings inside Markdown fenced code blocks are now suppressed.** Code blocks (\`\`\` / `~~~`) in `.md`/`.mdx`/`.markdown` files are documentation examples, not executable code. A `git push` inside a ` ```bash ` block is no longer flagged as SQL injection. The filter covers all finding sources (security/secrets/rules scanners + LLM) and uses full hunk context (Add + Context lines) to track fence state, so it works even when only the code-block body was edited.
- **Inbound caller (blast-radius) resolution.** A new context-chain phase resolves call-sites of functions/types defined or modified in the diff, so breaking changes to their signatures surface their consumers. Gated by new `review.context_chain.include_callers` (default `true`); uses gitignore-aware walking and is bounded (≤400 files, ≤3 call-sites/symbol), injecting only the call line + 1 line of context. New `ContextPriority::CallerSite`.
- **Definition extraction** (`extract_definitions_from_diff`) for Rust/Python/JS-TS/Go/Java-Kotlin — detects functions/types *declared* in the diff, feeding caller resolution. Rust `mod foo;` and Java `import com.example.*` wildcards are now extracted correctly (#73, #72).
- **Signature-only budget fallback.** When the token budget can't fit a full function/type body, a thin signature slice (up to `{`) is injected instead of skipping the entry entirely (~3–5× more symbols under the same budget).
- **`Config::validate()`** (#94) — rejects out-of-range/unsupported values at load: `temperature` (0.0–2.0), `max_tokens`/`timeout` (≥1), `max_tokens_param`, `response_format`, `output.format`, `hook.mode`/`on_violation`/`min_severity`, and `provider.base_url` scheme. Multiple errors are aggregated into one message.
- **`Profile::validate()`** (#81) — focus `weight` must be 1–10, and `action`/`tone`/`detail_level` must be recognized values.
- **`deny_unknown_fields`** on all config sections (#80) — misspelled YAML keys are rejected at parse time.

### Fixed — Config Validation & Best Practices (#334)
### Changed

- **Quality gate no longer fails when disabled (#58).** `evaluate()` forced `GateResult::Pass` when `enabled: false`; it now short-circuits before applying thresholds so a disabled gate never blocks a merge.
- **Category actions are now validated enums (#57).** `quality_gate.categories.*.action` accepted any string, so a typo like `blok` silently became blocking. It is now a case-insensitive `CategoryAction` enum (`block`/`warn`/`ignore`); unknown values fail loudly at config load.
- **Config values are validated (#94).** `Config::validate()` now rejects out-of-range/unsupported values at load time: `temperature` (0.0–2.0), `max_tokens`/`timeout` (≥1), `max_tokens_param`, `response_format`, `output.format`, `hook.mode`/`on_violation`/`min_severity`, and `provider.base_url` scheme. Multiple errors are aggregated into one message.
- **Profile values are validated (#81).** Focus area `weight` must be 1–10, and `action`/`tone`/`detail_level` must be recognized values; all built-in profiles pass.
- **`CategoryAction` enum** (#57) — `quality_gate.categories.*.action` is now a case-insensitive enum (`block`/`warn`/`ignore`); a typo like `blok` fails loudly at config load instead of silently becoming blocking.
- **Disabled quality gate never fails** (#58) — `evaluate()` forces `Pass` when `enabled: false`.
- **`context_chain.max_context_tokens` default** raised 3000 → **5000**.
- **`issue_type`** serializes consistently as `issue_type` (#48); `type` retained as a deserialize alias.
- **`Severity::from_str_lossy`** uses `eq_ignore_ascii_case` (no allocation) (#10).

### Added — Config Safety
### Fixed

- **`deny_unknown_fields` on all config sections (#80).** Misspelled YAML keys (e.g. `quailty_gate`, `temprature`) are now rejected at parse time instead of being silently dropped.
- **Markdown fenced-code-block false positives** (#329) — findings inside fenced code blocks (triple-backtick / triple-tilde) in `.md`/`.mdx`/`.markdown` files are dropped across all finding sources (security/secrets/rules scanners + LLM). Fence state is tracked across full hunk context, so it works even when only the block body was edited.
- **Cross-file resolver used the wrong ignore list** — `review.rs` passed `ignore.rules` (finding-type strings) instead of `ignore.files` (`target/**`, `node_modules/**`); the resolver could inject build-artifact code. Now uses `ignore.files`.
- **Test-file detection over-match** (#87) — `is_test_file` is path-segment aware; `latest`, `aspect`, `attestation` are no longer mistaken for test files.
- **Directory glob excludes over-permissive** (#66) — `src/` matches only at segment boundaries (`mysrc/` no longer caught).
- **Token estimation** (#68) — non-empty content returns ≥1 token (was 0 under integer division).
- **DB size** (#23) — `index_stats` queries `PRAGMA page_size` instead of assuming 4096 bytes.
- **Project-sync workflow** — a merged PR referencing issues via `Refs #N` (not `Closes #N`) no longer fails the `sync` check.
- **10 scan/review performance bottlenecks** (#335) — precompiled regex, batched DB queries, early cutoffs, file-content cache, single reused Tokio runtime, single-transaction prune, etc.
- **Security:** bumped `anyhow` 1.0.102 → 1.0.103 (RUSTSEC-2026-0190) and `crossbeam-epoch` 0.9.18 → 0.9.20 (RUSTSEC-2026-0204).
- Various silent-data-corruption bugs resolved (#333): severity sort, security-findings fallback, deterministic debt-snapshot hashing, debt-trend math, config precedence, `context_chain` merge, and hook-install composition.

## [0.6.2] - 2026-06-21

Expand Down
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "cora-cli"
version = "0.6.2"
version = "0.7.0"
edition = "2024"
description = "CLI-first AI code review — BYOK, diff/scan/branch, pre-commit hooks"
license = "MIT"
Expand Down
53 changes: 26 additions & 27 deletions docs/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added — Deeper cross-file review context (token-economical)
## [0.7.0] - 2026-07-16

- **Caller/blast-radius resolution**: reviews now resolve who *calls* changed code (not just what changed code calls). `review.context_chain.include_callers` (default `true`); bounded scan, thin slices.
- **Definition extraction** (Rust/Python/JS-TS/Go/Java-Kotlin) feeds caller resolution.
- **Signature-only budget fallback**: injects a signature slice when the full body won't fit.
### Highlights

### Fixed

- `review.rs` passed `ignore.rules` instead of `ignore.files` to the context resolver (could inject `node_modules`/`target` code).
- `context_chain.max_context_tokens` default 3000 → 5000.
- **Deeper, token-economical cross-file review** — reviews now resolve **who calls changed code** (blast radius), not just what changed code calls. Bounded scanning + thin slices + signature-only fallback keep token cost low.
- **Config validation at load time** — out-of-range values and misspelled keys fail loudly instead of being silently ignored.
- **Markdown false positives suppressed** — findings inside fenced code blocks dropped across all finding sources.
- **Perf + security + correctness fixes** across the pipeline (10 perf bottlenecks, 2 CVE bumps, silent-corruption & best-practice bugs).

### Fixed — Minor Best-Practice Items (#334)
### Added

- **#87** test-file detection uses path-segment awareness (no more `latest`/`aspect`/`attestation` false matches).
- **#66** directory glob excludes are segment-boundary aware (`src/` ≠ `mysrc/`).
- **#88** `max_findings` cutoff sorts severity-first so truncation drops least-important findings.
- **#30** debt snapshot save failures emit `warn!`.
- **#68** token estimation returns ≥1 for non-empty content.
- **#72** Java `import com.example.*` keeps the wildcard.
- **#73** Rust `mod foo;` extracted as a dependency.
- **#23** DB size queries `PRAGMA page_size` instead of assuming 4096.
- **#48** `issue_type` serializes consistently; `type` kept as deserialize alias.
- **#10** severity parsing avoids an allocation.
- **Caller (blast-radius) resolution** — `review.context_chain.include_callers` (default `true`); gitignore-aware, bounded ≤400 files / ≤3 call-sites per symbol. New `ContextPriority::CallerSite`.
- **Definition extraction** (Rust/Python/JS-TS/Go/Java-Kotlin) feeds caller resolution; Rust `mod foo;` and Java `import com.example.*` now extracted (#73, #72).
- **Signature-only budget fallback** — injects a signature slice when the full body won't fit.
- **`Config::validate()`** (#94) + **`Profile::validate()`** (#81) — reject out-of-range/unsupported values at load.
- **`deny_unknown_fields`** on all config sections (#80).

### Fixed — Markdown False Positives (#329)
### Changed

- **Findings inside Markdown fenced code blocks are now suppressed.** A `git push` inside a ` ```bash ` block in an `.md` file is no longer flagged as SQL injection. Covers all finding sources (security/secrets/rules + LLM); tracks fence state across full hunk context (Add + Context lines).
- **`CategoryAction` enum** (#57) — case-insensitive `block`/`warn`/`ignore`; typos fail loudly.
- **Disabled quality gate never fails** (#58).
- **`context_chain.max_context_tokens`** default 3000 → **5000**.
- **`issue_type`** serializes consistently (#48); `type` kept as deserialize alias.
- **`Severity::from_str_lossy`** avoids an allocation (#10).

### Fixed — Config Validation & Best Practices (#334)
### Fixed

- **Quality gate no longer fails when disabled (#58).** `evaluate()` now forces `GateResult::Pass` when `enabled: false` instead of applying thresholds.
- **Category actions are now validated enums (#57).** `quality_gate.categories.*.action` is a case-insensitive `CategoryAction` enum (`block`/`warn`/`ignore`); unknown values fail loudly at config load instead of silently becoming blocking.
- **Config values are validated (#94).** `Config::validate()` rejects out-of-range/unsupported values at load: `temperature` (0.0–2.0), `max_tokens`/`timeout` (≥1), `max_tokens_param`, `response_format`, `output.format`, `hook.*`, and `provider.base_url`.
- **Profile values are validated (#81).** Focus `weight` must be 1–10; `action`/`tone`/`detail_level` must be recognized.
- **`deny_unknown_fields` on all config sections (#80).** Misspelled YAML keys are rejected at parse time.
- **Markdown fenced-code-block false positives** (#329) dropped across all finding sources.
- **Cross-file resolver** now uses `ignore.files` (not `ignore.rules`) — no longer injects `node_modules`/`target` code.
- **Test-file detection** (#87) and **glob excludes** (#66) no longer over-match (`latest`/`aspect`/`mysrc/`).
- **Token estimation** (#68), **DB size** (#23).
- **Project-sync workflow** no longer fails on merged PRs using `Refs #N`.
- **10 performance bottlenecks** (#335); **silent data-corruption bugs** (#333).
- **Security:** `anyhow` 1.0.102 → 1.0.103, `crossbeam-epoch` 0.9.18 → 0.9.20.

## [0.6.2] - 2026-06-21

Expand Down
33 changes: 33 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ Settings are resolved in this order (highest priority first):
5. **Auto-detect** — Provider-specific env vars (`OPENAI_API_KEY`, `ZAI_API_KEY`, etc.)
6. **Built-in defaults** — Sensible defaults for all settings

After all sources are merged, **config values are validated at load time**: out-of-range values (e.g. `temperature: 5`), unsupported formats (`output.format: prety`), and misspelled keys (`quailty_gate`, `temprature`) fail loudly with a clear message instead of being silently ignored. This applies to `temperature` (0.0–2.0), `max_tokens`/`timeout` (≥1), `max_tokens_param`, `response_format`, `output.format`, `hook.mode`/`on_violation`/`min_severity`, `provider.base_url`, and profile `weight`/`action`/`tone`/`detail_level`.

### API Key Resolution

1. `--api-key` flag (one-shot)
Expand Down Expand Up @@ -152,6 +154,35 @@ cora uses two mechanisms to prevent the LLM from fabricating findings:
- **File path injection** — Actual file paths are embedded in the prompt, anchoring the LLM to real files in the diff.
- **Post-parse filtering** — After parsing, any reported file paths or line numbers that don't exist in the actual diff are discarded.

## Cross-File Review Context

To review a change accurately, cora injects **cross-file context** alongside the diff — it doesn't review the diff in isolation. This is deterministic (no extra LLM calls) and bounded by a token budget so cost stays predictable.

Two axes are resolved:

- **Outbound** — what the changed code *calls/imports* (function/type definitions the diff references).
- **Inbound (blast radius)** — *who calls the changed code*. If a PR modifies a function signature or type, its call-sites across the repo are surfaced so breaking changes can be flagged.

When the budget can't fit a full definition, a thin **signature slice** is injected instead of skipping it, so more symbols fit under the same budget.

```yaml
review:
context_chain:
enabled: true # master switch for cross-file context
max_context_tokens: 5000 # budget (~4 chars/token) for injected context
follow_depth: 1 # outbound resolution depth (1 = direct refs only)
include_tests: true # resolve test files via naming convention
include_callers: true # resolve callers of changed code (blast radius)
```

| Field | Default | Notes |
|-------|---------|-------|
| `enabled` | `true` | Disable to review the diff only. |
| `max_context_tokens` | `5000` | Approx. 20 KB of code injected. |
| `follow_depth` | `1` | Outbound recursion depth (`1` = direct references). |
| `include_tests` | `true` | Map changed source to its test files. |
| `include_callers` | `true` | Inbound caller resolution. Scans source files (gitignore-aware — `target/`, `node_modules/` are never scanned), bounded to ≤400 files and ≤3 call-sites per symbol. |

## Quality Gate

Quality gate evaluates review findings against configurable thresholds to produce a **PASS/FAIL** result. This is useful for CI enforcement — block merges when code quality drops below your standards.
Expand Down Expand Up @@ -190,6 +221,8 @@ quality_gate:
- **block** — exceed threshold = gate FAIL (exit code 2)
- **warn** — report but don't fail gate
- **ignore** — skip entirely

Actions are validated enums — case-insensitive (`block`, `Block`, `BLOCK` all work), and an unknown value (e.g. `blok`) fails at config load instead of silently becoming blocking. A disabled gate (`enabled: false`) never fails.
4. Overall gate status: **PASSED** or **FAILED**

### CLI Output
Expand Down
Loading