feat(cli): amy store stat/sweep-expired/scrub/compact + e2e cache test
Three changes that go together:
1. Reconcile cli/plans/2026-04-24-file-event-store-{overview,nips}.md
with shipped reality: code lives in quartz/jvmMain/, not commons/;
data dir is <data-dir>/events-store/, not <root>/events/.
2. New StoreCommands wired as `amy store …`:
- stat → events count, kind histogram, disk bytes,
oldest/newest createdAt. Pure read, no Context
(skips identity check).
- sweep-expired → wraps store.deleteExpiredEvents(); reports
{swept, remaining}.
- scrub → wraps store.scrub() to rebuild idx/ from
canonicals.
- compact → wraps store.compact() to drop dangling idx/.
All four open the FsEventStore directly (no Context, no identity
needed) — they're store-only operations.
3. New e2e harness at cli/tests/cache/cache-headless.sh that boots a
local nostr-rs-relay, two amy identities (A + B), and asserts:
T1 — store stat reports non-empty store after publish-lists +
profile edit, with kind:0 and kind:10002 present.
T2 — A's `profile show` is `source: "cache"` by default.
T3 — `--refresh` forces `source: "relays"`.
T4 — B's first `profile show <A_NPUB>` is a relay miss; second is
a cache hit (proves drain populates the local store and
subsequent reads serve from disk).
T5 — `relay list` reads URLs back from the local kind:10002 /
10050 / 10051 events.
T6 — relays.json no longer exists in either data-dir.
T7 — store stat / sweep-expired / scrub / compact all run
without an identity present.
Same pattern as cli/tests/dm/dm-interop-headless.sh — reuses the
nostr-rs-relay infrastructure from cli/tests/marmot/setup.sh.
This commit is contained in:
@@ -399,10 +399,10 @@ reads. O(size of idx trees).
|
||||
|
||||
### Location
|
||||
|
||||
`commons/src/jvmTest/kotlin/com/vitorpamplona/commons/store/fs/`
|
||||
|
||||
Uses JUnit4 (matches rest of the project). Temp-dir fixture creates
|
||||
a fresh store per test.
|
||||
`quartz/src/jvmTest/kotlin/com/vitorpamplona/quartz/nip01Core/store/fs/`
|
||||
(sibling to the SQLite reference tests). Uses kotlin.test (matches
|
||||
the rest of the quartz `jvmTest` source set). Temp-dir fixture
|
||||
creates a fresh store per test.
|
||||
|
||||
### Test categories
|
||||
|
||||
|
||||
@@ -51,29 +51,36 @@ files may be created or deleted by the user between runs.
|
||||
`events/`. `amy store scrub` does this.
|
||||
4. **`events/` is the source of truth.** If a file is there, it is
|
||||
part of the store. If it is gone, it is gone — tombstones aside.
|
||||
5. **No business logic.** This is a `commons/` module that the CLI
|
||||
imports. No Nostr-protocol decisions live in `cli/`.
|
||||
5. **No business logic.** Lives next to the SQLite reference store
|
||||
in `quartz/`, sibling pattern. No Nostr-protocol decisions live
|
||||
in `cli/`.
|
||||
|
||||
---
|
||||
|
||||
## Module placement
|
||||
|
||||
Source: `commons/src/jvmMain/kotlin/com/vitorpamplona/commons/store/fs/`
|
||||
Source: `quartz/src/jvmMain/kotlin/com/vitorpamplona/quartz/nip01Core/store/fs/`
|
||||
|
||||
- Sibling to the existing
|
||||
`quartz/src/commonMain/kotlin/.../nip01Core/store/sqlite/` reference
|
||||
implementation. The plan originally proposed `commons/` but the
|
||||
shipped placement is `quartz/jvmMain/`, where every other event-
|
||||
store concern already lives — and quartz already has a `jvmTest`
|
||||
source set so we get JVM-specific tests for free.
|
||||
- JVM-only (uses `java.nio.file`, `FileChannel.lock`, `Files.createLink`).
|
||||
- Consumed by `cli/`. Android keeps `SQLiteEventStore`. Desktop can
|
||||
opt in later if useful.
|
||||
- Tests under `commons/src/jvmTest/.../store/fs/`.
|
||||
|
||||
Not in `quartz/` because `quartz/` is protocol-only (no storage).
|
||||
Not in `cli/` because it contains reusable logic.
|
||||
- Tests under `quartz/src/jvmTest/.../store/fs/`.
|
||||
|
||||
---
|
||||
|
||||
## Directory layout
|
||||
|
||||
Root: configurable, defaults to `$AMY_HOME/events/` (where `$AMY_HOME`
|
||||
is `~/.amy` by default).
|
||||
Root: configurable. The CLI uses `<data-dir>/events-store/` (where
|
||||
`<data-dir>` is `--data-dir PATH`, `$AMETHYST_CLI_DATA`, or `./amy`).
|
||||
The plan originally said `events/`; the actual `DataDir.eventsDir`
|
||||
field is `events-store/` to leave the bare name `events/` available
|
||||
for the canonical-events subdirectory inside the store.
|
||||
|
||||
```
|
||||
<root>/
|
||||
|
||||
Reference in New Issue
Block a user