|
| 1 | +# Proposal: Smart `increment` / `reprocess` Mode Selection |
| 2 | + |
| 3 | +Status: **active — ready for planning**. |
| 4 | +Companion proposal: [`propose/active/TIER2-INCREMENTAL-REBUILD-PROPOSE.md`](TIER2-INCREMENTAL-REBUILD-PROPOSE.md) |
| 5 | +(Kuzu incremental rebuild implementation). |
| 6 | + |
| 7 | +## Goal |
| 8 | + |
| 9 | +Extend `java-codebase-rag increment` so it can choose incremental vs full |
| 10 | +rebuild automatically for both Lance and Kuzu, while staying safe for |
| 11 | +rename/delete/move and indexing-semantics changes. |
| 12 | + |
| 13 | +## Problem |
| 14 | + |
| 15 | +Current behavior: |
| 16 | + |
| 17 | +- `java-codebase-rag increment` updates Lance vectors incrementally |
| 18 | + (via CocoIndex) but prints a warning that the Kuzu graph is stale. |
| 19 | +- `java-codebase-rag reprocess` always does a full rebuild of both |
| 20 | + Lance and Kuzu. |
| 21 | + |
| 22 | +The `increment` command is correct for Lance but incomplete for Kuzu. |
| 23 | +The Kuzu incremental path is defined in |
| 24 | +[`TIER2-INCREMENTAL-REBUILD-PROPOSE.md`](TIER2-INCREMENTAL-REBUILD-PROPOSE.md). |
| 25 | +This proposal defines the decision engine that both commands use to |
| 26 | +determine when incremental is safe. |
| 27 | + |
| 28 | +## Proposed API Changes |
| 29 | + |
| 30 | +### CLI |
| 31 | + |
| 32 | +No new commands. Existing commands gain automatic mode selection: |
| 33 | + |
| 34 | +- `java-codebase-rag increment` — incremental Lance + Kuzu when safe, |
| 35 | + full Kuzu fallback when not. Lance is always incremental via CocoIndex. |
| 36 | +- `java-codebase-rag reprocess` — full rebuild of both Lance + Kuzu |
| 37 | + (unchanged). |
| 38 | +- `java-codebase-rag reprocess --graph-only` — full Kuzu rebuild only. |
| 39 | +- `java-codebase-rag reprocess --vectors-only` — full Lance rebuild only. |
| 40 | + |
| 41 | +### MCP tool (`refresh_code_index`) |
| 42 | + |
| 43 | +Add optional inputs: |
| 44 | + |
| 45 | +- `confirm: bool = false` (existing) |
| 46 | +- `mode: "auto" | "incremental" | "full" = "auto"` |
| 47 | +- `changed_paths: list[str] | null = null` |
| 48 | +- `git_ref_base: str = "HEAD"` |
| 49 | +- `reason: str | null = null` |
| 50 | + |
| 51 | +Backward compatibility: |
| 52 | + |
| 53 | +- Calls passing only `confirm=true` should still work. |
| 54 | +- Default mode is `auto` (safe-by-default decisioning). |
| 55 | + |
| 56 | +## Decision Engine (`mode=auto`) |
| 57 | + |
| 58 | +Returns two independent mode choices — Lance and Kuzu may use different |
| 59 | +modes: |
| 60 | + |
| 61 | +```python |
| 62 | +@dataclass |
| 63 | +class RefreshDecision: |
| 64 | + lance_mode: Literal["incremental", "full"] |
| 65 | + kuzu_mode: Literal["incremental", "full"] |
| 66 | + reasons: list[str] |
| 67 | + detected_changes: ChangeSet |
| 68 | +``` |
| 69 | + |
| 70 | +### Choose `full` for Kuzu when any of the following is true |
| 71 | + |
| 72 | +- At least one file is deleted. |
| 73 | +- At least one file is renamed or moved. |
| 74 | +- `.java-codebase-rag.yml` or `.lancedb-mcp.yml` changes. |
| 75 | +- Indexing pipeline/config files change (for example: |
| 76 | + `java_index_flow_lancedb.py`, `build_ast_graph.py`, |
| 77 | + `graph_enrich.py`, enrichment/chunking components). |
| 78 | +- `@interface` definitions changed (meta-annotation fanout risk). |
| 79 | +- `.deps.json` is missing, corrupt, or has wrong `ontology_version`. |
| 80 | +- Change detection fails or is ambiguous. |
| 81 | +- More than 50% of files are dirty (incremental would be slower). |
| 82 | + |
| 83 | +### Choose `full` for Lance when any of the following is true |
| 84 | + |
| 85 | +- Same config/indexing-pipeline triggers as Kuzu. |
| 86 | +- `.java-codebase-rag.yml` changes. |
| 87 | +- CocoIndex flow definition changes. |
| 88 | + |
| 89 | +### Choose `incremental` when all are true |
| 90 | + |
| 91 | +- Only in-place file content modifications/additions. |
| 92 | +- No rename/delete/move events. |
| 93 | +- No config/index/meta-annotation risk triggers. |
| 94 | +- `.deps.json` exists and is current (Kuzu incremental prerequisite). |
| 95 | + |
| 96 | +## Change Detection Strategy |
| 97 | + |
| 98 | +1. Prefer git diff status: |
| 99 | + - `git diff --name-status <base>...HEAD` |
| 100 | + - optionally include working tree status (`git diff --name-status` |
| 101 | + and `git diff --name-status --cached`) |
| 102 | +2. If git signal is unavailable, use `changed_paths` when supplied. |
| 103 | +3. If still uncertain, fall back to `full`. |
| 104 | + |
| 105 | +Represent results as: |
| 106 | + |
| 107 | +- `added[]`, `modified[]`, `deleted[]`, `renamed[]` |
| 108 | +- plus boolean risk flags for config/index/meta-annotation changes |
| 109 | + |
| 110 | +## Execution Plan |
| 111 | + |
| 112 | +### Full mode |
| 113 | + |
| 114 | +- Lance: `cocoindex update ... --full-reprocess -f` |
| 115 | +- Kuzu: `build_ast_graph.py --source-root ...` (full rebuild via |
| 116 | + `_drop_all`) |
| 117 | + |
| 118 | +### Incremental mode |
| 119 | + |
| 120 | +- Lance: `cocoindex update ... -f` (without `--full-reprocess`) |
| 121 | +- Kuzu: `build_ast_graph.py --source-root ... --changed-paths ...` |
| 122 | + (incremental rebuild via TIER2 proposal) |
| 123 | + |
| 124 | +The decision engine returns two independent mode choices — Lance and |
| 125 | +Kuzu may incrementally update independently. For example, if |
| 126 | +`.deps.json` is missing but no config changed, Lance could be |
| 127 | +incremental while Kuzu falls back to full. |
| 128 | + |
| 129 | +## Response Payload Enhancements |
| 130 | + |
| 131 | +Add decision transparency fields to `refresh_code_index` response: |
| 132 | + |
| 133 | +- `effective_mode: { lance: "incremental" | "full", kuzu: "incremental" | "full" }` |
| 134 | +- `decision_reasons: list[str]` |
| 135 | +- `detected_changes: { added, modified, deleted, renamed }` |
| 136 | +- optional `warnings: list[str]` |
| 137 | + |
| 138 | +Keep existing stdout/stderr/exit_code fields intact. |
| 139 | + |
| 140 | +For the CLI (`increment` command), emit the mode decision to stderr |
| 141 | +with `[graph]` / `[vectors]` prefixes consistent with existing |
| 142 | +progress output (see `CLI-PROGRESS-OUTPUT-PROPOSE.md`). |
| 143 | + |
| 144 | +## Safety Policy |
| 145 | + |
| 146 | +- Default `auto`. |
| 147 | +- On uncertainty, choose `full`. |
| 148 | +- `mode=full` always respected. |
| 149 | +- `mode=incremental` allowed, but return warnings when risk triggers |
| 150 | + exist. |
| 151 | +- Never silently downgrade explicit `full` to incremental. |
| 152 | +- Kuzu incremental failure at runtime → roll back, fall back to full |
| 153 | + Kuzu rebuild, log reason. |
| 154 | + |
| 155 | +## Test Plan |
| 156 | + |
| 157 | +1. `auto` + modified-only → incremental (both Lance + Kuzu). |
| 158 | +2. `auto` + deleted file → full Kuzu, incremental Lance. |
| 159 | +3. `auto` + renamed file → full Kuzu, incremental Lance. |
| 160 | +4. `auto` + `.java-codebase-rag.yml` change → full (both). |
| 161 | +5. `auto` + detection failure → full with reason. |
| 162 | +6. explicit `mode=full` → full regardless of diffs. |
| 163 | +7. explicit `mode=incremental` + risky changes → incremental + warning. |
| 164 | +8. backward compatibility: `confirm=true` only call still succeeds. |
| 165 | +9. `.deps.json` missing → full Kuzu, incremental Lance. |
| 166 | +10. `.deps.json` stale `ontology_version` → full Kuzu, incremental Lance. |
| 167 | + |
| 168 | +## Implementation Notes |
| 169 | + |
| 170 | +- Keep mode-selection logic isolated in helper functions for testability: |
| 171 | + - `_detect_repo_changes(...)` |
| 172 | + - `_choose_refresh_mode(...)` |
| 173 | +- Make logs/user-facing messages explicit about why full mode was |
| 174 | + selected. |
| 175 | +- Preserve current subprocess environment and project-root behavior. |
| 176 | +- The decision engine lives in a shared module (e.g. `index_common.py` |
| 177 | + or a new `refresh_decision.py`) usable by both `cli.py` and |
| 178 | + `server.py`. |
| 179 | + |
| 180 | +## Rollout |
| 181 | + |
| 182 | +1. Implement decision engine with isolated helpers + tests. |
| 183 | +2. Integrate into `cli.py`'s `_cmd_increment` — remove |
| 184 | + `_emit_increment_kuzu_warning()`, dispatch to Kuzu incremental or |
| 185 | + full based on decision. |
| 186 | +3. Integrate into `server.py`'s `refresh_code_index` MCP tool. |
| 187 | +4. Update `README.md` and `docs/JAVA-CODEBASE-RAG-CLI.md`. |
0 commit comments