Skip to content

cli: drift status, shadow drift detail, per-query staleness + prime block (spec steps 1–3)#35

Open
jschatz1 wants to merge 3 commits into
mainfrom
drift/01-graph-refs-status
Open

cli: drift status, shadow drift detail, per-query staleness + prime block (spec steps 1–3)#35
jschatz1 wants to merge 3 commits into
mainfrom
drift/01-graph-refs-status

Conversation

@jschatz1

@jschatz1 jschatz1 commented Jul 10, 2026

Copy link
Copy Markdown
Member

Steps 1–3 of the graph staleness / git drift spec. Companion to kaicontext/kai-engine#23, which this depends on.

kai status (step 1)

Graph:      2 commits behind git HEAD (graph 956aa12d11ce · git 2c6ddf3511cb · oldest unprocessed 2h ago)
            Run 'kai capture' (or 'kai import' for many commits) to catch up.

One line per relationship with an action hint; --json gains the drift block. Merge-base/rev-list only on the status path.

kai shadow drift (step 2)

No-flag default is the drift detail view: per-commit files touched, import-target annotations ([adds imports into pkg/foo]), the superseded leg on divergence, manifest state. Explicit --snap/--git-ref keep the legacy snapshot comparison. Pin sites (bridge import, kai import) sync the manifest so catch-up shrinks it.

Per-query staleness (step 3)

kai query callers|dependents|impact, kai test affected, kai blame:

  • Answer neighborhood (every file in the answer + the target) classified before printing.
  • stale-refused (orphaned graph, or ≥ staleness.refuse_after_intersecting intersecting commits) suppresses the answer and errors with the reason. Default: never refuse.
  • Otherwise the answer prints, then one stderr line (--quiet to suppress):
    staleness: stale-suspect — 1 unprocessed commit intersects this query (bf5e3fd6ee20); run 'kai capture' to catch up
    
    fresh stays silent.
  • --strict (or staleness.strict) makes stale-suspect exit 75 (the CI tripwire convention). Default exit stays 0 so existing scripts don't break.
  • kai blame --json embeds the full staleness block (existing shapes preserved).
  • kai prime appends a ## Staleness section to injected context — outside the char budget so truncation can't drop it — listing intersecting commits and steering agents to prefer current file contents.

New config slice: staleness.strict, staleness.refuse_after_intersecting (zero values = annotate, never block).

Verified end-to-end

Scratch repo: synced query silent → drift commit touching pkg/foo → same query annotates stale-suspect with the commit, unrelated query stale-valid; --strict exits 75; threshold config refuses before printing; --quiet suppresses; prime carries the block; blame JSON embeds it. All suites green (engine drift/status, cmd/kai, internal/config, vet, gofmt).

Note for CI

Builds against local engine via go.work; proxy-resolved CI needs an engine tag containing kaicontext/kai-engine#23.

🤖 Generated with Claude Code

kai status gains a Graph: section (human) and a drift block (--json)
classifying the semantic graph against git HEAD: synced, graph-behind
(with unprocessed count and oldest-commit age), graph-ahead, diverged
(both legs), orphaned, or unpinned — each with an action hint.
Classification is merge-base/rev-list only, no semantic work on the
status path.

Pin sites: the post-commit bridge import records each processed commit
in .kai/graph-refs.json, and kai import pins every replayed commit
(batched, one write), attributing the branch ref only when the branch
tip is the last imported commit.
@kaicontext

kaicontext Bot commented Jul 10, 2026

Copy link
Copy Markdown

🔍 Kai review

Warning

Needs a look — intent partially matches, 2 flags.

  • 🟡 Intent partially matches — semantic match unconfirmed
  • ✅ No coverage gaps
  • ⚠️ [correctness] cmd/kai/status_drift.go:115 — `annotateStaleness` calls `os.Exit(exitStaleSuspect)` which terminates immediately without running any `defer`red cleanup in the callin…
  • ⚠️ [correctness] cmd/kai/main.go:12950 — `runStatus` is changed to call `status.WriteOutputFull` (adding a `driftReport` arg) but this function does not appear to be defined anywhere…

+617 −14 · 4 files · reaches 15

View finding → · Awaiting your verdict — Kai never approves its own finding.

kai shadow drift (no flags) now shows the git-drift detail: the
graph↔git relationship, each unprocessed commit with files touched and
import targets, the superseded leg of a divergence, and the manifest
location. Explicit --snap/--git-ref keep the legacy snapshot-content
comparison.

The drift manifest is synced after the bridge-import and kai-import
pin sites, so catch-up shrinks it and new drift extends it without
per-query git work.
@jschatz1 jschatz1 changed the title cli: report graph↔git drift in kai status; pin graph_refs on import cli: kai status drift reporting + kai shadow drift detail view (spec steps 1–2) Jul 10, 2026
…ness block

Query commands (query callers/dependents/impact, test affected, blame)
now classify their answer against graph drift before printing: an
orphaned graph or intersection above staleness.refuse_after_intersecting
refuses with the reason instead of answering; otherwise the answer
prints with a one-line stale-valid/stale-suspect annotation on stderr
(suppressible with --quiet). fresh stays silent.

--strict (or staleness.strict in config) makes stale-suspect exit 75,
following the CI tripwire convention. blame --json embeds the full
staleness block without changing existing output shapes.

kai prime appends a '## Staleness' section to injected context —
outside the char budget so truncation can't drop the trust signal —
listing intersecting commits and steering the agent to prefer current
file contents over stale symbol lists.
@jschatz1 jschatz1 changed the title cli: kai status drift reporting + kai shadow drift detail view (spec steps 1–2) cli: drift status, shadow drift detail, per-query staleness + prime block (spec steps 1–3) Jul 10, 2026
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