Skip to content

fix(stratify): report negative cycles with a stable predicate pair (#410) - #419

Merged
adityamukho merged 1 commit into
mainfrom
fix/410-stable-cycle-error
Sep 26, 2026
Merged

adityamukho merged 1 commit into
mainfrom
fix/410-stable-cycle-error

Conversation

@adityamukho

Copy link
Copy Markdown
Collaborator

Summary

Closes #410.

stratify() walked the rule dependency graph in HashMap order and reported the first (head, dep) pair whose stratum reached n. So the INT-054 message for the same rules named the two predicates in either order, depending on the run. The edges are now stored in a BTreeMap, so heads are walked in sorted order and the same rules always give the same message. Which rules are accepted or rejected is unchanged.

For the example in the issue, the message is now always:

Error: [INT-054] unstratifiable: predicate 'q' is involved in a negative cycle through 'p'

This matches the Stratification section of the wiki Datalog Reference, so the wiki needs no change.

Other error paths

As the issue asked, I checked the err_coded! sites in evaluator.rs, optimizer.rs, magic_sets.rs and rules.rs. They use fixed text or iterate Vecs, so none has the same problem.

Tests

  • New unit test test_negative_cycle_error_message_is_deterministic: it builds the two-rule cycle 64 times, each with a fresh RandomState, and checks the exact message. Before the fix it failed with the reversed pair.
  • REPL end to end: 20 of 20 runs gave the same message (before the fix, 7 of 10 runs did).
  • cargo fmt --check, cargo clippy -- -D warnings, and cargo test: 1203 passed, 0 failed, 8 ignored.

Docs: CHANGELOG entry and test counts updated (CLAUDE.md, README.md, docs/TEST_COVERAGE.md).

🤖 Generated with Claude Code

https://claude.ai/code/session_01BedF9ZmqVZLkvDwn91fuKy

)

stratify() walked the rule dependency graph in HashMap order and returned
the first (head, dep) pair whose stratum reached n, so the INT-054 message
for the same rules named the predicates in either order between runs.
Store the edges in a BTreeMap so heads are walked in sorted order. The
message now matches the wiki example every time; acceptance is unchanged.

Adds a unit test that builds the same two-rule cycle 64 times and checks
the exact message. Other error paths in the evaluator, optimizer and
magic-sets use fixed text or iterate Vecs, so they were not affected.

Closes #410

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BedF9ZmqVZLkvDwn91fuKy
@adityamukho adityamukho added this to the v2.0.2 milestone Sep 26, 2026
@codecov

codecov Bot commented Sep 26, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

@adityamukho
adityamukho merged commit 1941eb6 into main Sep 26, 2026
20 checks passed
@adityamukho
adityamukho deleted the fix/410-stable-cycle-error branch September 26, 2026 13:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: INT-054 negative-cycle error names the two predicates in a random order

1 participant