# Axiom Relation Resolver Bug: Parent-Child BINDS_TO ## Summary The relation resolver fails to resolve `@RELATION BINDS_TO -> [ParentContractId]` when the target is a parent `#region` in the **same file** and the children are nested inside it. The parent contract exists in the index (`read_outline` shows it), but `search_contracts` does not return it — suggesting the parent fails to register in the graph, causing all child `BINDS_TO` edges to become `unresolved_relation`. **Impact:** ~550 of 638 `unresolved_relation` warnings (~86%). ## Reproduction ### File: `backend/src/api/routes/__tests__/test_assistant_api.py` ```python # #region AssistantApiTests [TYPE Module] [C:3] [SEMANTICS tests, assistant, api] # @BRIEF Validate assistant API endpoint logic via direct async handler invocation. # @RELATION DEPENDS_ON -> [AssistantApi] import asyncio ... # #region _run_async [TYPE Function] # @RELATION BINDS_TO -> [AssistantApiTests] ← unresolved_relation def _run_async(coro): return asyncio.run(coro) # #endregion _run_async # #region test_unknown_command_returns_needs_clarification [TYPE Function] # @RELATION BINDS_TO -> [AssistantApiTests] ← unresolved_relation def test_unknown_command_returns_needs_clarification(monkeypatch): ... # #endregion test_unknown_command_returns_needs_clarification ... (17 children total, all BINDS_TO flagged) # #endregion AssistantApiTests ``` ### Observations 1. **`read_outline` on the file** returns the parent `AssistantApiTests` correctly — it exists structurally. 2. **`search_contracts query="AssistantApiTests"`** returns ONLY the 8 children — the parent is NOT in results. 3. All 17 children have `@RELATION BINDS_TO -> [AssistantApiTests]` — all marked `unresolved_relation`. 4. The parent `#region AssistantApiTests` wraps the entire file, opens at line 4, closes at the last line. ### Checked hypotheses (ruled out) | Hypothesis | Ruled out by | |-----------|-------------| | `@TAG:` colon format breaks registration | Colon was there, but even after fixing 2216 colon instances across the codebase, the parent still doesn't register in the graph | | Brackets vs no-brackets in `BINDS_TO` syntax | Both `-> AssistantApiTests` (no brackets) and `-> [AssistantApiTests]` (with brackets) fail identically | | `@INVARIANT:` tag parsing failure | The colon in tags was normalized, but other parents without that tag also fail | | Duplicate relation edges | Removed duplicates from auth.py; test files have no duplicates | | Tag forbidden by complexity | Config now allows ALL tags at ALL tiers (C1-C5) | ### Likely root cause The relation graph builder processes the parent `#region` at file-open time but the children's `BINDS_TO` references are resolved **before** the parent node is fully registered in the graph. This is a timing/order-of-operations issue in the Rust parser. Alternatively: when the parent contract's body contains code (imports, helper functions) mixed with metadata, the parser may consider the parent "not a valid contract" and skip it, making all child references dangling. ### Affected files (same pattern) ``` backend/src/api/routes/__tests__/test_assistant_api.py — 17 children → AssistantApiTests backend/src/api/routes/__tests__/test_assistant_authz.py — 3 children → TestAssistantAuthz backend/src/api/routes/__tests__/test_clean_release_api.py — 4 children → TestCleanReleaseApi backend/src/api/routes/__tests__/test_clean_release_legacy_compat.py — 2 children backend/src/api/routes/__tests__/test_clean_release_source_policy.py — 2 children backend/src/api/routes/__tests__/test_clean_release_v2_api.py — 3 children backend/src/api/routes/__tests__/test_clean_release_v2_release_api.py — 3 children backend/src/api/routes/__tests__/test_dashboards.py — 25 children → DashboardsApiTests backend/tests/core/test_defensive_guards.py — 2 children → UnknownModule ... and more across the codebase (~550 total) ``` ### Expected behavior If a child contract is nested inside a parent `#region`/`#endregion` pair and the child has `@RELATION BINDS_TO -> [ParentId]`, the resolver should: 1. Register the parent contract `ParentId` in the graph 2. Resolve `BINDS_TO -> [ParentId]` as a valid edge pointing to `ParentId` ### Fix suggestion In the Rust relation resolver (`axiom-mcp-server-rs`): - When processing a file, register parent contracts **before** resolving their children's relation edges - Ensure the parent node is added to the graph even if it contains code blocks between its opening anchor and first metadata tag