Summary
The incremental consistency test fails on Rails due to orphan <TODO> declarations that exist in the incremental graph but not in the fresh graph.
Found by the incremental consistency testing tool: incremental_test ../../../rails/rails --seed 42 --cycles 1
Extra declarations (incremental only)
Aes256Gcm (<TODO>)
Aes256Gcm::<Aes256Gcm> (SingletonClass)
Buffer (<TODO>)
Buffer::<Buffer> (SingletonClass)
DateSelect (<TODO>)
DateSelect::<DateSelect> (SingletonClass)
TextField (<TODO>)
Root cause
name_owner_id (resolution.rs:1097) converts Retry(None) from resolve_constant_internal to Unresolved(None), which triggers create_todo_for_parent. This means a temporarily-unresolvable parent (name exists but hasn't resolved yet in this convergence pass) is treated identically to a genuinely unknown parent.
In fresh builds, this creates orphan Todos that are harmless — the real declarations resolve correctly alongside them, and both builds have the same Todos.
In incremental builds (delete + re-add), the delete-phase resolution creates Todos that:
- Are never promoted because the real definition re-resolves under its correct FQN
- Get singleton classes created on them (via
get_or_create_singleton_class during ancestor linearization)
- Are never cleaned up
Attempted fixes
-
Propagate Retry(None) instead of converting to Unresolved(None): Breaks 7 todo_tests — resolve_constant_internal returns Retry(None) for BOTH "name unresolved" and "member not found", so they can't be distinguished at the name_owner_id level.
-
Skip get_or_create_singleton_class on Todo declarations: Causes panic in singleton_parent_id — ancestor linearization needs singleton classes even on Todos when a real class inherits from a Todo.
Possible fix directions
- Add a disambiguation mechanism so
name_owner_id can tell "parent name exists but unresolved" (retry) from "parent genuinely missing" (create Todo)
- Post-resolution cleanup: remove Todo declarations that coexist with a real declaration of the same unqualified name under the correct owner
- Track whether resolution is in "delete-phase" vs "normal" and suppress Todo creation during delete-phase
Summary
The incremental consistency test fails on Rails due to orphan
<TODO>declarations that exist in the incremental graph but not in the fresh graph.Found by the incremental consistency testing tool:
incremental_test ../../../rails/rails --seed 42 --cycles 1Extra declarations (incremental only)
Root cause
name_owner_id(resolution.rs:1097) convertsRetry(None)fromresolve_constant_internaltoUnresolved(None), which triggerscreate_todo_for_parent. This means a temporarily-unresolvable parent (name exists but hasn't resolved yet in this convergence pass) is treated identically to a genuinely unknown parent.In fresh builds, this creates orphan Todos that are harmless — the real declarations resolve correctly alongside them, and both builds have the same Todos.
In incremental builds (delete + re-add), the delete-phase resolution creates Todos that:
get_or_create_singleton_classduring ancestor linearization)Attempted fixes
Propagate
Retry(None)instead of converting toUnresolved(None): Breaks 7 todo_tests —resolve_constant_internalreturnsRetry(None)for BOTH "name unresolved" and "member not found", so they can't be distinguished at thename_owner_idlevel.Skip
get_or_create_singleton_classon Todo declarations: Causes panic insingleton_parent_id— ancestor linearization needs singleton classes even on Todos when a real class inherits from a Todo.Possible fix directions
name_owner_idcan tell "parent name exists but unresolved" (retry) from "parent genuinely missing" (create Todo)