Module: tabibu-engine

The safety core: shared types, the scanning/reclaiming contract, denylist, undo manifests, cancellation, and Smart Scan orchestration. Everything else plugs into this. (Guide §4; ADR-0001 for how it crosses to Swift.)

The contract

flowchart LR
    subgraph READ-ONLY
        S[Scanner trait\nscan ctx,cancel,sink] --> G[GuardedSink\ndenylist + allowed_roots]
    end
    G -->|CleanupItem stream| UI[Review UI\nuser selects]
    UI --> R[reclaim - the ONLY mutating path]
    subgraph MUTATING
        R --> V{batch validation\ndenylist + tier}
        V -->|violation| REF[refuse all,\ntouch nothing]
        V -->|ok| M[undo manifest\nfsync first] --> ACT[trash / delete / truncate\nmeasured before+after]
    end

Denylist (the invariant)

Absolute prefixes (/System, /bin, /usr except /usr/local, …) plus home-relative user data (Documents, Desktop, Library/Mail, iCloud Drive, Keychains, device backups…). Relative paths and any .. component are rejected outright. home is injected — fully testable.

Tests (15)

7 unit (denylist, cancel, undo) + 3 adversarial property tests + 5 golden-image/fault-injection reclaim tests (exact-files-changed snapshot diff, batch refusal, tier violation, permission-denied honesty).

Extension points

New scanner: implement Scanner, register in your crate's scanners(), wire the id through tabibu-ffi's scan registry. Mutating behavior beyond trash/delete/truncate requires a new ReclaimAction + engine tests first.