86 lines
4.5 KiB
Markdown
86 lines
4.5 KiB
Markdown
# 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
|