# AGENTS.md This file provides guidance to coding agents collaborating on this repository. ## Mission Chase-rs is an efficient implementation of the chase algorithm in Rust for advanced reasoning engines. Priorities, in order: 1. Correctness of reasoning (sound and complete chase). 2. Termination guarantees (restricted chase for existential rules). 3. Performance and scalability. 4. Clear, maintainable, idiomatic Rust code. ## Core Rules - Use English for code, comments, docs, and tests. - Keep all chase state inside well-defined structs; avoid global mutable state. - Prefer small, focused changes over large refactoring. - Add comments only when they clarify non-obvious behavior. - Follow Rust idioms: use `Result` for errors, iterators over manual loops, etc. Quick examples: - Good: add a new chase variant by implementing a trait or strategy pattern. - Bad: add global configuration that affects all chase instances. ## Repository Layout - `src/`: core implementation. - `src/chase/`: chase algorithm modules. - `term.rs`: terms (constants, nulls, variables). - `atom.rs`: atoms (predicate applied to terms). - `instance.rs`: database instance (set of facts). - `rule.rs`: TGDs (tuple-generating dependencies). - `substitution.rs`: variable bindings and unification. - `engine.rs`: core chase algorithm. - `tests/`: integration, regression, and property-based tests. ## Architecture Constraints - `Instance` holds the database state (set of ground atoms). - `Rule` represents tuple-generating dependencies (TGDs). - The chase engine is stateless; state is passed explicitly. - New chase variants should be composable with existing infrastructure. - Existential variables generate labeled nulls (`Term::Null`). ## Rust Conventions - Target stable Rust (edition 2024, rust-version 1.92). - Use `#[derive(...)]` for common traits where appropriate. - Prefer `&str` over `String` in function parameters when ownership isn't needed. - Use `impl Trait` for return types when the concrete type is an implementation detail. - Run `cargo clippy` and address warnings before committing. ## Required Validation Run these checks for any non-trivial change: 1. `cargo test` (all unit and integration tests) 2. `cargo clippy` (lint checks) 3. `cargo fmt --check` (formatting) For performance-sensitive changes: 1. Add benchmarks if they don't exist 2. Compare before/after performance ## First Contribution Flow Use this sequence for your first change: 1. Read `src/chase/mod.rs` and the relevant module files. 2. Implement the smallest possible code change. 3. Add or update tests that fail before and pass after. 4. Run `cargo test`. 5. Run `cargo clippy` and fix any warnings. 6. Update docs if public API behavior changed. Example scopes that are good first tasks: - Add tests for an edge case in unification. - Implement a new utility method on `Instance` or `Atom`. - Add support for equality-generating dependencies (EGDs). - Improve error handling with proper `Result` types. ## Testing Expectations - No chase logic change is complete without tests. - Unit tests go in `#[cfg(test)] mod tests` within each module. - Integration tests go in `tests/integration_tests.rs`. - Regression tests for bug fixes go in `tests/regression_tests.rs`. - Property-based tests go in `tests/property_tests.rs`. - Do not merge code that breaks existing tests. Minimal unit-test checklist: 1. Create an `Instance` with relevant facts. 2. Define rules using `RuleBuilder`. 3. Run `chase(instance, &rules)`. 4. Assert on `result.terminated`, `result.instance`, and derived facts. Example test skeleton: ```rust #[test] fn test_example() { let instance: Instance = vec![ Atom::new("Pred", vec![Term::constant("a")]), ].into_iter().collect(); let rule = RuleBuilder::new() .when("Pred", vec![Term::var("X")]) .then("Derived", vec![Term::var("X")]) .build(); let result = chase(instance, &[rule]); assert!(result.terminated); assert_eq!(result.instance.facts_for_predicate("Derived").len(), 1); } ``` ## Change Design Checklist Before coding: 1. Confirm whether the change affects chase semantics or termination. 2. Identify affected tests. 3. Consider impact on API stability. Before submitting: 1. Verify `cargo test` passes. 2. Verify `cargo clippy` has no warnings. 3. Ensure tests were added/updated where relevant. ## Review Guidelines (P0/P1 Focus) Review output should be concise and only include critical issues. - `P0`: must-fix defects (incorrect reasoning, non-termination, soundness bugs). - `P1`: high-priority defects (likely functional bug, performance regression, API breakage). Do not include: - style-only nitpicks, - praise/summary of what is already good, - exhaustive restatement of the patch. Use this review format: 1. `Severity` (`P0`/`P1`) 2. `File:line` 3. `Issue` 4. `Why it matters` 5. `Minimal fix direction` ## Practical Notes for Agents - Prefer targeted edits over broad mechanical rewrites. - If you detect contradictory repository conventions, follow existing code and update docs accordingly. - When uncertain about correctness, add/extend tests first, then optimize. - The chase algorithm has well-defined semantics; consult database theory literature if needed. ## Commit and PR Hygiene - Keep commits scoped to one logical change. - PR descriptions should include: 1. behavioral change summary, 2. tests added/updated, 3. performance impact (if applicable), 4. API changes (if any). Suggested PR checklist: - [ ] Tests added/updated for behavior changes - [ ] `cargo test` passes - [ ] `cargo clippy` has no warnings - [ ] `cargo fmt` applied