Imported from nwtks/lsm-tree (
AGENTS.md). Install upstream withnpx skills add nwtks/lsm-tree. Copyright stays with the author.
AGENTS.md
This file provides guidance for AI agents working in this repository.
AGENTS.md Editing Rules
- Don't write what's in the codebase — information that can be obtained by reading source code or project files must not be written in AGENTS.md.
- Don't duplicate README.md — content already described in README.md should only be referenced by a link (
See [README.md](...)).
Documentation Location Rules
| Topic | Destination |
|---|---|
| Architecture and design discussions | docs/architecture.md |
| Design trade-offs | docs/trade-off.md |
| Common mistakes / gotchas | docs/gotchas.md |
- When a design decision, trade-off, bug fix, or known issue occurs, update
docs/trade-off.mdordocs/gotchas.mdimmediately (in the same session). - Do not defer updates.
- When a new trade-off or gotcha arises, first consider appending to the relevant
docs/file. Only add to AGENTS.md if it's an "implicit rule not obvious from the codebase." - Only keep project-specific implicit rules in AGENTS.md.
The topics above belong in their corresponding
docs/*.mdfiles.
Cross-Platform Compatibility
All code must work on both Windows and Linux (including test code). Avoid:
- Hard-coded path separators; use
System.IO.Path.Combine. - Platform-specific APIs without fallback (e.g.,
stream.Flush(true)/FileStream.Flush(bool)is supported on both). - Assumptions about case-sensitive file paths (tests use
withTestDirwith unique lowercase names). - Process-level locks on files that outlive the test scope (
FileShare.Readon SSTables, etc.).
Coding Conventions
- Prefer functional programming idioms over imperative ones throughout the codebase. This includes test code.
- Favor expressions over statements.
Use
matchexpressions,if/then/else, and pattern matching instead of imperative control flow. - Leverage discriminated unions. Model domain concepts with DUs for exhaustiveness checking.
- Use
[<TailCall>]on recursive functions that loop to prevent stack overflows. - Do not introduce new external NuGet packages without checking existing dependencies in the
.fsprojfiles first. - Cyclomatic complexity: Every function/method must keep its keyword-calculated complexity ≤ 15 (hard limit).
Keep it ≤ 10 where practical.
After
dotnet test,scripts/check-complexity.fsxreadscoverage.cobertura.xmland reports both a keyword-based estimate (calculated) and the Coverlet reference value. The error/warning thresholds apply to the calculated column. Configure thresholds inDirectory.Build.props. If the check fails, split the function into smaller helpers or simplify branching.
Testing Conventions
- After any code change, run
dotnet testand confirm all tests pass. - The
dotnet testoutput includes a Cyclomatic Complexity Report (from coverage data viascripts/check-complexity.fsx). Address any warnings (above 10) and fix any errors (above 15). - Maintain high unit test coverage (target: ≥ 90% line coverage). If line coverage falls below 90%, add test code to restore it above the threshold before merging.
- Test ordering rules:
- Within each test file,
[<Fact>]functions must appear in the same order as the corresponding functions/methods/constructors in the source file under test. - When multiple test cases target the same source function, order them by test priority: normal (happy path) → error cases → fault/failure scenarios.
- Within each test file,
- Prefer data-driven tests (
[<Theory>]+[<InlineData>]) when multiple test cases share the same test logic but differ only in inputs or expected outputs. This reduces code duplication and makes it easy to add new cases. - Use a unique test directory name per test. Tests may run in parallel, so directory names must not collide.
- Each test uses
withTestDir "<unique_name>" (fun testDir -> ...)to get an isolated temp directory (creates before use, cleans up after intry/finally). - Use
assertEqual expected actual msgfor readable failure output. (It wrapsAssert.True.) - To simulate IO errors deterministically (e.g., for error propagation tests), use reflection to close private
FileStreamhandles. Never use file truncation (SetLength). .NET'sFileStreaminternal buffer can mask the corruption.
Adding a New Feature
- Identify the owning layer: WAL, SkipList, MemTable, BloomFilter, SSTable, or LsmTree coordinator.
- Respect the
LsmTree.fsprojcompilation order (insert new files after their dependencies). - Add
[<Fact>]tests in the appropriate test file (BloomFilterTests.fs,SkipListTests.fs, etc.) with a uniquewithTestDirname. - Run
dotnet test. All tests must pass. - If the feature changes the WAL or SSTable format, update both README.md and the recovery path. Add regression tests for backward compatibility.