mirror of
https://github.com/vitorpamplona/amethyst.git
synced 2026-10-06 03:38:23 +00:00
docs(commons): correct what blocks the event cache from commonMain
The earlier note said the NIP-95 `java.io.File` spill was the only thing keeping the cache out of `commonMain`. That was wrong. The binding blocker is that the cache's own storage — `LargeSoftCache`, holding `users`, `notes` and `addressables` — is itself `jvmAndroid`, as are both `*ListMatchingFilter` observables, `MintDirectoryIndex` and `NwcPaymentTracker`. `EventCache` cannot go without them. The audit also found most of it is already answered in the tree: `commons.util.WeakReference` is an expect/actual that already anticipates iOS, quartz's commonMain ships `ConcurrentMap`/`ConcurrentSet`/`LargeCache`, and `LargeSoftCache`'s skip-list ordering is not load-bearing — its surface has no ordered read, so the skip list is there for concurrency alone. That leaves two pieces of real work: an okio or `expect` blob sink, and getting `java.util.SortedSet` out of `EventCache.filter`'s signature, which has no common equivalent and ripples into `CacheSearch`, both observables and the parity test. Recorded with a bottom-up order, and noted that none of it is on part B's critical path — Desktop is JVM. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KkULS5SVq4GHDdoCzajKi8
This commit is contained in:
+12
-4
@@ -253,10 +253,18 @@ These are intentionally *documented*, not silently tolerated. Fix opportunistica
|
||||
namespaces expected to grow; do not fold them into `util` just for size.
|
||||
- **`onchain`** (on-chain zap splitting) is `quartz`-adjacent but un-numbered;
|
||||
leave readable unless a clear NIP number lands.
|
||||
- **`model/cache/LocalCache` is `jvmAndroid`, not `commonMain`**, because it
|
||||
spills NIP-95 blobs through `java.io.File`. Promoting it needs an okio (or
|
||||
`expect`) sink behind `LocalCacheHost.nip95BlobDir`; nothing else in the
|
||||
move-group blocks iOS.
|
||||
- **`model/cache/EventCache` is `jvmAndroid`, not `commonMain`.** The NIP-95
|
||||
`java.io.File` spill is the obvious blocker but not the binding one: the
|
||||
cache's own storage, `LargeSoftCache`, is `jvmAndroid`
|
||||
(`WeakReference` + `ConcurrentSkipListMap`), as are the two
|
||||
`*ListMatchingFilter` observables, `MintDirectoryIndex` and
|
||||
`NwcPaymentTracker`. Promoting the cache means promoting those first.
|
||||
Most of it has answers already in the tree — `commons.util.WeakReference`
|
||||
is an expect/actual, and quartz's `commonMain` has `ConcurrentMap`,
|
||||
`ConcurrentSet` and `LargeCache` — so the genuinely new work is an okio (or
|
||||
`expect`) blob sink and getting `java.util.SortedSet` out of
|
||||
`EventCache.filter`'s signature, which has no common equivalent. See the
|
||||
audit in `commons/plans/2026-08-30-commons-migration-sweep.md`.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1000,3 +1000,66 @@ GC-eligible on Desktop, as they already are on Android.
|
||||
**The test suite is not sufficient for this step.** 62 tests cover the consume
|
||||
path well, but nothing covers a stale render. Run the desktop app against a
|
||||
real relay before calling part B done.
|
||||
|
||||
|
||||
### Can `EventCache` go to `commonMain`? — audit (2026-09-21)
|
||||
|
||||
Short answer: yes in principle, but it is a **port, not a move**, and the
|
||||
earlier note in this file ("needs an okio sink … nothing else in the
|
||||
move-group blocks iOS") was wrong. The file sink is the visible blocker; the
|
||||
binding one is that the cache's own storage is `jvmAndroid`.
|
||||
|
||||
`commons` really does build `iosArm64`/`iosSimulatorArm64`, so this is a real
|
||||
constraint rather than a hypothetical one.
|
||||
|
||||
**What must move with it** (`EventCache` cannot go alone):
|
||||
|
||||
| Dependency | Why it is `jvmAndroid` |
|
||||
|---|---|
|
||||
| `LargeSoftCache` — `users`, `notes`, `addressables` | `java.lang.ref.WeakReference`, `ConcurrentSkipListMap`, `BiConsumer` |
|
||||
| `EventListMatchingFilter`, `NoteListMatchingFilter` | `SortedSet`, `ConcurrentHashMap`, `ConcurrentSkipListSet` |
|
||||
| `MintDirectoryIndex` | `ConcurrentHashMap` |
|
||||
| `NwcPaymentTracker` | `ConcurrentHashMap`, `AtomicInteger` |
|
||||
| `DvmHeartbeatRegistry`, `OnchainZapResolver` | `ConcurrentHashMap` |
|
||||
| `LocalCacheHost` | `java.io.File` |
|
||||
|
||||
**Most of it already has an answer in the tree:**
|
||||
|
||||
- `commons.util.WeakReference` is already an `expect`/`actual`, and its KDoc
|
||||
already anticipates `kotlin.native.ref.WeakReference` for iOS.
|
||||
- quartz `commonMain` already ships `ConcurrentMap`, `ConcurrentSet`,
|
||||
`ConcurrentHashCache` and `LargeCache` — so every `ConcurrentHashMap` /
|
||||
`ConcurrentSkipListSet` above is a swap, not a design problem.
|
||||
- `LargeSoftCache`'s skip-list ordering is **not** load-bearing: its whole
|
||||
surface is `get`/`put`/`remove`/`size`/`containsKey`/`keys`/`forEach`, with
|
||||
no ordered read. `ConcurrentSkipListMap` is there for lock-free concurrency,
|
||||
so quartz's `ConcurrentMap` should substitute — worth confirming nothing
|
||||
iterates expecting order before relying on that.
|
||||
- `AtomicInteger` → `kotlin.concurrent.atomics`; `BiConsumer` → a function
|
||||
type; the `dateFormatter` call is one log line and can go.
|
||||
- `androidx.collection.LruCache` in `AntiSpamFilter` is already KMP —
|
||||
`commonMain` uses it in `blurhash/CosineCache` and `relays/EOSE`.
|
||||
|
||||
**The two pieces of genuinely new work:**
|
||||
|
||||
1. **NIP-95 blob sink.** `EventCache.consume(FileStorageEvent)` writes through
|
||||
`java.io.File`/`FileOutputStream`. Needs okio or an `expect` sink behind
|
||||
`LocalCacheHost.nip95BlobDir`.
|
||||
2. **`java.util.SortedSet` in the public API.** `EventCache.filter(Filter)`
|
||||
returns one, and both `*ListMatchingFilter` observables take
|
||||
`(Filter) -> SortedSet<Note>`. Kotlin has no common `SortedSet`, so this is
|
||||
a signature change rippling into `CacheSearch`, both observables and
|
||||
`LocalCacheSearchParityTest`.
|
||||
|
||||
**Recommended order** (bottom-up; each step is independently shippable):
|
||||
|
||||
1. `LargeSoftCache` → `commonMain` on the existing `WeakReference` expect plus
|
||||
quartz's `ConcurrentMap`. This is the keystone — everything else is behind it.
|
||||
2. The `ConcurrentHashMap`/`ConcurrentSkipListSet` holders, mechanically.
|
||||
3. `SortedSet` out of `EventCache.filter`'s signature.
|
||||
4. The NIP-95 sink.
|
||||
5. `EventCache` + `LocalCacheHost` themselves.
|
||||
|
||||
**Not on part B's critical path.** Desktop is JVM, so retiring
|
||||
`DesktopLocalCache` needs none of this. The payoff here is an iOS front end
|
||||
later, not anything queued now.
|
||||
|
||||
Reference in New Issue
Block a user