Files
ss-tools/axiom-resolver-bug-report.md
2026-05-26 09:30:41 +03:00

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