From dbf26844bb7b7b49e5c3d1d27365e6c657643f26 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 8 Sep 2026 12:30:03 +0000 Subject: [PATCH 1/5] directory/1: re-vendor check-directory.mjs to the shipping canonical MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The vendored copy of @flashyos/directory's checker had drifted behind the authoritative EDGE_REQUIRES: it required settled edges to carry only ['sealed'], where packages/directory/src/types.ts (origin/main) requires ['sealed', 'capability']. A lagging copy does not fail — it disagrees silently, validating a settled edge the estate's own spec rejects. Re-vendored byte-identical to flashyos origin/main packages/directory/vendor-check-directory.mjs (the shipping canonical, not a stale working tree). Verified: the re-vendored checker still validates this repo's own directory.fragment.json (16 nodes, 22 edges, 0 problems). The estate-level differential tools/vendored-directory.test.mjs in flashyos is the guard that catches this class of drift. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U --- scripts/check-directory.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/check-directory.mjs b/scripts/check-directory.mjs index 7b91e56..c104e5c 100644 --- a/scripts/check-directory.mjs +++ b/scripts/check-directory.mjs @@ -60,7 +60,7 @@ const REQUIRES = { convenes: [], spokeAt: ['year'], issued: ['date'], - settled: ['sealed'], + settled: ['sealed', 'capability'], publishes: [], supersededBy: ['reason'], } From 2994a146e5363d84eb7aaac0933e5cf9a41241de Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 4 Oct 2026 13:20:34 +0000 Subject: [PATCH 2/5] Architecture audit: pin domain purity as I-9, write CLAUDE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ledger's headline architectural claim — the domain reads no database, calls no clock, and generates no randomness, which is the whole reason it can move onto a chain without its rules changing — was only half enforced. eslint guards the runtime half (Date, Date.now, Math.random banned in src/domain), but nothing guarded the dependency direction: a domain module importing an adapter, a port, node:fs, or a third-party package would pass lint, typecheck and every behavioural test, silently breaking the seam the package is built on. - tests/domain-purity.test.ts reads the real import graph of src/domain with ts.preProcessFile (not a regex) and refuses any specifier that is not a domain sibling or node:crypto. Verified non-vacuous: it goes red when an adapter import or node:fs is injected into a domain file. - docs/INVARIANTS.md gains I-9, making purity a numbered, cited invariant; tests/invariants.test.ts holds the doc and the suite together as before. - CLAUDE.md gains the "what makes this repository different" section the file template asked for: what it is, that it ships as a library with no deploy target, the ports-and-adapters shape, and the invariants an agent must not break. Full suite 198 passing, typecheck clean, new test lint-clean. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01X8LDnsexvNjSkqc2ihZR7U --- CLAUDE.md | 37 +++++++++++-- docs/INVARIANTS.md | 38 ++++++++++++++ tests/domain-purity.test.ts | 101 ++++++++++++++++++++++++++++++++++++ 3 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 tests/domain-purity.test.ts 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).