Skip to content

Orphan Todo declarations persist after incremental invalidation #718

@st0012

Description

@st0012

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:

  1. Are never promoted because the real definition re-resolves under its correct FQN
  2. Get singleton classes created on them (via get_or_create_singleton_class during ancestor linearization)
  3. Are never cleaned up

Attempted fixes

  1. 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.

  2. 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

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions