feat: stable symbol handles across reindexing and agent context compaction #37
Labels
No labels
code-review
correctness
dos
performance
security
severity/high
severity/low
severity/medium
tech-debt
Kind/Breaking
Kind/Bug
Kind/Documentation
Kind/Enhancement
Kind/Feature
Kind/Security
Kind/Testing
Priority
Critical
Priority
High
Priority
Low
Priority
Medium
Reviewed
Confirmed
Reviewed
Duplicate
Reviewed
Invalid
Reviewed
Won't Fix
Status
Abandoned
Status
Blocked
Status
Need More Info
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
h-dv/code-index#37
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Product
Give agents a durable symbol identity that survives daemon restarts, ordinary reindexing, edits that move a symbol, and context compaction. Numeric
symbol_idremains the fast project-local lookup key, but must not be the durable agent contract.Why
Long-running coding agents pass symbol handles between planning, editing, review, subagents, and later sessions. Current numeric IDs may change after a rebuild or migration. A stale ID can fail closed, or worse, identify a different row. This becomes a prerequisite for trustworthy
context_pack(#35), durable review findings (#34), and saved evidence trails.Proposed handle
A versioned opaque encoding derived from:
The wire representation should be opaque and versioned so its internals can evolve.
Resolution contract
Add
stable_handleto symbol-bearing responses and a resolver that reports one of:exactmoved_or_changedwith explicit evidenceambiguouswith candidatesmissingNever silently choose an ambiguous candidate. Project routing must be explicit, and old handle versions must either remain readable or return a structured upgrade error.
Boundaries
Acceptance
moved_or_changedor ambiguity, never false exactnessmissingcontext_pack,review_diff, and existing symbol drill-down toolsTriage: P1 prerequisite for the agent workflow
Land before, or as the first track of,
context_pack(#35). Keep the first version deliberately structural and deterministic. A handle must fail honestly under ambiguity rather than becoming a fuzzy search token.Implementation should separate the stable external identity from the current-generation numeric ID so existing hot paths remain cheap.
Shipped in v0.7.0 (mission I031).
What landed
Versioned durable handle
cih1_<base64url(payload)>— the payload is a unit-separated join of five stored-column-derived fields:project | path | identity_name | kind | fingerprint. Because it's derived from existing columns there is no schema change, so a healed DB and a fresh index emit byte-identical handles (migration ≡ fresh-index, trivially). The codec lives dependency-free incode_index_core::handle(FNV-1a + base64url inlined) and is shared by both the MCP emit/route side and the daemon resolve side.identity_name=qualified_namewhen present, else the barename(resolver applies the same fallback so legacy NULL-qualified_namerows round-trip).fingerprint= 16 hex of FNV-1a over the whitespace-normalized signature. It is signature-shaped, not body-shaped: survives body-only edits and line moves, flips on a signature/shape change.Resolution contract (
resolve_handle→ daemonresolve_symbol_identity, run against exactly one project, routed by the key inside the handle — a handle for project A can never resolve against project B):signature_changed,path_changed, orrenamed. Renames require a non-empty fingerprint corroboration (a NULL-signature symbol can never vacuously "rename-match").unsupported_handle_version; corrupt body →malformed_handle. Never a guess.stable_handleis now stamped at the MCP boundary (where routing is authoritative) onsearch_symbols,get_symbol, andfile_outline, plus context_pack targets/dependents. The numericidstays as the cheap generation-local drill-down key.Acceptance criteria — all met
exactafter a full rebuild with different numeric idsexactmoved_or_changedwith explicit evidence, never a falseexactmissingambiguous, never arbitraryReview
Deep adversarial review (13 agents: 7 confirmed / 2 refuted), all confirmed findings fixed with reproduction-backed regression tests. Headline catch — the exact hazard this system exists to prevent:
get_symbol(path:line)/file_outlinewere stamping handles with the requested project key while absolute paths auto-route to linked projects, so a handle decodedproject="primary"and resolved against the wrong index. Fixed:routed_index_for_pathnow returns the resolved project key and both stamp sites use it. Also fixed: the vacuous NULL-signature false-rename above.Deferred (honest):
stable_handleis not yet stamped onchange_impact/review_diff/changed_symbols/refactorresponses — those still carry numeric ids + paths. That stamping is purely additive and non-blocking for this issue; tracked as a follow-up.Closing as done.