astral-sh/ruff · error

every TDD constraint should have a source order

Error message

every TDD constraint should have a source order

What it means

`PathBounds::compute` walks the BDD's satisfying paths and sorts each path's constraints by their position in a registered source-order set (`source_orders: FxIndexSet<ConstraintId>`). The expect asserts every positive constraint encountered on a path has a registered source order; it fires when the path walker visits constraints the registration set does not contain.

Source

Thrown at crates/ty_python_semantic/src/types/constraints.rs:3744

impl Debug for NodeId {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let mut f = f.debug_tuple("Node");
        match self.node() {
            // We use format_args instead of rendering the strings directly so that we don't get
            // any quotes in the output: ScopedReachabilityConstraintId(AlwaysTrue) instead of
            // ScopedReachabilityConstraintId("AlwaysTrue").
            Node::AlwaysTrue => f.field(&format_args!("AlwaysTrue")),
            Node::AlwaysFalse => f.field(&format_args!("AlwaysFalse")),
            Node::Interior(_) => f.field(&self.0),
        };
        f.finish()
    }
}

impl std::ops::Add<usize> for NodeId {
    type Output = NodeId;

    fn add(self, rhs: usize) -> Self::Output {
        NodeId::from_usize(self.index() + rhs)
    }
}

impl Idx for NodeId {
    #[inline]
    fn new(value: usize) -> Self {
        Self::from_usize(value)
    }

    #[inline]
    fn index(self) -> usize {
        debug_assert!(!self.is_terminal());
        self.0 as usize
    }
}

View on GitHub (pinned to 15f3fe6b15)

Solutions

  1. Register every constraint in `source_orders` at the single point where it is added to the storage the walker will traverse.
  2. If registration can legitimately miss, return a deterministic fallback order (insert on miss) behind a debug assertion and investigate the miss.
  3. Add a regression mdtest with the constraint shape that panicked and run `cargo nextest run -p ty_python_semantic --test mdtest`.
  4. Report upstream with the fixture if stock ty panics.

Example fix

// before: constraint added to storage only
let constraint = storage.add_constraint(db, c);

// after: keep path ordering registration in lockstep
let constraint = storage.add_constraint(db, c);
source_orders.insert(constraint);
Defensive patterns

Strategy: try-catch

Try / catch

let bounds = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
    PathBounds::compute(db, env, storage, node, inferable, source_order)
}))
.unwrap_or_else(|_| PathBounds::Unconstrained); // conservative fallback

Prevention

When it happens

Trigger: Computing per-path typevar bounds (assignability checks, bound narrowing) where a constraint on a path was never inserted into `self.source_orders` - e.g. constraints added during folding without registration, or a source-order set rebuilt/compacted differently than the path walker expects.

Common situations: Contributions to constraint ordering/determinism machinery (new constraint producers, compaction changes); surfaces in ordering-sensitive mdtests and the constraint-order wobble tests rather than normal checks.

Related errors


AI-assisted analysis of astral-sh/ruff@15f3fe6b15 (2026-08-20). Data as JSON: /api/errors/08fff8a7d5bea8d0. Report an issue: GitHub.