Mosaic one model, many lenses

ADR 0035 — Latest-changes analysis for git knowledge sources (K11)

  • Status: accepted
  • Date: 2026-10-04
  • Slice: P35 (knowledge roadmap K11)

Context

The Eezy-parity feature set (the EE AI assistant with MCP support, git repository indexing, source-code symbol recognition, source analysis, repo statistics, MCP tools) is already landed in Mosaic across the K1–K10 knowledge series and P29 (Mosaic Aide). The one remaining capability the feature list names is analyzing the latest changes: the K2 git facts are static (branch, commit count, last short-sha + date, contributor count). Nothing exposes the recent commit history, the files each commit touched, or the diff magnitude — and the assistant (Aide) cannot answer "what changed recently in this repo?" because no change data is indexed.

The knowledge engine already has the pieces this needs: the git CLI seam (K2 — fail-soft, pure parse layer + thin command wrapper), the ingest pipeline (K1/ADR 0019 delta with per-source manifests), the per-source stats row (which already carries the live git facts), and the MCP tool conventions (K1–K6).

Decision

K11 = latest-changes analysis, as a strategy layer (default on) on every git work-tree source — declared sources[].git, a plain path that happens to be a work tree, or a runtime-added git source (K9):

  1. Engine (mosaic-knowledge):

    • git.rs gains ChangedFile { path, status, added, deleted }, RecentCommit { sha, date, author, subject, files }, a pure parse_recent_commits(name_status, numstat) -> Option<Vec<RecentCommit>> (two git log outputs joined by sha — --name-status for the A/M/D/R status, --numstat for the +/- magnitude; binary files are 0/0), and the fail-soft recent_commits(dir, limit) over the git CLI seam (None when not a work tree, git missing, or the log is empty). source_worktree(base, path, git_url) resolves a source's work tree WITHOUT cloning (git source → the K8 .gitcache/<label> when present; path source → the path when present) so surfaces can read history from disk live.
    • ingest.rs: Strategy.changes (default on — "with and without is a flag", like symbols/graph/git/books). For a work-tree source, ingest appends synthetic knowledge entries — one per recent commit (kind: git-commit, Locator::Inline { doc: "git-commit/<sha>" }, subject + author + date + per-file status and +/-) and one aggregate summary (kind: git-changes: the window's per-commit one-liners + the most-changed files) — under a dedicated doc slug <label>/git-log (upserted as a whole, so re-ingest replaces the window cleanly). The slug is tracked in SourceManifest.git_log so ADR 0014 removal deletes it with the source, and in IngestReport.changes so every stats surface carries it (the entries themselves are excluded from the LOC language mix, like code-summary).
    • The window is capped at CHANGES_LIMIT = 20 commits (deterministic; the cap lives in the engine so REST/MCP/stats agree).
  2. Surfaces (generated app lens):

    • The per-source stats row gains changes (the last ≤20 commits with their files) — flowing through GET /api/vectordb/{name}/stats, the knowledge_stats + repo_profile MCP tools, the /knowledge page, and mosaic knowledge-report with zero per-surface code.
    • GET /api/vectordb/{name}/changes?limit=N — LIVE (recomputed from the checkout on request, default 10, capped 50; not ingest-time data), reporting every git work-tree source of the collection (declared + runtime) with branch + commits. Fail-soft per source.
    • The recent_changes MCP tool (kb + optional limit) over the same live path — the agent-facing "analyze the latest changes".
    • The /knowledge page renders a "recent changes" table per KB from the stats row (no new fetch — the page already consumes the stats JSON).
  3. DSL: vector_dbs[].strategy.changes (default on) — the only new key. No new dependencies (the git CLI seam is unchanged), no new surfaces beyond the existing conventions.

Consequences

  • Aide (P29) can answer "what changed recently / who touched file X recently" by RAG over the indexed commit entries, and can call recent_changes for a live read — closing the Eezy code-intelligence feature list.
  • Shallow (--depth 1) remote clones (K8) have a one-commit history, so their changes window is that single commit — inherent to the K8 reuse-if-present clone contract (delete the cache to refresh; a full local path or bundle carries the full history).
  • The commit entries live in the index (embedded like any chunk); a reindex refreshes the window. The live /changes endpoint is always current.
  • Stats payloads grow by ≤20 small commit rows per git source (deterministic order, newest first).