Skip to content

Commit 4161c89

Browse files
jsbattigclaude
andcommitted
fix: v9.14.3 — CLI temporal anti-fallback second path
E2E variation testing revealed cli.py had a second fallback path at the _has_temporal check (~line 5190). When no temporal collection directory existed, the CLI printed "Falling back to space-only search" and set time_range = None, silently executing a full regular semantic search instead of returning nothing. Fixed: replaced time_range = None fall-through with early return after printing honest "Temporal index not available. No results returned." message. Consistent with Messi Rule #2 (graceful failure over forced success). Added test: test_cli_no_temporal_index_returns_immediately verifies execute_temporal_query_with_fusion is never called when _has_temporal=False. Also found (not fixed here): --chunk-type, --author, diff_type filters are silently dropped in execute_temporal_query_with_fusion — pre-existing gap not introduced by this work. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 559f991 commit 4161c89

File tree

4 files changed

+65
-10
lines changed

4 files changed

+65
-10
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## v9.14.3
9+
10+
### Fixes
11+
12+
- fix: Temporal CLI anti-fallback (second path) — discovered during E2E variation testing that `cli.py` had a second fallback at the `_has_temporal` check (line ~5190). When no temporal collection directory existed at all, the CLI printed "Falling back to space-only search (current code state only)" and set `time_range = None`, causing a full regular semantic search to execute silently. Fixed by replacing `time_range = None` fall-through with an early `return` after printing the honest "No results returned" message. Added test `test_cli_no_temporal_index_returns_immediately` that verifies `execute_temporal_query_with_fusion` is never called when the temporal index is absent.
13+
814
## v9.14.2
915

1016
### Fixes
1117

12-
- fix: Temporal index anti-fallback — removed dishonest "Showing results from current code only" fallback messaging when a temporal index is unavailable. The old behavior silently returned a warning claiming to show current-code results; the corrected behavior returns an empty result set and an honest message stating "No results returned. Build the temporal index with 'cidx index --index-commits' to enable time-range queries." Applies to both MCP/REST (server) and CLI paths. Rule: graceful failure over forced success (Messi Rule #2).
18+
- fix: Temporal index anti-fallback — removed dishonest "Showing results from current code only" fallback messaging when a temporal index is unavailable in the server/MCP path (`semantic_query_manager.py`) and in the CLI warning display when `execute_temporal_query_with_fusion` returns empty results with a warning. The corrected behavior returns an empty result set and an honest message stating "No results returned. Build the temporal index with 'cidx index --index-commits' to enable time-range queries." Rule: graceful failure over forced success (Messi Rule #2).
1319

1420
- fix: Temporal query `temporal_context` field mapping — `_execute_temporal_query` was reading legacy fields (`first_seen`, `last_seen`, `appearance_count`, `commits`) from `TemporalSearchResult.temporal_context` that no longer exist in the current diff-based implementation, causing all temporal_context fields to be `None` in query responses. Fixed by mapping the actual current fields: `commit_hash`, `commit_date`, `commit_message`, `author_name`, `commit_timestamp`, `diff_type`. Verified end-to-end with a real git repo, temporal index, and CLI query confirming all fields populated with real data.
1521

src/code_indexer/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66
HNSW graph indexing (O(log N) complexity).
77
"""
88

9-
__version__ = "9.14.2"
9+
__version__ = "9.14.3"
1010
__author__ = "Seba Battig"

src/code_indexer/cli.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5188,18 +5188,18 @@ def get_daemon_config(self):
51885188
if d.is_dir()
51895189
)
51905190
if not _has_temporal:
5191-
console.print("[yellow]⚠️ Temporal index not found[/yellow]")
5191+
console.print("[yellow]⚠️ Temporal index not available[/yellow]")
51925192
console.print()
5193-
console.print("Time-range filtering requires a temporal index.")
51945193
console.print(
5195-
"Falling back to space-only search (current code state only)."
5194+
"Temporal index not available for this repository. No results returned."
51965195
)
51975196
console.print()
5198-
console.print("To enable temporal queries, build the temporal index:")
5199-
console.print(" [cyan]cidx index --index-commits[/cyan]")
5200-
console.print()
5201-
# Fall through to regular search without time-range filtering
5202-
time_range = None
5197+
console.print(
5198+
"Build the temporal index with "
5199+
"[cyan]cidx index --index-commits[/cyan] "
5200+
"to enable time-range queries."
5201+
)
5202+
return
52035203
else:
52045204
# Handle time_range="all" from --time-range-all flag
52055205
if time_range == "all":

tests/unit/cli/test_temporal_warning_display.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,9 +122,58 @@ def _invoke_temporal_query(runner, temp_project, temporal_results):
122122
)
123123

124124

125+
@pytest.fixture
126+
def temp_project_no_temporal(tmp_path):
127+
"""Project directory WITHOUT any temporal collection — _has_temporal check fails."""
128+
code_indexer_dir = tmp_path / ".code-indexer" / "index"
129+
code_indexer_dir.mkdir(parents=True)
130+
# No temporal collection directory created — simulates missing temporal index
131+
return tmp_path
132+
133+
125134
class TestCLITemporalWarningDisplay:
126135
"""Verify the CLI displays the warning from TemporalSearchResults."""
127136

137+
def test_cli_no_temporal_index_returns_immediately(
138+
self, runner, temp_project_no_temporal
139+
):
140+
"""When no temporal collection directory exists, CLI returns immediately.
141+
142+
Must print honest "No results returned" message and must NOT invoke
143+
execute_temporal_query_with_fusion at all (no fallback search).
144+
"""
145+
config_manager_mock = _make_config_manager_mock(temp_project_no_temporal)
146+
147+
with patch(
148+
"src.code_indexer.services.temporal.temporal_fusion_dispatch"
149+
".execute_temporal_query_with_fusion"
150+
) as mock_fusion:
151+
result = runner.invoke(
152+
query_command,
153+
["--time-range-all", "authentication"],
154+
obj={
155+
"config_manager": config_manager_mock,
156+
"project_root": str(temp_project_no_temporal),
157+
"mode": "local",
158+
"standalone": True,
159+
},
160+
catch_exceptions=False,
161+
)
162+
163+
assert result.exit_code == 0, (
164+
f"Expected exit code 0, got {result.exit_code}. Output: {result.output!r}"
165+
)
166+
assert "No results returned" in result.output, (
167+
f"CLI must display honest 'No results returned' message. Output: {result.output!r}"
168+
)
169+
assert "cidx index --index-commits" in result.output, (
170+
f"CLI must mention the build command. Output: {result.output!r}"
171+
)
172+
assert not mock_fusion.called, (
173+
"Fusion dispatch must NOT be called when temporal index is absent — "
174+
"no fallback search allowed"
175+
)
176+
128177
def test_cli_displays_temporal_warning_when_no_index(self, runner, temp_project):
129178
"""When fusion dispatch returns empty results with a warning, CLI must display it.
130179

0 commit comments

Comments
 (0)