Shopify / Shopify/rubydex

Orphan Todo declarations persist after incremental invalidation

Open
#718 1 comment 0 reactions 1 assignee View on GitHub

@st0012 is already working on this.

Since Apr 2, 2026.

Dominant language
Rust
Stars
355
Forks
24
Avg merge
2d 6h
Merged PRs (30d)
17

Description

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

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.