Skip to content

Review inbox: 'kai review analyze' headless Finding emitter#26

Open
jschatz1 wants to merge 9 commits into
mainfrom
review-inbox-evidence-layer
Open

Review inbox: 'kai review analyze' headless Finding emitter#26
jschatz1 wants to merge 9 commits into
mainfrom
review-inbox-evidence-layer

Conversation

@jschatz1

@jschatz1 jschatz1 commented Jul 1, 2026

Copy link
Copy Markdown
Member

CLI half of the agent-review inbox. New command kai review analyze <review-id> --format json assembles the structured Finding for an agent change and prints it as JSON — the headless surface both the TUI and the server web UI render.

Serializes existing engine data (review state → verdict, changeset intent + optional contract enrichment → intent-vs-code, semanticdiff → per-file patch with +/- counts) and drives the new evidence layer: transitive blast (safetygate.Reachback), grounded callers() claims, and should-touch (shouldtouch.Detect candidates + an LLM judge gated on ai.IsConfigured, so it emits nothing rather than assert an unverified candidate).

Depends on kai-engine#4 (finding/reachback/shouldtouch packages).

jschatz1 added 9 commits July 1, 2026 15:23
New command: kai review analyze <review-id> --format json — assembles the
structured Finding for an agent change and prints it as JSON. This is the
headless surface both the TUI and the server web UI render.

Serializes existing engine data (review.State -> verdict, changeset intent +
optional contract enrichment -> intent-vs-code, semanticdiff -> per-file patch
with +/- counts) and drives the new evidence layer: transitive blast radius
(safetygate.Reachback), grounded callers() claims, and should-touch (graph
candidates from shouldtouch.Detect + an LLM judge gated on ai.IsConfigured,
so it emits nothing rather than assert an unverified candidate).
…aw ai.Client

The should-touch LLM judge was using the legacy ai.Client (hardcoded
ANTHROPIC_API_KEY + api.anthropic.com). Switch it to the same provider path the
rest of the engine uses — provider.FromEnv + provider.New via buildGateProvider —
so it goes through kailab -> OpenRouter when logged in, with ANTHROPIC_API_KEY only
as an offline fallback. Degrades to no should-touch findings when no provider is
available, unchanged.
CI review pods had no image with the kai CLI (registry has only kailab-*
images; ubuntu:22.04 default has no kai/git/jq). Add a kai-ci image: builds
the kai CLI from the local workspace (kai-cli+kai-core+kai-engine via go.work,
because kai review analyze needs kai-engine packages not in the published tag),
plus git/jq/curl/bash. CGO on for tree-sitter, amd64 builder. build.sh logs in
via kailab-registry-credentials and pushes registry.kaicontext.com/kai-ci.
Make the image actually build (verified: 208MB, kai 0.34.3, git/jq/curl/bash):
- Resolve local modules via replace directives, not go.work (the go.work +
  dockerignore whitelist stripped kai-engine's contents in-container, so the
  build tried to fetch the private kai-engine v0.1.3 and failed).
- Cross-compile the CGO binary (tree-sitter) on a native BUILDPLATFORM builder
  instead of compiling under qemu (qemu emulation crashes the Go toolchain with
  'illegal instruction'). Needs the target cross-gcc AND libc6-dev-<arch>-cross
  headers (--no-install-recommends omits the latter).
- Retry the runtime apt layer (transient dpkg/perl flake under emulation).
- buildx --load/--push in build.sh.
hydrateSnapshot() materializes a snapshot's full graph on fetch-by-ref — the
snapshot node plus every file node, content blob, and HAS_FILE edge — so a clean
store can diff/analyze a snapshot resolved from a git.<sha> ref. Previously
fetch-by-ref inserted only the bare root node, leaving the snapshot undiffable
(kai diff saw no files; a review analyzed to files:0).

Push now propagates the git.<sha> bridge refs: the push allowlist includes the
git. prefix, and the 'Already up to date' gate is ref-aware (compares each ref
to its remote/<remote>/<name> tracking ref) instead of keying on snap.latest
alone — which had both misfired across remotes and never published a ref whose
target snapshot already existed.

Together these make the data plane SHA-addressable, so a server-side review can
resolve a PR's base/head SHA to snapshots and diff them without re-capture.
runReviewAnalyze is now a thin wrapper: open the store, build the should-touch
judge from client config, call reviewanalyze.Analyze, print JSON. The analysis
logic moved to github.com/kaicontext/kai-engine/reviewanalyze.
Thin wrapper over reviewanalyze.AnalyzeSnapshots — emits the Finding JSON for an
arbitrary base->head snapshot pair with no persisted review. Parity with the
server-side entry point and useful for testing.
kai review-commit built its diff from `git --numstat` (line counts only),
so the finding's diff.files carried Added/Removed but no Patch — the
findings inbox Code tab rendered file headers with an empty body. Add
rcCommitPatches(): run the real `git diff`/`git show`, split per file,
strip file headers, keep hunk headers + +/-/context body, and attach as
DiffFile.Patch keyed by path. Blast radius is still computed elsewhere and
left as a separate follow-up.
Walk the captured graph from the changed files so the finding shows what the
change reaches, not just the diff. Non-fatal panel. Durably commits the wiring
the shipped kai-ci image already builds from the working tree.
@kaicontext

kaicontext Bot commented Jul 7, 2026

Copy link
Copy Markdown

🔍 Kai review

Kai is reviewing this pull request… the verification result will appear here shortly.

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