Skip to content

chore(release): sync develop to main for v0.14.0 - #540

Merged
ajianaz merged 11 commits into
mainfrom
release/v0.14.0
Aug 28, 2026
Merged

chore(release): sync develop to main for v0.14.0#540
ajianaz merged 11 commits into
mainfrom
release/v0.14.0

Conversation

@ajianaz

@ajianaz ajianaz commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

What

Sync develop (via release/v0.14.0) to main to cut the v0.14.0 release: 5 bug fixes, 3 features, license change to Apache-2.0, and the v0.14.0 version bump/CHANGELOG promotion.

Highlights: empty LLM response recovery for reasoning models (#536), cross-crate method-call resolution in dead-code (#519) with public-API skip and --include-pub (#520), ignore.files honored by the index (#521), workspace-root resolution + honest incremental status (#522), enclosing control-flow scope in review prompts (#523).

Why

Tags must point at commits reachable from main (enforced by release.yml verify-main). Per the OSS release workflow, the develop → main sync is a PR with CI green and no admin bypass. Head branch uses the release/ prefix required by the branch-naming check.

Testing

CI runs on this PR; all checks must pass before merge. Contents already validated on develop (934 tests, fmt, clippy).

ajianaz and others added 11 commits August 25, 2026 12:25
…#526)

* feat(review): defend against adversarial source-code comments (ALIBI)

LLM reviewers are highly vulnerable to adversarial comments in the code
under review — fabricated tool-result claims ('sanitizer passed', 'already
validated') steer reviewer reasoning with >90% attack success across 125
real-world vulnerabilities (arXiv:2607.24964). Prompt-level 'ignore
comments' instructions are proven ineffective against adaptive attacks.

Architectural defenses (issue #524):
- comment_sanitizer module: strip comments from added diff lines
  (opt-in, review.sanitize-comments) with quote-aware marker detection
  (//, leading #, --, leading ;) — line numbers preserved
- Claim flagging (always on): added comments asserting verification or
  tool results are surfaced in review context as untrusted claims
- Deterministic scanners (rules, secrets, security) always run on the
  unsanitized diff
- SECURITY.md threat model section + configuration docs

Refs #524

* fix(review): run deterministic scanners on unsanitized diff; guard decrement ops

- Rules/secrets/security scanners now parse the original diff; only the
  LLM prompt receives the sanitized text (matches documented behavior)
- '--' marker requires preceding whitespace/line-start so C/C++
  decrement (i--) is not stripped as a comment
- Add regression test for decrement guard

Refs #524

---------

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
Empirical study (n=34, arXiv:2607.24601): full explanations maximize
perceived trust but NOT agreement — moderate explanations achieve the
highest developer agreement (89.22%). Instruct the reviewer to keep each
finding at severity + short reason (1-3 sentences) + code evidence,
avoiding long reasoning chains.

Refs #525

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…s) (#518)

Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…tal status (#528)

Running 'cora index' inside a workspace member crate resolved that crate's
plain Cargo.toml as the project root, while MCP sessions resolved the
workspace root — two different project rows, so index_status silently
reported total_symbols: 0 despite a populated DB (#522).

- resolve_project_root now prefers a Cargo.toml declaring [workspace],
  still honors .cora.yaml overrides first, and never climbs past a .git
  boundary so unrelated parent workspaces cannot hijack resolution
- incremental no-op re-runs now print 'Index up to date' plus stored
  totals instead of a confusing 'Indexed 0 symbols from 0 files'
- MCP index_status carries root-mismatch hint listing other roots with
  data when the resolved project has zero symbols

Regression tests: workspace-root preference, .cora.yaml precedence,
.git boundary stop, incremental count preservation, mismatch hint.

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
… default (#529)

* fix(index): resolve cross-crate method calls — cut dead-code false positives

Method calls inside Rust impl blocks were never walked for call edges
(only top-level free functions were), and method/qualified call targets
stored the raw AST text ('self.export_full', 'std::mem::drop') which can
never join against bare symbol names. Both made find_dead_code flag
symbols that are called across files/crates — 557 false positives on a
5-crate workspace (#519).

- impl-block function bodies now get extract_calls_from_node like free
  functions, recording their internal calls
- new normalize_callee_name reduces targets to the final name segment,
  so self.x(), manager.y() and std::mem::drop() all land on x/y/drop
- applies to every language routed through the shared walker

Regression tests: bare-name edge extraction (AST level) and a two-file
cross-crate dead-code integration mirroring the uteke case.

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>

* feat(dead-code): skip public API surface by default (+ --include-pub)

Majority of dead-code noise on library workspaces is pub API meant for
external consumption — 557 findings on uteke were mostly pub fns in
lib crates (#520). Missing internal callers does not make them dead.

- find_dead_code skips pub (incl. pub(crate)) and export items by
  default, keyed off captured signatures; DeadCodeOptions.include_pub_api
  opts back in
- new --include-pub CLI flag and include_pub_api MCP parameter
- cora dead-code now resolves the project root exactly like cora index,
  so queries hit the same workspace project after #522

On cora-code itself: 213 findings drop to 89 with the default filter.
Regression test covers pub-skip default, opt-in flag, private helper.

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>

---------

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…#530)

* feat(index): honor ignore.files — exclude matched files from indexing

skip patterns only invalidated fingerprints; the walker still indexed
every matching file, so dead-code and review's index scanners reported
~90 false positives per run from examples/ and extensions/ on uteke even
with .cora.yaml ignore.files configured (#521).

- index_project_with_id now excludes files matching skip patterns
  (should_skip_file glob matching) before reading them; new
  IndexStats.files_excluded reports the count
- cora index / watch merge review's ignore.files with index.skip_files,
  so one ignore list governs scan, index, and dead-code alike
- cora scan passes the merged list to its index-based findings stage too

Config-hash invalidation already wipes prior state when the pattern list
changes, so newly excluded files are purged on the next run. Regression
test covers exclusion plus purge-on-new-pattern.

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>

* chore(ci): re-trigger PR checks

Signed-off-by: Anaz S. Aji <aji.anaz@gmail.com>

---------

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
Signed-off-by: Anaz S. Aji <aji.anaz@gmail.com>
Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…#531)

Review run 2 on uteke#1084 flagged a false positive: the handler
validated author_type up front and set_author_type sat in a SHARED match
arm fed by two producers, but build_review_prompt shipped only raw diff
hunks — the LLM reconstructed branch structure from diff shape and got
it wrong (#523).

- new engine::enclosing module: for hunks whose add/context lines touch
  branching constructs, extract the enclosing function from the
  post-image file (brace-balance heuristic), clamped to 120 lines with
  head+tail windowing so shared arms stay visible without token blowup
- gated injection: new files, deletions, binaries, non-branching hunks,
  and unreadable files are skipped
- always-on prompt guardrail forbidding reachability claims unless
  verified against surrounding code (stage 2 of the issue proposal)
- stage 3 (call-graph reachability cross-check) intentionally left out

Regression tests: acceptance fixture mirrors the shared-arm case (both
producers visible in injected context); negative case without branching;
new-file skip; clamp bound; guardrail presence.

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
…brain output (#534)

Signed-off-by: Anaz S. Aji <aji.anaz@gmail.com>
…edefines the symbol (#535)

Signed-off-by: Anaz S. Aji <aji.anaz@gmail.com>
…ets (#537)

Reasoning models (e.g. GLM via Bifrost) can spend the entire
max_tokens budget on chain-of-thought and return HTTP 200 with
content: "" and finish_reason: "length". cora never read finish_reason
or reasoning_content and silently fed an empty string to the JSON
parser, surfacing the misleading 'EOF while parsing a value at line 1
column 0' — while the model's actual answer sat in the backend logs
(cosy#63) (#536).

Recovery now follows productivity over token frugality:
- response parsing captures finish_reason and reasoning_content
- empty content + finish_reason=length auto-retries with doubled
  budget (4096 -> ... -> 32768 ceiling) inside chat_completion
- last resort: JSON-looking reasoning text is salvaged as the raw
  response; the parse layer still validates it
- parse layer reports an explicit 'provider returned an EMPTY
  response' instead of serde EOF noise
- default max_tokens raised 4096 -> 8192 for reasoning headroom

Regression tests: budget escalation table, reasoning salvage
(string/parts/fenced/prose), explicit empty-raw error.

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
- Bump version 0.13.0 -> 0.14.0
- Promote CHANGELOG [Unreleased] to [0.14.0] (2026-08-28): empty LLM
  response recovery (#536), cross-crate dead-code fixes (#519), workspace
  root resolution (#522), ignore.files honored by index (#521), enclosing
  control-flow scope in review (#523), pub API skip + --include-pub
  (#520), relicensing to Apache-2.0
- docs: cli-reference gains dead-code --include-pub; AGENT.md test count
  and engine tree updated

Signed-off-by: ajianaz <ajianaz@users.noreply.github.com>
Co-authored-by: ajianaz <ajianaz@users.noreply.github.com>
@ajianaz
ajianaz merged commit 5eb37f7 into main Aug 28, 2026
29 of 30 checks passed
@ajianaz
ajianaz deleted the release/v0.14.0 branch August 28, 2026 03:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant