diff --git a/CLAUDE.md b/CLAUDE.md index e9e0d1e..1797c07 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,11 +1,38 @@ # flashy-ledger - +`@flashylabs/ledger` — an append-only, multi-asset settlement ledger, published +to npm under Apache-2.0. It is the estate's **verification layer**: the rules +flashynetwork.com checks the books against, published in the open so nobody +takes "verifiable" on faith. It ships as a **library, not a site** — there is no +`public/` build and no deploy target, which is why the estate fold-coverage +survey reads it as a record repo with no served URL rather than a gap. It is +consumed by `@flashylabs/ledger` in ClaimYour.Gold and flashy.gold. The default +branch is `main`. -_Not yet described. The house rules below are estate-wide and were synced -here; what makes this repository different is still to be written._ +**The shape is the product, and it is ports-and-adapters with teeth.** `src/domain/` +is a pure core — it reads no database, calls no clock, generates no randomness — +and everything that touches storage sits behind one interface, `LedgerStore` +(`src/ports/store.ts`). That seam is the entire migration story: a chain-backed +store can implement it later and the rules above do not change, because the rules +never knew where entries were kept. `src/adapters/` holds the implementations +(in-memory, Mongo, the read-only `GoldLedgerReader`, and the `field-map` that +lets this package's rules sit on top of a collection it did not design). + +**What an agent must not break** is enumerated and executable: the numbered +guarantees in [`docs/INVARIANTS.md`](docs/INVARIANTS.md), each mapped to the test +that proves it, with `tests/invariants.test.ts` failing the build if the doc and +the suite drift. In particular — **`LedgerStore` has no update and no delete**, +and that absence is the append-only invariant (I-1); correct a mistake with +`reverse()`, never a mutation. **The `hashEntry` field order is frozen** — +changing it invalidates every chain that exists, so it is fixed deliberately, not +derived from object keys. **Amounts are signed integer `Minor` units**, never a +float or a formatted string (I-2/I-3). **Identities are opaque and tenant-scoped**, +enforced in `post()` before anything is hashed (I-8). And **the domain stays +pure** — no adapter, port, I/O builtin or third-party import reaches into +`src/domain/` (I-9, guarded by eslint for clocks/randomness and by +`tests/domain-purity.test.ts` for the import graph). Run `npm run check` +(typecheck + lint + coverage) before pushing; the roadmap, which is North Star +beyond Phase 1, is [`docs/ROADMAP.md`](docs/ROADMAP.md).