v2.21.0

Added

  • Each finding shows where its evidence came from (#1026). A short label and the confidence score follow the finding text, for example (corroborated by analyzer, confidence 88). The label is one of corroborated by analyzer, analyzer finding, judge kept, single agent, unverified, or single agent, not judged. It shows on GitHub, GitLab, and Bitbucket. It is display text only and does not change the approval decision. It is on by default. Set finding-badges: 'false' (AI_FINDING_BADGES=false on Bitbucket) to hide it. A finding that the judge did not rule on shows single agent, not judged.
  • Behavior change: new analyzer dep-exists flags a new dependency that its registry does not know (#1024). A model can invent a package name, and an attacker can register that name. The analyzer checks each dependency that a diff adds to package.json, requirements*.txt, Cargo.toml, composer.json, or Gemfile. An unknown name is a High finding. A version bump of an existing dependency is not looked up. An npm, PyPI, or crates.io package first published under 30 days ago is a Medium finding. It sends only the package name to the public registry. It does not check Go modules, and it skips an ecosystem when the repository sets a private registry. It is on by default. Turn it off with exclude-analyzers: dep-exists. A High finding makes the review request changes, so a repository can see a pull request blocked by a dependency that is real but private. The analyzer reads only files in the repository, so it cannot see a private registry that is set in CI settings or a user-level config. It also asks the public registry about a private scoped npm package, or about a monorepo package that another package lists by plain version (workspace:, file: and link: specs are skipped). If that affects you, turn the analyzer off with exclude-analyzers: dep-exists, or set the registry in a file in the repository. When registry lookups fail, the run logs a warning, and the dependencies that were not checked add no finding.
  • The review comment says what the review did not look at (#1023). A short Not reviewed: note lists the exclude-patterns you set, the agents that did not run, and whether the review is incremental. The note is empty when nothing was left out.
  • The finding judge can read the code a finding cites, and the repository has a measured comparison (#1025). The production review does not use this yet, because the first measurement did not meet the bar. The shipped judge is unchanged.
  • Claude Haiku 5.5 has a pricing row, with a second set of rates for long prompts (#1012). Haiku 5.5 is not a default model.
  • The consistency harness has a hard spend cap (#1014). It also refuses to start without --yes. This changes the test tools only, not the action.

Changed

  • Behavior change: the pre-flight cost estimate is about 2.2 times higher for the same diff (#1013). The estimate now counts input tokens from a measured ratio of 1.8 characters per token. The old estimate counted only 48% to 81% of the real tokens. This affects AI_MAX_COST_USD (off by default), the COST_ESTIMATE log line, and the cost-ceiling skip. A repository that sets a ceiling can see a review skipped that passed before. Raise the ceiling, or compare it with the logged estimate.
  • The published docs are rewritten to ASD-STE100 and checked against the code (#1021, #1028). Em dashes are removed. Statements that did not match the code are fixed.
  • Dependency updates. The trufflehog image is 3.99.2, the ruff image is 0.17.0, and docker/dockerfile is 1.28. The artifact and setup-ruby actions are newer. The ruff analyzer can report findings that the old 0.16.10 did not.
  • The engine pins the git diff format (#1032). A non-ASCII directory name or diff.mnemonicPrefix=true in a user’s git config no longer makes dep-exists skip a manifest. A path with a control character is never decoded, and dep-exists warns when it cannot read a path.
  • The policy paths globs now match a non-ASCII path. Git used to write such a path in quotes, so a route like docs/** did not match it.

Fixed

  • The Sonnet 5.5 cache-read price was twice the published price (#1012). The token table and the compact usage line counted Sonnet 5.5 cache hits at $0.20 per million tokens. The correct price is $0.10.
  • A model id with a digit glued to opus-5 is no longer priced or handled as Opus 5 (#1012). A future claude-opus-59 would have used the Opus 5 rates and settings.
  • Claude Haiku 5.5 no longer fails with HTTP 400, and its thinking is capped (#1015). The action omits temperature for Haiku 5.5 and caps effort at low.
  • The rescan and review-full commands read their own fail-on-findings variable. The shipped workflows read AI_REVIEW_SLASH_FAIL_ON_FINDINGS (default false) on that path. They read AI_REVIEW_FAIL_ON_FINDINGS before, so a repository that set it to true for the review job also made a rescan that found something fail the run. If you want the gate on rescans, set the new variable to true. The example pipelines also state the correct AI_CONTEXT_ENRICHMENT default and learning-loop scope.

Not verified

  • Haiku 5.5 is not a default model. A model-change verification run is still needed before it can become one.
  • The code-aware judge is not part of the production review.

See CHANGELOG.md for full technical detail.