astmap-core 0.0.1

Core domain types and logic for astmap
Documentation
# astmap-core — Crate-Level Instructions

## Scope

This crate is the **domain core** of astmap. It contains domain models (including parser contract types), port trait definitions, the scan pipeline, diff logic, and export formatting. It must NOT depend on infrastructure (SQLite, tree-sitter, git2, clap, tokio, etc.).

## Module Responsibilities

| Module       | Owns                                                                 |
|--------------|----------------------------------------------------------------------|
| `error`      | All error types: `ParseEnumError`, `DbError`, `DiffError`, `ScanError` (Layer 0 — depends on nothing) |
| `model`      | All domain enums (`SymbolKind`, `DepType`, `ScanStatus`, …), domain structs (`Scan`, `File`, `Symbol`, `Dependency`, query result types), and parser contract types (`ExtractedSymbol`, `ExtractedImport`, `ExtractedCall`, `ExtractedTypeRef`, `ParseResult`). Depends only on `error`. |
| `port`       | All capability traits: `ConfigStore`, `ScanStore`, `QueryStore`, `DiffStore`, `ExportStore`, `VcsProvider`, `LanguageParser`, `LanguageResolver`, `LanguageRegistry`. Depends on `model`, `error`. |
| `scanner`    | Scan orchestration: file discovery, AST indexing, stale-file reconciliation, import resolution, cross-file dependency resolution |
| `diff`       | Working-tree diff, since-ref diff, session anchor management. Pure module parent (mod + pub use). |
| `export`     | Markdown export with token budget                                    |

## Layer Rules (enforced by `tests/architecture.rs`)

```
Layer 0: error      — depends on nothing (foundation)
Layer 1: model      — depends on error (validation errors)
Layer 2: port       — depends on model, error
Layer 3: scanner    — depends on model, error, port
Layer 3: diff       — depends on model, error, port
Layer 3: export     — depends on model, error, port
No sibling deps: scanner/diff/export do not import from each other.
```

## Purity Principle

This crate is a **pure domain layer** — it defines *what* the system does, not *how*. All side effects (disk I/O, database access, network, process spawning) are abstracted behind traits and injected by the caller.

- **No I/O in this crate.** Functions must not directly read/write files, open DB connections, or make network calls. The only exception is `scanner::discovery` which reads the filesystem to list source files — this is accepted as a boundary convenience but should not expand further.
- **No async runtime.** This crate is synchronous. Never add `tokio`, `async-trait`, or any async dependency.
- **No concrete infra types.** Types like `rusqlite::Connection`, `git2::Repository`, or `tree_sitter::Parser` must never appear in signatures or fields. Use trait objects (`&dyn ScanStore`, `&dyn LanguageParser`, etc.) instead.
- **Testable in isolation.** All logic should be testable with in-memory trait implementations — no database, no filesystem (except discovery), no external processes.

## Rules

- **No infra dependencies.** Never add `rusqlite`, `tree-sitter-*`, `git2`, `clap`, `tokio`, or any I/O-heavy crate to `Cargo.toml`. All infrastructure is injected via traits.
- **All traits live in `port.rs`.** New storage capabilities, VCS abstractions, and language capabilities all go into `port.rs`.
- **All error types live in `error.rs`.** New error enums go into `error.rs`.
- **Domain enums must roundtrip.** Every `Display`/`FromStr` pair must have a roundtrip test in `model.rs`.
- **Scanner sub-modules are `pub(crate)`.** Only `Scanner` and `ScanResult` are public from the `scanner` module.
- **Keep `lib.rs` re-exports minimal.** Only re-export types that downstream crates actually need.
- **Internal imports use explicit paths.** Within astmap-core, use `crate::port::ScanStore`, `crate::error::DbError`, `crate::model::Symbol` etc. The `lib.rs` re-exports are for external consumers only.

## Conventions

- Error handling: return `Result<T, DbError>` for storage operations, `Result<T, ScanError>` for scan operations, `Result<T, DiffError>` for diff operations.
- All domain structs derive `Debug, Clone, Serialize, Deserialize`.
- Domain enums use `#[serde(rename_all = "snake_case")]` and implement `Display + FromStr` with `ParseEnumError`.