Files
amethyst/quartz/src
Claude 65c683c9c7 fix(store): classify insert failures against the database, not the driver's message
`classifyRowError` read SQLite's exception text to decide whether a row that
failed to insert was a duplicate, a superseded replaceable, or a genuine write
failure. That text is the driver's business, not a contract: the bundled JVM
driver spells out `UNIQUE constraint failed: event_headers.id`, while Android's
wraps the same failure in an `android.database.SQLException` whose message is
**null**. So on the Android host every duplicate fell through to `Failed`, which
the relay renders as `OK false "error: SQLException"` — an answer clients retry
forever, and a direct violation of STORE-W01/W02 (`OK true` with the `duplicate:`
prefix). Four commonTest suites caught it and failed on that target only:
NostrServerTest x3 and LiveNegentropyIndexStoreTest.

The classifier now asks the connection instead. It already runs after the
savepoint rollback, so the connection shows pre-insert state and the two
questions have exact answers: is this id already stored, and does a stored
version already beat this one at its replaceable/addressable coordinate? The
latter is the exact complement of `displacedBy`'s predicate, so a disk error
while inserting a *winning* version still reports `Failed` rather than turning
into a silent `OK true`. Trigger RAISEs (`blocked:`, `not allowed`) keep being
decided by text — they leave no database-visible trace.

One behaviour change, noted in the skill's changelog: re-offering a stored
replaceable/addressable event byte-for-byte now reports DUPLICATE where the JVM
driver previously reported SUPERSEDED. It violates both indexes and which one
SQLite names first is up to the driver; the id answer is the one that holds
everywhere (and is the truer sentence). Both carry the `duplicate:` prefix, so
the wire answer is unchanged.

`InsertOutcomeClassificationTest` pins all of this at the store level on both
targets, including the guard that a winning version at an occupied coordinate is
still Accepted.

Also corrects a false claim in the previous commit's message: moving the cordn
and contextvm tests to `jvmAndroidTest` did NOT make them run on the Android
host. `androidHostTest` has no `dependsOn(jvmAndroidTest)` — only `jvmTest`
does — so those suites run on the JVM target alone.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012BfD4txdnsaPRXmNXbup9n
2026-09-18 21:36:33 +00:00
..