Tests Implementation Plan
Tests live primarily in codeagent-engine/crates/codeagent-core/src/, with additional tests in
codeagent-mcp (MCP server tools) and codeagent-cli (init + hooks).
This document lists every test that has been (or should be) written, organised by the phase whose
feature it exercises. Tests that cover infrastructure shared across multiple phases are filed under
the earliest phase that requires them.
Symbol
Meaning
✅
Implemented and passing
⬜
Planned — not yet written
🔁
Deferred — requires infrastructure not yet built
Phase
Implemented
Planned / Deferred
1 — Foundation
148
0
2a — Semantic enrichment
37
0
2b — Rename detection
23
0
3 — Embedding
17
0
Multi-file fixture (integration)
41
0
4a — Retrieval channels
20
0
4b — Merge, rerank, eval
28
0
5 — MCP server
24
0
6 — Hardening
28
0
OSS Integration Tests
30
0
Hooks, Dead Code & Init
17
0
ASP.NET Core API Boundary
33
0
Pipeline integration
7
0
Features: tree-sitter parsing, schema + migrations, graph CRUD, FTS5, path normalisation, type
system, embedding text construction, query layer, basic incremental invalidation.
ID
Test
Description
Status
T-001
test_csharp_extracts_namespace
namespace Foo {} → Module node with symbol_key = "Foo:module"
✅
T-002
test_csharp_extracts_class_with_method
Class + method both extracted; method symbol_key includes param count and types
✅
T-003
test_csharp_overload_distinct_symbol_keys
Two methods with same name but different param lists → distinct symbol_key values
✅
T-004
test_csharp_extracts_interface
interface IFoo {} → Interface node
✅
T-005
test_csharp_extracts_property
public int Prop { get; set; } → Property node
✅
T-006
test_csharp_generated_flag_propagated
Node from a file matching a generated-glob pattern has generated = 1
✅
T-007
test_csharp_parse_status_on_invalid_syntax
Malformed C# does not panic; file node still emitted with parse_status = 'syntactic_only'
✅
T-008
test_csharp_extracts_enum
enum Status { … } → NodeType::Type with symbol_key = "Status:type"
✅
T-009
test_csharp_extracts_struct
struct Point { … } routed through handle_class → Class node
✅
T-010
test_csharp_nested_class_qualified_name
Nested class receives fully-qualified name Outer.Inner:class; type-stack propagates correctly
✅
T-011
test_csharp_extracts_constructor
Constructor symbol_key includes param count, e.g. Widget.Widget:constructor:1(string)
✅
T-013
test_csharp_deeply_nested_generics_signature_truncated
Parameter signature with deeply-nested generics truncated at configured max_signature_length; stored value ends with "..."
✅
T-420
test_csharp_reference_count_defaults_to_zero_in_phase1
Phase 1 tree-sitter indexing sets reference_count = 0 for all method nodes (not computed until semantic enrichment)
✅
ID
Test
Description
Status
T-014
test_ts_extracts_exported_function
export function foo() → node with export_scope = "module", stored as node_type = 'method'
✅
T-015
test_ts_extracts_interface
export interface IService {} → Interface node
✅
T-016
test_ts_non_exported_function_has_file_scope
Non-exported function extracted with export_scope = "file"
✅
T-017
test_ts_symbol_key_contains_file_id_segment
Phase 1 TS symbol_key contains the file_id segment for module-scoped symbols
✅
T-018
test_tsx_file_parses_without_error
.tsx file with JSX parses without error
✅
T-019
test_ts_file_node_emitted
Indexing a .ts file produces a file node
✅
T-020
test_ts_arrow_function_extracted_as_method
const double = (n: number) => … → node_type = 'method'
✅
T-021
test_ts_class_method_extracted
Class extracted + body method extracted as node_type = 'method'
✅
T-022
test_ts_type_alias_extracted
type UserId = string → NodeType::Type
✅
T-023
test_ts_enum_extracted
enum Direction { … } → NodeType::Type
✅
T-421
test_ts_reference_count_defaults_to_zero_in_phase1
Phase 1 tree-sitter indexing sets reference_count = 0 for all method nodes (not computed until semantic enrichment)
✅
T-422
test_ts_same_named_exports_in_different_files_distinct_keys
Two identically-named exported functions in different files produce distinct identity keys (file_id segment differs)
✅
T-431
test_ts_interface_body_walked
Interface method and property signatures extracted as child nodes
✅
ID
Test
Description
Status
T-025
test_migration_from_empty
Empty DB → migrate to CURRENT_SCHEMA_VERSION
✅
T-026
test_migration_idempotent
Running run_migrations() twice is a no-op
✅
T-027
test_downgrade_rejected
DB at higher schema version → CoreError::SchemaTooNew
✅
T-028
test_quick_check_passes_on_valid_db
PRAGMA quick_check succeeds on a freshly migrated DB
✅
T-029
test_schema_tables_exist
All expected tables are present after migration 001
✅
T-030
test_primary_span_partial_unique_index_exists
idx_node_spans_one_primary partial unique index exists
✅
T-031
test_node_identity_map_table_exists
node_identity_map table present after migration 002
✅
T-032
test_node_identity_map_index_exists
idx_node_identity_map_old index exists after migration 002
✅
T-033
test_node_identity_map_insert_and_query
Row with BLOB(16) UUID columns can be inserted and queried back
✅
T-034
test_schema_version_is_4
CURRENT_SCHEMA_VERSION == 4; DB reaches version 4 after all migrations (api_endpoints added by migration 004)
✅
ID
Test
Description
Status
T-036
test_root_project_creation_and_idempotency
ensure_root_project() creates self-referential project node; second call is a no-op
✅
T-037
test_upsert_node_insert
New node round-trips all fields via upsert_node()
✅
T-039
test_c_sharp_overload_identity
Two C# overloads coexist without a UNIQUE constraint violation
✅
T-040
test_multi_span_chunk_hash_ordering
Multi-span chunk_hash is order-independent (sorted by bytes ASC)
✅
T-041
test_fts_insert_and_search
After sync_fts_insert(), FTS MATCH query on name returns that node
✅
T-042
test_fts_delete_on_node_removal
After sync_fts_delete(), FTS query returns no results
✅
T-043
test_fts_prefix_search
3-character prefix query (Pro*) returns the matching node
✅
T-044
test_fts_update_replaces_old_name
Re-inserting with a new display_name removes old name from FTS index
✅
T-045
test_fts_dotted_name_is_single_token
. is a tokenchar: AuthSvc.Login is one FTS token; plain AuthSvc does NOT match it
✅
T-046
test_fts_at_verbatim_identifier_preserved
@ is a tokenchar: @event is indexed and matchable as a single token
✅
T-047
test_fts_underscore_identifier_preserved
_ is a tokenchar: MY_CONST is indexed as one token
✅
T-048
test_fts_dollar_identifier_preserved
$ is a tokenchar: $scope is indexed as one token including the $ prefix
✅
T-423
test_upsert_nodes_in_tx_panics_above_500
debug_assert fires when caller passes >500 nodes to upsert_nodes_in_tx (bounded write transactions invariant)
✅
T-424
test_multi_project_same_symbol_name_coexists
Identical symbol_key in two distinct projects coexists without UNIQUE violation (project_id differentiates)
✅
T-425
test_parse_status_stays_syntactic_only_when_enrichment_skipped
Node inserted with parse_status=syntactic_only retains that value until explicit upgrade to full
✅
ID
Test
Description
Status
T-049
test_edge_insert_and_query
Edge inserted and retrieved by get_outgoing_edges() / get_incoming_edges()
✅
T-050
test_on_delete_cascade_for_edges
Deleting the source node cascade-deletes its edges
✅
T-051
test_replace_semantic_edges_removes_stale
replace_semantic_edges_in_tx() removes old exact edges and inserts the new set
✅
T-052
test_replace_semantic_edges_preserves_out_of_scope_edges
Approximate edges from nodes outside the scope survive the replacement
✅
T-053
test_replace_semantic_edges_upgrades_approximate_to_exact
Approximate edge for (A→B) upgraded to exact when semantic pass confirms the same edge
✅
T-054
test_replace_semantic_edges_empty_new_set_removes_exact
Empty new-edge slice removes all exact and approximate edges from the scope
✅
T-055
test_delete_outgoing_edges_by_type_selects_only_matching_type
delete_outgoing_edges_by_type(Calls) leaves References edges untouched
✅
T-056
test_upsert_edge_insert_or_ignore_no_duplicate
Calling upsert_edge twice produces exactly one row
✅
ID
Test
Description
Status
T-057
test_insert_span_roundtrip
Span inserted via insert_span() is retrievable with all fields correct
✅
T-058
test_replace_spans_replaces_old
replace_spans() removes prior spans for a node and inserts the new set
✅
T-059
test_primary_span_flag
After replace_spans(), exactly one span has is_primary = 1
✅
T-060
test_reassign_primary_span
reassign_primary_span() flips the primary flag correctly without touching other nodes
✅
T-061
test_replace_spans_on_empty_slice
replace_spans() with an empty slice leaves no spans for the node
✅
T-426
test_node_spans_file_id_cascade_deletes_orphaned_spans
Directly deleting a file node CASCADE-deletes its node_spans rows (safety net independent of explicit deletion algorithm)
✅
ID
Test
Description
Status
T-062
test_delete_file_removes_single_span_nodes
Deleting a file removes all single-span nodes and their spans; journals each deleted node; edges cascade-delete
✅
T-063
test_delete_file_preserves_multi_span_node
Multi-span node not hard-deleted when only one of its files is removed; primary span reassigned
✅
T-064
test_deletion_is_in_single_transaction
Entire deletion sequence (spans → nodes → file node) executes atomically
✅
T-065
test_journal_sweep
sweep_deletion_journal() removes entries older than the configured TTL
✅
T-066
test_journal_node_direct_roundtrip
journal_node() writes all fields (including chunk_fingerprint bytes) to deletion_log
✅
T-067
test_delete_symbol_journals_and_removes_node
delete_symbol() writes a journal entry first, then hard-deletes the node
✅
T-068
test_delete_file_no_orphaned_fts_rows
After file deletion, fts_nodes has no rows for any deleted symbol's node_id
✅
ID
Test
Description
Status
T-069
test_creates_before_deletes_ordering
ChangeBatch always yields creates/modifications before deletes regardless of event order
✅
T-070
test_deduplication_keeps_latest
Multiple events for the same path are collapsed to the most recent
✅
ID
Test
Description
Status
T-072
test_decision_matrix_calls_source_changed
Calls + SourceNodeChanged → RecomputeViaSemantic
✅
T-073
test_decision_matrix_calls_target_body_only
Calls + TargetBodyOnly → NoAction
✅
T-074
test_decision_matrix_calls_node_id_preserved
Calls + TargetNodeIdPreserved → NodeIdPreserved
✅
T-075
test_decision_matrix_calls_node_id_replaced
Calls + TargetNodeIdReplaced → CascadeRemoved
✅
T-076
test_decision_matrix_contains_child_changed
Contains + ContainerChildChanged → RecomputeFromAst
✅
T-077
test_decision_matrix_contains_method_body_only
Contains + MethodBodyOnly → NoAction
✅
T-078
test_decision_matrix_imports_source_changed
Imports + SourceNodeChanged → RecomputeFromAst
✅
T-079
test_decision_matrix_semantic_context_recompute
Any edge + SemanticContextChanged → RecomputeSemanticEdges
✅
T-080
test_needs_reindex_hash_changed
needs_reindex() returns true when chunk_hash differs
✅
T-081
test_decision_matrix_references_source_changed
References + SourceNodeChanged → RecomputeViaSemantic
✅
T-082
test_decision_matrix_references_target_body_only
References + TargetBodyOnly → NoAction
✅
T-083
test_decision_matrix_references_target_node_id_replaced
References + TargetNodeIdReplaced → CascadeRemoved
✅
T-084
test_decision_matrix_inherits_declaration_header_changed
Inherits + DeclarationHeaderChanged → RecomputeViaSemantic
✅
T-085
test_decision_matrix_inherits_base_type_changed
Inherits + BaseTypeChanged → NoAction
✅
T-086
test_decision_matrix_implements_declaration_header_changed
Implements + DeclarationHeaderChanged → RecomputeViaSemantic
✅
T-087
test_decision_matrix_implements_base_type_changed
Implements + BaseTypeChanged → NoAction
✅
T-088
test_decision_matrix_overrides_declaration_header_changed
Overrides + DeclarationHeaderChanged → RecomputeViaSemantic
✅
T-089
test_decision_matrix_overrides_base_type_changed
Overrides + BaseTypeChanged → NoAction
✅
T-090
test_decision_matrix_accepts_source_changed
Accepts + SourceNodeChanged → RecomputeViaSemantic (+ ProbableIfStructural)
✅
T-091
test_decision_matrix_accepts_target_body_only
Accepts + TargetBodyOnly → NoAction
✅
T-092
test_decision_matrix_extends_source_changed
Extends + SourceNodeChanged → RecomputeViaSemantic
✅
T-093
test_decision_matrix_extends_target_body_only
Extends + TargetBodyOnly → NoAction
✅
T-094
test_decision_matrix_default_fallback_is_no_action
Any unspecified (edge_type, change_type) pair → NoAction
✅
ID
Test
Description
Status
T-095
test_resolve_project_id_exact_dir
File inside a project directory resolves to that project
✅
T-096
test_resolve_project_id_falls_back_to_root
File with no matching project resolves to the root
✅
T-097
test_resolve_project_id_most_specific_wins
File under nested projects resolves to the most deeply nested one
✅
T-098
test_detect_csproj_project
Directory with a .csproj file detected as a CSharp project
✅
T-099
test_detect_package_json_project
package.json → TypeScript project with correct display_name
✅
T-100
test_detect_tsconfig_only_project
tsconfig.json with no package.json → detected as TS project
✅
T-101
test_detect_skips_node_modules
node_modules/ subtrees not walked during detection
✅
T-102
test_detect_nested_csproj_projects
Two .csproj at different depths → two distinct detected projects
✅
T-103
test_ensure_projects_in_db_idempotent
Calling ensure_projects_in_db twice returns the same ProjectId both times
✅
ID
Test
Description
Status
T-104
test_to_posix_forward_slashes
Windows backslashes converted to forward slashes
✅
T-105
test_normalize_relative_path
Leading separators stripped; backslashes converted
✅
T-106
test_detect_language
.cs → CSharp; .ts/.tsx → TypeScript; others → None
✅
T-107
test_is_generated
Files matching configured glob patterns flagged as generated
✅
T-108
test_is_semantic_context_file
.csproj, tsconfig.json, package.json identified as semantic context files
✅
T-109
test_glob_match
Glob pattern matching works for common patterns
✅
T-110
✅ test_symlink_outside_repo_root_rejected
Symlink pointing outside repo root → path rejected by verify_within_repo_root()
✅
T-111
✅ test_symlink_inside_repo_root_accepted_when_follow_enabled
Symlink within repo root indexed when follow_symlinks = true; skipped when false
✅
ID
Test
Description
Status
T-112
test_language_roundtrip
Language::as_str() / from_str() / Display consistent; unknown string → None
✅
T-113
test_node_type_roundtrip
All 10 NodeType variants round-trip through as_str() → from_str()
✅
T-114
test_edge_type_roundtrip
All 9 EdgeType variants round-trip
✅
T-115
test_edge_type_is_source_driven
Calls, References, Overrides, Extends → true; other 5 → false
✅
T-116
test_edge_confidence_roundtrip
All 3 EdgeConfidence variants round-trip
✅
T-117
test_parse_status_roundtrip
All 3 ParseStatus variants round-trip
✅
T-118
test_access_modifier_roundtrip
All 7 AccessModifier variants (incl. ProtectedInternal, Exported, Unexported) round-trip
✅
T-119
test_export_scope_roundtrip
All 3 ExportScope variants round-trip
✅
T-121
test_content_hash_to_hex_all_zeroes
All-zero hash → 64-char hex of "00"×32
✅
T-122
test_content_hash_to_hex_known_value
Known byte values produce expected hex characters
✅
T-123
test_content_hash_from_bytes_roundtrip
as_bytes() → from_bytes() returns original ContentHash
✅
T-124
test_content_hash_from_bytes_wrong_length
31, 33, and 0-byte slices all return None
✅
T-125
test_content_hash_serde_roundtrip
serde_json serialize → deserialize produces identical ContentHash; form is 64-char hex
✅
T-126
test_node_id_from_bytes_roundtrip
NodeId::as_bytes() → from_bytes() round-trips
✅
T-127
test_node_id_from_bytes_wrong_length
15 and 17-byte slices return None
✅
T-128
test_file_id_and_project_id_roundtrip
FileId and ProjectId both round-trip; wrong-length slices return None
✅
T-129
test_node_id_to_string_repr_is_uuid_format
to_string_repr() produces canonical 8-4-4-4-12 UUID format
✅
embedding/onnx (text builders only — model load requires external files)
ID
Test
Description
Status
T-130
test_build_embedding_text_no_boilerplate
Symbol embedding text omits constant boilerplate
✅
T-131
test_build_file_embedding_text
File embedding text includes path, filename, and language
✅
T-132
test_build_embedding_text_all_none_optionals
All-None → output is just "qualified_name node_type"
✅
T-133
test_build_embedding_text_empty_string_optionals_skipped
Empty "" optional strings produce no extra tokens
✅
T-134
test_build_embedding_text_doc_comment_truncated_at_200
Doc comments > 200 chars are truncated
✅
T-135
test_build_file_embedding_text_no_slash_in_path
Path with no / still extracts the filename correctly
✅
T-136
test_build_file_embedding_text_empty_summary_omitted
Empty import/export summary not included
✅
T-137
test_build_file_embedding_text_doc_comment_truncated
File doc comment truncated to 200 chars
✅
ID
Test
Description
Status
T-138
test_get_node_roundtrip
Node written to DB → retrieved with all fields intact
✅
T-139
test_get_node_not_found
get_node() returns None for an unknown NodeId
✅
T-140
test_get_neighbors_outgoing
get_neighbors() returns correct outgoing edges and their target nodes
✅
T-141
test_get_neighbors_incoming
get_neighbors() returns correct incoming edges and their source nodes
✅
T-142
test_get_source
get_source() returns the primary span content for a node
✅
T-143
test_get_outline
get_outline() returns all child nodes of a file, ordered by line number
✅
T-144
test_filter_nodes_sql
filter_nodes() applies language, type, and text search filters correctly
✅
T-145
test_get_node_by_qualified_name
Node looked up by qualified_name
✅
T-146
test_filter_nodes_fts_returns_bm25_rank
FTS query in filter_nodes() populates rank field; results ordered best-first
✅
Phase 2a — Semantic Enrichment
Features: Roslyn / TS Language Service IPC, identity reconciliation, semantic edge replacement,
semantic-context invalidation.
ID
Test
Description
Status
T-149
test_csharp_unavailable_when_safe_mode_true
safe_mode = true blocks C# even when the extractor path is set
✅
T-150
test_csharp_available_when_safe_mode_false_and_path_set
safe_mode = false + path set → C# available
✅
T-151
test_csharp_unavailable_when_no_extractor_path
csharp_extractor_path = None → C# unavailable regardless of safe_mode
✅
T-152
test_typescript_available_regardless_of_safe_mode
TypeScript availability not gated by safe_mode
✅
T-153
test_typescript_unavailable_when_no_extractor_path
typescript_extractor_path = None → TypeScript unavailable
✅
T-154
test_default_config_both_languages_unavailable
Default config (safe_mode=true, no paths) → both languages unavailable
✅
T-432
test_parse_tfm_major_valid
TFM major version parsing succeeds for net8.0 and net10.0
✅
T-433
test_parse_tfm_major_rejects_invalid
TFM parsing rejects netstandard and invalid formats
✅
T-434
test_resolve_dll_picks_highest_available_runtime
DLL resolution selects highest TFM with installed runtime
✅
T-435
test_resolve_dll_falls_back_when_no_runtime_matches
DLL resolution returns original path if no matching runtime
✅
T-436
test_resolve_dll_not_under_tfm_dir_returns_as_is
Non-TFM DLL paths returned unchanged
✅
T-437
test_resolve_non_dll_returns_as_is
Non-DLL files returned as-is by resolver
✅
T-155
✅ test_ipc_handshake_version_mismatch_triggers_fallback
Protocol version mismatch during handshake → graceful fallback to syntactic-only mode
✅
T-156
✅ test_ipc_request_deadline_enforced
IPC request that exceeds deadline → Timeout error code returned promptly
✅
T-157
✅ test_ipc_child_process_crash_clears_slot
Child process exiting clears the slot so next request re-spawns
✅
T-158
✅ test_nuget_restore_blocked_when_allow_nuget_restore_false
allow_nuget_restore = false → NuGet restore command not sent even when safe_mode = false
✅
T-251
✅ test_ipc_backpressure_error_when_child_queue_full
Bounded semaphore at capacity → next request returns structured backpressure error rather than blocking indefinitely
✅
T-252
✅ test_ipc_cancel_inflight_request_does_not_write_edges
Cancelling a request mid-flight prevents any edges from that enrichment request being committed
✅
T-253
✅ test_ipc_deadline_timeout_respects_max_retries
IPC request exceeding deadline is retried up to the configured max-retries then returns a structured timeout error
✅
ID
Test
Description
Status
T-159
test_rpc_request_new_has_jsonrpc_2_0_field
RpcRequest::new() sets jsonrpc = "2.0"
✅
T-160
test_rpc_notification_has_empty_id
RpcRequest::notification() produces empty id string
✅
T-161
test_rpc_request_serializes_to_valid_json_rpc_2_0
Serialized JSON has correct jsonrpc, method, id fields
✅
T-162
test_rpc_request_no_params_omitted_in_json
params: None omitted via skip_serializing_if
✅
T-163
test_ipc_error_code_from_code_all_variants
All 5 IpcErrorCode variants decode from their integer codes
✅
T-164
test_ipc_error_code_unknown_returns_none
Unrecognised codes return None
✅
T-165
test_parse_result_extracts_analyze_file_result
parse_result<AnalyzeFileResult>() deserializes valid response
✅
T-166
test_parse_result_returns_error_on_rpc_error_field
parse_result returns Err when response has error field
✅
T-167
test_parse_result_returns_error_when_no_result_and_no_error
parse_result returns Err when both fields absent
✅
T-168
test_handshake_params_serde_roundtrip
HandshakeParams serializes and deserializes losslessly
✅
T-169
test_analyze_file_params_project_file_omitted_when_none
project_file: None omitted from AnalyzeFileParams JSON
✅
T-170
test_analyze_file_params_project_file_present_when_some
project_file: Some(_) present in AnalyzeFileParams JSON
✅
T-171
test_rpc_error_data_omitted_when_none
data: None omitted from RpcError JSON
✅
ID
Test
Description
Status
T-172
test_csharp_reconciliation_in_place
Roslyn-provided symbol_key replaces tree-sitter key in-place
✅
T-173
test_csharp_reconciliation_noop_if_same_key
Reconciling with identical key makes no DB change
✅
T-174
test_csharp_reconciliation_conflict_falls_back_to_identity_map
UNIQUE conflict → old node deleted; surviving node gets new key; node_identity_map entry written
✅
T-175
test_ts_export_scope_upgrade
upgrade_ts_export_scope() updates export_scope and symbol_key in-place
✅
ID
Test
Description
Status
T-254
✅ test_semantic_enrichment_failure_preserves_existing_edges
When enrichment returns an error for a scope, existing edges (exact or approximate) survive unchanged; no partial replacement occurs
✅
Phase 2b — Rename Detection
Features: git-based, fingerprint-based, and symbol-level rename detection; deletion_log
chunk_fingerprint; node_identity_map fallback.
ID
Test
Description
Status
T-177
test_rename_detector_no_deletes_returns_empty
Batch with no deletes → empty rename result set
✅
T-178
test_rename_detector_no_creates_returns_empty
Batch with deletes but no creates → empty rename result set
✅
T-179
test_parse_git_rename_basic
"R95\told.cs\tnew.cs" parses to one rename pair
✅
T-180
test_parse_git_rename_not_in_batch_filtered_out
Rename line referencing paths not in the batch excluded
✅
T-181
test_parse_git_rename_ignores_non_rename_lines
M, A, D status lines ignored
✅
T-182
test_parse_git_rename_multiple_renames
Multiple rename lines all parsed correctly
✅
T-183
test_parse_git_rename_malformed_line_skipped
Malformed R lines skipped silently
✅
T-184
test_fingerprint_rename_detected_via_deletion_log
Deletion log entry with matching fingerprint → rename detected
✅
T-185
test_fingerprint_rename_not_detected_when_no_journal_entry
No journal entry → no fingerprint match
✅
T-438
test_rename_class_and_file_detected_via_fingerprint
Fingerprint detects simultaneous class and file rename
✅
T-186
✅ test_symbol_level_rename_preserves_node_id
Method rename (same body, new name) → node_identity_map entry written; node_id preserved or remapped
✅
T-187
✅ test_rename_and_body_change_is_not_detected
Rename + substantial body rewrite → similarity < threshold → treated as delete+create
✅
T-188
✅ test_file_rename_preserves_embeddings
File-level rename → node_id preserved; vec_nodes embedding row retained
✅
T-255
✅ test_rename_detector_ambiguous_candidates_resolved_deterministically
Two deleted nodes with similar fingerprints and one created node → either no match (preferred) or highest-score with deterministic tie-breaker; result stable across runs
✅
T-257
✅ test_git_diff_failure_falls_back_to_fingerprint
Git unavailable or errors → rename detector continues with fingerprint-only mode without failing the batch
✅
ID
Test
Description
Status
T-189
test_jaccard_identical
Identical fingerprints → similarity 1.0
✅
T-190
test_jaccard_empty
Empty fingerprint sets → similarity 0.0
✅
T-191
test_jaccard_disjoint
Completely different sets → similarity 0.0
✅
T-192
test_jaccard_half_overlap
Half-overlapping sets → Jaccard ≈ 0.33 (intersection=2, union=6)
✅
T-193
test_renamed_method_high_similarity
Method with only its name changed → Jaccard ≥ 0.80
✅
T-194
test_fingerprint_roundtrip
fingerprint_to_bytes() / fingerprint_from_bytes() round-trip losslessly
✅
T-195
test_fingerprint_unchanged_file_similarity_is_1
Same file content both times → Jaccard = 1.0
✅
T-196
test_fingerprint_completely_rewritten_is_below_threshold
Completely different content → similarity < 0.20
✅
Features: EmbeddingProvider trait; HashEmbeddingProvider test stub (SHA-256 deterministic,
L2-normalised, 384-dim); vec_nodes embedding store (regular SQLite table for Phase 3; Phase 4
upgrades to ANN); embedding invalidation on model change.
ID
Test
Description
Status
T-200
test_hash_embedding_provider_dimensionality
HashEmbeddingProvider reports dimensionality() == 384
✅
T-201
test_hash_embedding_provider_unit_norm
SHA-256-based embedding is L2-normalised (‖v‖ ≈ 1.0)
✅
T-202
test_hash_embedding_provider_deterministic
Same text always produces identical embedding vector
✅
T-203
test_hash_embedding_provider_different_texts_differ
Two distinct texts produce different embeddings
✅
T-204
test_hash_embedding_provider_batch_matches_single
embed_batch results match embed_single results element-by-element
✅
T-205
test_hash_embedding_provider_model_id
model_id() returns "test-hash-model" for default constructor
✅
T-207
test_hash_embedding_provider_custom_model_id
with_model_id() constructor overrides the model ID
✅
ID
Test
Description
Status
T-206
test_embedding_stored_in_vec_nodes
After indexing a node, vec_nodes contains a row with the node's 384-dim embedding (stored as 1 536 LE bytes)
✅
T-208
test_embedding_model_change_triggers_re_embedding
handle_model_change() with a new model ID clears all vec_nodes rows and updates _metadata.embedding_model
✅
T-258
test_embedding_model_unchanged_returns_false
handle_model_change() with the same model ID returns false and leaves vec_nodes untouched
✅
T-259
test_insert_or_replace_overwrites_existing_embedding
Calling insert_or_replace_embedding twice for the same node results in exactly one row
✅
T-262
test_delete_embedding_removes_row
delete_embedding() removes the row for the given node_id
✅
T-263
test_delete_embedding_is_noop_when_absent
delete_embedding() with an absent node_id does not error
✅
T-264
test_vec_nodes_table_created_by_ensure
ensure_vec_nodes_table() creates the vec_nodes table (verified via sqlite_master)
✅
T-265
test_ensure_vec_nodes_table_is_idempotent
Calling ensure_vec_nodes_table() twice does not error
✅
T-439
test_vector_search_brute_force_empty_table
Empty vec_nodes table returns no results
✅
T-440
test_vector_search_brute_force_limit
Vector search respects limit parameter
✅
Phase 4a — Retrieval Channels
Features: sqlite-vec vector index; BM25 channel; qualified-name channel; hybrid retrieval with
token-budget enforcement.
retrieval/channels + retrieval/context + retrieval/mod
ID
Test
Description
Status
T-209
✅ test_vector_channel_returns_ranked_results
Vector similarity search returns ranked results with correct ordering
✅
T-210
✅ test_bm25_channel_returns_ranked_results
BM25 channel returns the expected node for a known-good keyword query
✅
T-211
✅ test_qualified_name_channel_exact_match
Qualified-name channel returns exact match with rank=1, score=1.0
✅
T-212
✅ test_token_budget_truncation
Result set serialised to context never exceeds token budget; truncated flag set
✅
T-213
✅ test_retrieve_end_to_end
Full retrieve() pipeline returns results from independent channels
✅
T-271
✅ test_build_fts_query_escapes_special_chars
FTS5 operators escaped and wildcard appended; no panic or query error
✅
T-272
✅ test_qualified_name_channel_no_match
Qualified-name channel returns empty for non-existent name
✅
T-273
✅ test_looks_like_qualified_name
Query analysis routes dot-separated identifiers to qname lookup
✅
T-274
✅ test_vector_search_brute_force_roundtrip
Brute-force cosine search returns results ordered by distance
✅
T-276
✅ test_context_preserves_score_order
Results with scores are ordered deterministically in context assembly
✅
T-277
✅ test_token_budget_no_truncation
Token budget with enough room fits all results; truncated=false
✅
T-441
test_bm25_channel_empty_query
BM25 search with empty FTS query returns empty results
✅
T-442
test_build_fts_query_empty
Empty query string produces empty FTS query
✅
T-443
test_build_fts_query_qualified_name_quoted
Qualified names wrapped in quotes for FTS phrase matching
✅
T-444
test_build_fts_query_simple_words
Simple words converted to OR-joined tokens with wildcards
✅
T-445
test_context_entry_has_metadata
Context entry contains node type, public api, and signatures
✅
T-446
test_estimate_tokens_non_zero
Token estimation produces non-zero positive result
✅
T-447
test_retrieve_cross_cutting_doubles_channel_k
Cross-cutting queries double the per-channel result limit
✅
T-448
test_retrieve_no_results
Non-existent queries return empty results
✅
T-449
test_retrieve_qualified_name_triggers_qname_channel
Qualified name queries rank qname channel matches first
✅
Phase 4b — Merge, Rerank & Eval
Features: Reciprocal Rank Fusion (RRF); quality/confidence penalty multipliers; intent classifier;
NDCG@10 eval harness.
retrieval/reranker + retrieval/intent
ID
Test
Description
Status
T-216
✅ test_rrf_merge_multi_channel
RRF score for a node in two channels is higher than a node in one channel
✅
T-217
✅ test_generated_node_penalty
Nodes with generated = true receive the configured generated_penalty multiplier
✅
T-218
✅ test_failed_parse_excluded
Nodes with parse_status = Failed are excluded from results entirely
✅
T-220
✅ test_cross_cutting_diversity_penalty
Cross-cutting mode diversity penalty reduces score for 2nd+ node from same file
✅
T-221
✅ test_targeted_intent_qualified_symbol
Dot-qualified symbol and file path queries classified as targeted intent
✅
T-222
✅ test_cross_cutting_intent
"All usages of …" style query classified as cross_cutting intent
✅
T-223
✅ test_exploratory_intent
Broad "how does X work" query classified as exploratory intent
✅
T-224
✅ test_eval_produces_valid_metrics
Eval harness produces valid NDCG and MRR metrics in [0,1] range
✅
T-225
✅ test_eval_negative_queries
Queries referencing non-existent symbols produce 0 metrics
✅
T-278
✅ test_qname_match_ranks_first
Qualified-name exact match always ranked first regardless of RRF base score
✅
T-279
✅ test_public_api_boost
Public API boost applied additively after base RRF score computation
✅
T-280
✅ test_fallback_is_targeted
Ambiguous queries without clear signals default to targeted intent
✅
T-281
✅ test_syntactic_only_penalty
Syntactic-only nodes penalized below full-parse nodes
✅
T-450
test_targeted_intent_file_path
File paths classified as targeted intent
✅
T-451
test_targeted_takes_priority_over_cross_cutting_when_symbol_present
Dot-qualified symbols take priority over quantifiers
✅
ID
Test
Description
Status
T-282
✅ test_ndcg_at_k
NDCG@k computed on hardcoded relevance list matches expected values; perfect ranking yields 1.0
✅
T-283
✅ test_mrr
MRR computed on hardcoded ranked result list matches expected value (1/rank)
✅
T-284
test_precision_at_k
Precision@k matches expected values for known result sets
✅
T-452
test_recall_at_k
Recall@k matches expected values for known result sets
✅
T-285
✅ test_load_eval_dataset_roundtrip
Eval dataset loads from JSON and round-trips correctly; archetype serde verified
✅
T-453
test_ndcg_no_relevant_nodes
NDCG@k returns 0.0 with empty relevance set
✅
T-454
test_mrr_first_is_relevant
MRR equals 1.0 when first result is relevant
✅
T-455
test_mrr_no_relevant
MRR equals 0.0 when no relevant nodes found
✅
T-456
test_precision_k_zero
Precision@k returns 0.0 when k is zero
✅
T-457
test_recall_no_relevant
Recall@k returns 0.0 when no relevant nodes exist
✅
T-458
test_load_eval_dataset_missing_file
Missing eval dataset file returns error
✅
T-459
test_query_archetype_serde_roundtrip
All QueryArchetype enums serialize and deserialize correctly
✅
T-460
test_eval_empty_dataset
Empty eval dataset produces zero metrics
✅
Features: MCP tool registration; file system tools (sandboxed); index query tools;
engine management tools; transport (stdio + SSE).
ID
Test
Description
Status
T-461
test_resolve_sandboxed_allows_valid_path
Valid paths inside repo root are resolved successfully
✅
T-462
test_resolve_sandboxed_empty_path_returns_root
Empty path resolves to repository root
✅
T-463
test_resolve_sandboxed_nonexistent_path
Nonexistent paths return error
✅
T-464
test_resolve_sandboxed_rejects_dotdot
Paths containing .. are rejected as escaping sandbox
✅
mcp/tools/filesystem (planned module)
ID
Test
Description
Status
T-226
✅ test_list_directory_returns_files_and_dirs
list_directory at repo root returns known files and subdirectories with correct types
✅
T-227
✅ test_list_directory_rejects_path_escape
list_directory with ../ path returns path_escape error
✅
T-228
✅ test_read_file_returns_content
read_file for a known file returns its full content with correct line count
✅
T-229
✅ test_read_file_line_range
read_file with line_start and line_end returns only the specified lines
✅
T-230
✅ test_read_file_rejects_binary
read_file on a binary file returns binary_file error with detected MIME type
✅
T-231
✅ test_read_file_truncates_large_content
read_file on a file exceeding max lines returns truncated: true
✅
T-232
✅ test_get_directory_tree_respects_depth
get_directory_tree with depth=1 returns only immediate children
✅
T-233
✅ test_get_directory_tree_respects_gitignore
get_directory_tree excludes paths matched by .gitignore
✅
mcp/tools/search (planned module)
ID
Test
Description
Status
T-286
✅ test_search_symbols_returns_ranked_results
search_symbols with FTS query returns BM25-ranked results with expected fields
✅
T-287
✅ test_lookup_symbol_by_qualified_name
lookup_symbol returns exact match(es) for a known qualified name
✅
T-260
✅ test_search_symbols_filters_by_type_and_language
search_symbols with node_type and language filters restricts results correctly
✅
mcp/tools/navigation (planned module)
ID
Test
Description
Status
T-261
✅ test_get_symbol_returns_full_metadata
get_symbol returns all node fields including access modifier and return type
✅
T-288
✅ test_get_callers_returns_incoming_call_edges
get_callers returns nodes with Calls edges pointing to the target
✅
T-289
✅ test_get_file_outline_returns_symbols_in_order
get_file_outline returns symbols ordered by line number
✅
T-290
✅ test_get_implementations_returns_implements_and_extends
get_implementations returns both Implements and Extends incoming edges
✅
T-465
test_get_symbol_invalid_uuid
Invalid UUID node_id returns INVALID_PARAMETER error
✅
mcp/tools/management (planned module)
ID
Test
Description
Status
T-291
✅ test_index_files_triggers_pipeline
index_files with valid paths runs the ingest pipeline and updates the graph
✅
T-292
✅ test_get_status_returns_accurate_counts
get_status returns correct indexed_files, indexed_symbols, and watcher_active
✅
T-466
test_index_files_rejects_empty_paths
Empty paths array is rejected with INVALID_PARAMETER
✅
T-467
test_index_files_rejects_too_many_paths
More than 100 paths rejected with INVALID_PARAMETER
✅
Features: WAL performance; large-repo stress; adversarial encodings; generated-code dampening;
concurrent read/write safety.
ID
Test
Description
Status
T-293
test_default_logs_exclude_prompt_and_source
With default log config, debug_content_logging defaults to false — prevents leaking content
✅
T-294
test_debug_content_logging_gated_by_opt_in
Content logging only enabled when explicitly set via config flag; defaults to off
✅
IPC retry & error classification
ID
Test
Description
Status
T-469
test_ipc_child_exited_is_retryable
IpcChildExited classified as retryable (respawn will fix it)
✅
T-470
test_ipc_timeout_is_retryable
IpcTimeout classified as retryable (temporary overload)
✅
T-471
test_ipc_oom_restart_is_retryable
IPC error with code -32104 (OomRestart) classified as retryable
✅
T-472
test_ipc_version_mismatch_is_not_retryable
IpcVersionMismatch classified as non-retryable (fundamental incompatibility)
✅
T-473
test_cancelled_is_not_retryable
Cancelled classified as non-retryable (explicit cancellation)
✅
T-474
test_ipc_semantic_unavailable_is_not_retryable
IPC error -32100 classified as non-retryable (deterministic)
✅
T-475
test_ipc_project_load_failed_is_not_retryable
IPC error -32101 classified as non-retryable (deterministic)
✅
T-476
test_ipc_plugin_blocked_is_not_retryable
IPC error -32102 classified as non-retryable (safe mode)
✅
T-477
test_non_ipc_errors_are_not_retryable
Non-IPC errors (NotInitialized, WriteQueueFull, etc.) all classified as non-retryable
✅
T-478
test_ipc_retry_defaults
Default ipc_max_retries=2 and ipc_retry_base_delay_ms=500
✅
T-479
test_ipc_retry_config_from_json
JSON config overrides for retry fields parse correctly
✅
T-480
test_ipc_retry_config_defaults_when_omitted
Missing retry fields in JSON default to expected values
✅
T-481
test_ipc_retry_zero_disables_retry
Setting ipc_max_retries=0 disables retry
✅
ID
Test
Description
Status
T-234
test_large_file_creates_file_node_and_metadata
1 000-method file → file node emitted; method spans have file_path and line numbers
✅
T-235
test_cyclic_call_graph_traversal_terminates
A→B→C→A call graph → WITH RECURSIVE query terminates via UNION dedup; returns bounded results
✅
T-236
test_2000_near_identical_methods_indexed
2 000 methods with near-identical bodies indexed; FTS search returns bounded results
✅
T-237
test_wal_concurrent_read_write_no_data_loss
Concurrent writer + 4 read connections under load; all reads observe consistent snapshots (#[ignore])
✅
T-238
test_mixed_encoding_bom_stripped_before_hashing
UTF-8 BOM stripped before parsing/hashing; chunk_hash matches BOM-free equivalent
✅
T-239
test_generated_code_glob_applies_penalty
Generated node gets generated = 1; retrieval score receives multiplicative ×0.3 penalty
✅
T-240
test_rename_class_and_file_uuid_reused
Class + file renamed → journal entry + node_identity_map links old→new (unit + integration)
✅
T-241
test_10k_file_write_throughput
Index 10 000 files via writer; completes within 60s (#[ignore])
✅
T-295
test_reader_pool_connections_set_required_pragmas
Every reader pool connection has foreign_keys = ON, busy_timeout = 5000, and correct mmap_size
✅
T-296
test_disk_full_returns_structured_error
Write failure on read-only file → structured CoreError with meaningful message
✅
T-297
test_mcp_tool_error_returns_structured_json
MCP tool error → ErrorData with NOT_FOUND code and descriptive message
✅
T-427
test_cancellation_rolls_back_uncommitted_writes
Writer thread rolls back uncommitted transaction when CancellationToken fires before COMMIT; no partial results persisted
✅
T-428
test_writer_connection_has_foreign_keys_on
Writer connection has PRAGMA foreign_keys = ON (complements T-295 which tests reader pool)
✅
Multi-file fixture project tests (integration)
Tests that index small multi-file C# and TypeScript projects and verify the full
graph output. Located in tests/fixture_tests.rs with fixtures under
tests/fixtures/{csharp_project,typescript_project}/.
ID
Test
Description
Status
T-300
test_cs_fixture_file_nodes
6 .cs files → 6 file nodes
✅
T-301
test_cs_fixture_module_nodes
2 namespaces deduplicated across 6 files → 2 module nodes
✅
T-302
test_cs_fixture_class_nodes
User, Address (struct), UserService → 3 class nodes
✅
T-303
test_cs_fixture_interface_nodes
IEntity, IUserService → 2 interface nodes
✅
T-304
test_cs_fixture_type_nodes
Status enum → 1 type node
✅
T-305
test_cs_fixture_constructor_nodes
User(string), User(string,string) → 2 constructor nodes
✅
T-306
test_cs_fixture_method_nodes
12 method nodes across all files
✅
T-307
test_cs_fixture_property_nodes
7 property nodes across all files
✅
TypeScript fixture — node census
ID
Test
Description
Status
T-308
test_ts_fixture_file_nodes
6 .ts files → 6 file nodes
✅
T-309
test_ts_fixture_type_nodes
UserId, UserRole, Status → 3 type nodes
✅
T-310
test_ts_fixture_interface_nodes
IEntity, IUserService → 2 interface nodes (body not walked)
✅
T-311
test_ts_fixture_class_nodes
User, UserServiceImpl → 2 class nodes
✅
T-312
test_ts_fixture_method_nodes
12 method nodes (class methods + top-level functions)
✅
T-313
test_ts_fixture_property_nodes
6 property nodes (class fields + constants)
✅
Symbol keys and qualified names
ID
Test
Description
Status
T-314
test_cs_fixture_qualified_names
User and UserService have fully-qualified symbol keys with namespace prefix
✅
T-315
test_cs_fixture_overloaded_methods_distinct_keys
GetDisplayName(0) and GetDisplayName(1) have distinct symbol keys
✅
T-316
test_cs_fixture_overloaded_constructors_distinct_keys
User(string) and User(string,string) have distinct symbol keys
✅
T-317
test_cs_fixture_struct_is_class_node
Address struct stored as class node
✅
T-318
test_cs_fixture_enum_is_type_node
Status enum stored as type node
✅
ID
Test
Description
Status
T-319
test_cs_fixture_namespace_contains_class
Module(SampleApp.Models) → Contains → User, Address, IEntity, Status
✅
T-320
test_cs_fixture_class_contains_methods
Class(User) → Contains → GetDisplayName, Validate
✅
T-321
test_ts_fixture_file_contains_symbols
File(utils.ts) → Contains → formatName, capitalize, internalHelper, MAX_USERS
✅
T-322
test_ts_fixture_class_contains_methods
Class(User) → Contains → constructor, getDisplayName, toJSON
✅
ID
Test
Description
Status
T-323
test_cs_fixture_fts_search_finds_user
FTS query "User" returns User class
✅
T-324
test_ts_fixture_fts_search_finds_function
FTS query "formatName" returns the function
✅
T-325
test_cs_fixture_fts_by_qualified_name
FTS query "SampleApp.Models"* returns namespace members
✅
ID
Test
Description
Status
T-326
test_cs_fixture_delete_file_removes_symbols
Delete Address.cs → class + 3 properties + file gone; others remain
✅
T-327
test_cs_fixture_delete_preserves_shared_namespace
Delete Status.cs → SampleApp.Models module survives (span from Address.cs)
✅
T-328
test_ts_fixture_delete_file_removes_symbols
Delete utils.ts → 4 symbols + file gone; other files unaffected
✅
ID
Test
Description
Status
T-329
test_cs_fixture_detects_csproj
detect_projects() finds SampleApp.csproj with language=CSharp
✅
T-330
test_ts_fixture_detects_package_json
detect_projects() finds package.json with display_name=sample-ts-app
✅
ID
Test
Description
Status
T-331
test_cs_fixture_outline_user_file
get_outline() for User.cs returns class, properties, constructors, methods
✅
T-332
test_ts_fixture_outline_utils_file
get_outline() for utils.ts returns formatName, capitalize, internalHelper, MAX_USERS
✅
Flags and access modifiers
ID
Test
Description
Status
T-333
test_cs_fixture_private_method_not_public_api
User.Validate has is_public_api=false
✅
T-334
test_cs_fixture_static_method
UserService.Create has is_static=true
✅
T-335
test_cs_fixture_async_method
UserService.RefreshAsync has is_async=true
✅
T-336
test_ts_fixture_export_scope_module
formatName has export_scope=module
✅
T-337
test_ts_fixture_export_scope_file
internalHelper has export_scope=file
✅
ID
Test
Description
Status
T-338
test_ts_fixture_reindex_idempotent
TS fixture indexed twice → same node count (deterministic FileId)
✅
T-468
test_cs_fixture_reindex_idempotent
Re-indexing same C# fixture produces identical node count
✅
Project detection sequencing
ID
Test
Description
Status
T-429
test_project_detection_before_indexing_assigns_correct_project_id
Running detect_projects + ensure_projects_in_db before indexing assigns detected project_id (not root) to symbols
✅
Real-world open-source repository indexing and query tests. Tests against tRPC (TypeScript,
v11.10.0) and Hot Chocolate graphql-platform (C#, 15.1.12) at pinned commits. Gated behind
cargo test --features oss-tests. Cached DBs reused across tests for fast iteration.
Tier 0 — Baseline Indexing
ID
Test
Description
Status
T-339
test_oss_trpc_typescript_indexing
tRPC repo indexes with low error rate; node census meets thresholds; FTS finds key symbols; no duplicate symbol keys
✅
T-340
test_oss_hotchocolate_csharp_indexing
Hot Chocolate repo indexes with low error rate; node census meets thresholds; FTS finds key symbols; no duplicate symbol keys
✅
T-341
test_oss_trpc_idempotent_reindex
Re-indexing tRPC produces identical node count as first pass
✅
T-342
test_oss_hotchocolate_idempotent_reindex
Re-indexing Hot Chocolate produces identical node count as first pass
✅
Tier 1 — Basic Navigation
ID
Test
Description
Status
T-343
test_oss_trpc_lookup_symbol_by_qualified_name
Lookup discovered method by qualified name returns correct node with matching language
✅
T-344
test_oss_trpc_file_outline_ordered_by_line
File outline is non-empty, ordered by line_start, excludes file and project nodes
✅
T-345
test_oss_trpc_fts_search_known_name
FTS search for discovered method display name returns results with rank
✅
T-346
test_oss_trpc_neighbors_contains
Container node has non-empty outgoing contains edges, all typed Contains
✅
T-347
test_oss_trpc_neighbors_implements
Interface has incoming implements edges (skips gracefully if none in Phase 1 TS)
✅
T-348
test_oss_hc_lookup_symbol_by_qualified_name
Lookup discovered C# method by qualified name returns correct node
✅
T-349
test_oss_hc_file_outline_ordered_by_line
C# file outline is non-empty, ordered by line_start, excludes file and project nodes
✅
T-350
test_oss_hc_fts_search_known_name
FTS search for discovered C# method display name returns results with rank
✅
T-351
test_oss_hc_neighbors_contains
C# container has non-empty outgoing contains edges
✅
T-352
test_oss_hc_neighbors_implements
C# interface has incoming implements edges (skips if none)
✅
Tier 2 — Complex Queries and Stress
ID
Test
Description
Status
T-353
test_oss_trpc_multihop_interface_methods
2-hop: interface → implementors → their methods (skips if no implements)
✅
T-354
test_oss_trpc_multihop_callers_file
3-hop: method → callers → caller file_path (skips if no calls edges)
✅
T-355
test_oss_trpc_transitive_contains
Transitive closure from module: result >= direct children, no duplicate node IDs
✅
T-356
test_oss_trpc_fts_common_terms_bounded
FTS search for 5 common terms each returns <=50 results in <5s
✅
T-357
test_oss_trpc_outline_all_files_no_panics
Outline up to 200 files with no panics, <5000 symbols per file
✅
T-358
test_oss_trpc_filter_combined_criteria
Combined filter: language + node_type + FTS query returns matching results
✅
T-359
test_oss_hc_multihop_interface_methods
2-hop: C# interface → implementors → methods; asserts non-empty
✅
T-360
test_oss_hc_multihop_callers_file
3-hop: C# method → callers → file_path
✅
T-361
test_oss_hc_transitive_contains
Transitive closure from C# namespace: result >= direct children, no dupes
✅
T-362
test_oss_hc_fts_common_terms_bounded
FTS search for 5 common C# terms each returns <=50 results in <5s
✅
T-363
test_oss_hc_outline_all_files_no_panics
Outline up to 500 C# files with no panics, <5000 symbols per file
✅
T-364
test_oss_hc_filter_combined_criteria
Combined filter: C# language + Class + FTS query returns matching results
✅
ID
Test
Description
Status
T-365
test_oss_trpc_benchmarks
5 benchmarks (symbol lookup, FTS, neighbors, outline, transitive) on tRPC DB
✅
T-366
test_oss_hc_benchmarks
5 benchmarks (symbol lookup, FTS, neighbors, outline, transitive) on HC DB
✅
Tier 4 — Pipeline Benchmarks
End-to-end pipeline tests that run initial indexing, incremental reindex, and (for HC)
a touched-file reindex across multiple projects. Gated behind --features oss-tests.
Semantic enrichment paths (IPC, solution load, minimal solution reload) only exercise
when the corresponding extractor is found on the system: CodeAgentExtractor.dll for
C# (Roslyn), dist/index.js for TypeScript, and codeagent-rust-extractor for Rust.
Without extractors, tests still pass but skip semantic assertions. Run 10–30 minutes;
use run_in_background and poll.
ID
Test
Description
Status
T-482
test_oss_trpc_pipeline_benchmark
Full tRPC pipeline: initial index + idempotent reindex with content-hash skip; integrity checks (dup edges, FTS, orphans)
✅
T-483
test_oss_hc_pipeline_benchmark
Full HC pipeline: initial index + idempotent reindex + touched-file reindex (60 files across 10 projects exercises minimal solution reload); integrity checks and node stability across 3 passes
✅
T-484
test_oss_rust_analyzer_pipeline_benchmark
Full rust-analyzer pipeline (Rust, ~1435 .rs files, ~50 crates): initial index + idempotent reindex with content-hash skip; node census (methods, structs, traits, modules), integrity checks, semantic enrichment when extractor available
✅
Hooks, Dead Code Detection & Init
PageRank computation, dead code detection, Claude Code hook handlers, and CLI init command.
Tests span codeagent-core (graph/ranking, query/dead_code) and codeagent-cli (init).
PageRank (graph/ranking.rs)
ID
Test
Description
Status
T-367
test_pagerank_star_topology
Star graph: hub node called by 5 callers ranks highest
✅
T-368
test_pagerank_linear_chain
Chain A→B→C: B (both in-degree and out-degree) outranks A
✅
T-369
test_pagerank_isolated_node
Isolated node (no edges) does not appear in edge-based PageRank results
✅
T-370
test_pagerank_empty_graph
Empty graph (no edges) returns empty results
✅
T-371
test_pagerank_summary_returns_nodes
get_pagerank_summary returns full Node objects with display names and positive scores
✅
Dead code detection (query/dead_code.rs)
ID
Test
Description
Status
T-372
test_dead_code_uncalled_method
Method with zero incoming Calls/References is detected as dead code
✅
T-373
test_dead_code_constructor_excluded
Constructor excluded from dead code by default (entry point)
✅
T-374
test_dead_code_public_api_filtering
Public API method excluded by default, included when include_public_api=true
✅
T-375
test_dead_code_override_excluded
Override method excluded from dead code (interface implementations are not dead)
✅
T-376
test_dead_code_called_method_not_dead
Method called by another method is NOT flagged as dead code
✅
T-377
test_dead_code_cross_file
Method in file A with no callers from any file is detected as dead
✅
T-378
test_count_dead_code_matches
count_dead_code returns same count as find_dead_code().len()
✅
Init command (codeagent-cli/init.rs)
ID
Test
Description
Status
T-379
test_init_creates_directory_and_config
Creates .codeagent/ dir, config.json, index.db, and .claude/settings.json
✅
T-380
test_init_idempotent
Running init twice does not duplicate hooks or corrupt config
✅
T-381
test_init_preserves_existing_settings
Preserves existing .claude/settings.json content while adding hooks
✅
T-382
test_init_gitignore_entry
Adds .codeagent/index.db to .gitignore without duplicating on re-run
✅
CLI output (codeagent-cli)
ID
Test
Description
Status
T-430
✅ test_cli_commands_produce_valid_json
All CLI subcommands that output JSON produce valid JSON (requires subprocess invocation or refactoring command logic into testable functions)
✅
ASP.NET Core API Boundary Support
Features: API endpoint detection, route/auth/request/response metadata extraction from tree-sitter
and Roslyn, api_endpoints table (Migration 004), MCP search_api_endpoints tool, endpoint
enrichment on get_symbol and get_file_outline.
graph/api_endpoints (schema + CRUD)
ID
Test
Description
Status
T-383
test_migration_004_creates_api_endpoints_table
Migration 004 creates api_endpoints table in SQLite
✅
T-384
test_upsert_and_get_roundtrip
Upsert an endpoint then read it back with all fields matching
✅
T-385
test_upsert_replaces_existing_row
Upsert same node_id twice replaces old row; only one row exists
✅
T-386
test_search_by_http_method
search_api_endpoints with http_method=GET returns only GET endpoints
✅
T-387
test_search_by_route_pattern
search_api_endpoints with route_pattern substring matches correct routes
✅
T-388
test_search_by_controller_id
search_api_endpoints with controller_id filter returns only that controller's endpoints
✅
T-389
test_delete_api_endpoints_for_file
Deleting endpoints for a file path removes correct rows, preserves others
✅
T-390
test_on_delete_cascade_removes_endpoint
Deleting a node hard-removes its api_endpoints row via ON DELETE CASCADE
✅
T-391
test_get_api_endpoints_for_file
Batch load returns all endpoints for nodes in a given file
✅
T-392
test_search_limit_capped_at_50
Requesting limit=100 is capped to 50 rows returned
✅
T-393
test_get_nonexistent_endpoint_returns_none
Looking up a random node_id returns None
✅
T-394
test_api_style_roundtrip
All ApiStyle variants round-trip through as_str/from_str
✅
adapters/csharp (ASP.NET tree-sitter extraction)
ID
Test
Description
Status
T-395
test_aspnet_basic_api_controller_httpget
Basic [ApiController] + [HttpGet] produces api_endpoints row with GET method
✅
T-396
test_aspnet_all_http_methods
[HttpGet/Post/Put/Delete/Patch] each produce correct http_method values
✅
T-397
test_aspnet_route_resolution_with_controller_token
[Route("api/[controller]")] + [HttpGet("{id}")] resolves to api/users/{id}
✅
T-398
test_aspnet_auth_extraction
[Authorize(Policy="Admin")] and [AllowAnonymous] produce correct auth_policy
✅
T-399
test_aspnet_from_body_parameter
[FromBody] parameter type extracted as request_body_type
✅
T-400
test_aspnet_response_type_from_action_result
ActionResult and Task<ActionResult> unwrapped to response_type
✅
T-401
test_aspnet_non_controller_class_no_endpoints
Class without [ApiController] or ControllerBase produces no api_endpoints
✅
T-402
test_aspnet_class_without_api_controller_attribute_no_endpoints
Class without [ApiController] attribute and not inheriting ControllerBase produces no endpoints
✅
T-403
test_aspnet_controller_base_inheritance_without_attribute
Class inheriting ControllerBase (no [ApiController]) still detected as controller
✅
T-404
test_resolve_route_template_combinations
Unit test for route template resolution helper with various inputs
✅
T-405
test_extract_response_type_from_return_type
Unit test for response type extraction from Task<ActionResult> strings
✅
T-406
test_unwrap_generic
Unit test for generic type unwrapping helper
✅
ipc/protocol (API endpoint IPC backward compat)
ID
Test
Description
Status
T-407
test_semantic_node_with_api_endpoint_deserializes
SemanticNode JSON with api_endpoint field deserializes correctly
✅
T-408
test_semantic_node_without_api_endpoint_backward_compat
SemanticNode JSON missing api_endpoint deserializes as None
✅
T-409
test_semantic_node_api_endpoint_omitted_in_serialization_when_none
Serializing SemanticNode with api_endpoint=None omits the field
✅
mcp/tools/search (search_api_endpoints tool)
ID
Test
Description
Status
T-410
test_search_api_endpoints_returns_results
search_api_endpoints returns endpoint+method JSON with all fields
✅
T-411
test_search_api_endpoints_filters_by_route
search_api_endpoints with route_pattern returns matching endpoints only
✅
T-412
test_search_api_endpoints_empty_filters_returns_all
search_api_endpoints with no filters returns all endpoints up to limit
✅
mcp/tools/navigation (endpoint enrichment on get_symbol/get_file_outline)
ID
Test
Description
Status
T-413
test_get_symbol_includes_api_endpoint
get_symbol for an action method includes api_endpoint field with metadata
✅
T-414
test_get_symbol_omits_api_endpoint_when_absent
get_symbol for a non-endpoint method omits api_endpoint field
✅
T-415
test_get_file_outline_includes_api_endpoint
get_file_outline includes api_endpoint on action methods, omits on helpers
✅
Test harness prerequisites (Phase 3+)
The following traits and test utilities are introduced for Phases 3–5 to enable TDD without
real network calls, ONNX models, or child processes:
✅ EmbeddingProvider trait (embedding/provider.rs) — real: ONNX EmbeddingModel; test: HashEmbeddingProvider (SHA-256 deterministic, L2-normalised, 384-dim, no model file)
⬜ Clock trait — real: system time; test: frozen clock for TTL and correlation-window tests
⬜ ChildProcessTransport trait — real: stdio JSON-RPC; test: in-memory scripted responder
⬜ TestRepoBuilder utility — creates temp repo with files, optional git init, and common project structures (.csproj, tsconfig.json, package.json)
⬜ TestDb helper — file-backed SQLite with extensions enabled (needed for sqlite-vec ANN integration tests in Phase 4a)
Pipeline integration (deferred)
These tests require a file-based SQLite database, start_writer_thread, DbReaderPool, a live
IpcManager, and #[tokio::test]. The cost of the test harness is high; they are deferred to a
dedicated integration-test phase.
ID
Test
Description
Status
T-242
✅ test_pipeline_full_index_csharp
Full ingest of a small C# project → correct nodes, edges, and FTS entries in DB
✅
T-243
✅ test_pipeline_incremental_update
Modify one file → only changed nodes updated; chunk_hash comparison skips unchanged
✅
T-244
✅ test_pipeline_semantic_enrichment_csharp
C# semantic pass via Roslyn extractor → parse_status = 'full', exact edges present
✅
T-245
✅ test_pipeline_semantic_enrichment_typescript
TS semantic pass via TS LS extractor → parse_status = 'full', exact edges present
✅
T-246
✅ test_pipeline_semantic_context_invalidation
.csproj change → semantic edges for affected project recomputed atomically
✅
T-247
✅ test_pipeline_rename_detection_end_to_end
Delete + create within debounce window → rename detected; node_id preserved
✅
T-248
✅ test_pipeline_delete_file_journals_and_cleans_up
Delete file → nodes hard-deleted; deletion journal written; FTS + edges removed
✅