addArtifact was a stub: it returned null unconditionally (so the
ViewModel's success path never fired), called a TODO() addArtifactVersion
that threw mid-flow, and passed empty chatRoomId/userPublicKey — yielding
a wrong event id and foreign-key violations.
- Persist the MantraArtifact with the real chatRoomId and userPublicKey,
plus a MarmotInnerEvent rumor (marmotGroupEventId IS NULL) that the
outbound pipeline encrypts into the group, mirroring sendChatMessage.
Set the inner event kind to ArtifactEvent.KIND so it matches the hashed
id (it previously defaulted to ChatEvent.KIND).
- Implement addArtifactVersion (was TODO) and create the initial version;
add MantraArtifactVersion.fromArtifactVersionEventTemplate mirroring
MantraArtifact for consistent id derivation.
- Return the created inner event so the caller can detect success; wrap
writes in try/catch to fail without crashing.
Thread the required dialectId plus chatRoomId/userPublicKey and the
visibility/license params (defaulting to private/cc) through
MantraRepository and AddArtifactViewModel. The ViewModel now validates
inputs up front, routes exceptions to onFailure, clears fields only on
success, and uses isActionPending to block double submits. The screen
passes dialectId = null with a TODO until a dialect picker exists; the
flow fails gracefully in the meantime.
Also fix the ArtifactVersionEvent.build phantom generic
(TagArrayBuilder<ArtifactEvent> -> <ArtifactVersionEvent>) so it returns
the correct EventTemplate type.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The artifact/dialect/chapter/translation-version events packed several
independent attributes into single positional tags
(["artifact", url, visibility, license], ["dialect", name, country,
language], etc.). Positional packing made every field mandatory (a
missing or malformed field nulled the whole metadata blob), blocked
extension, and forced ArtifactMetadataTag and
TranslationArtifactVersionMetadataTag to share TAG_NAME "artifact" with
field 1 meaning url vs name.
Replace the four compound tags with seven shared single-field tags
(NameTag, UrlTag, VisibilityTag, LicenseTag, CountryTag, LanguageTag,
OriginalTextTag), following the NIP-23 one-tag-per-field convention.
Event accessors now read each field independently and build()/toXEvent()
emit one tag per field; from...Event() readers let-chain the per-field
accessors. This also removes the duplicate "artifact" tag-name collision.
Note: breaking wire-format change for kinds 30300/30302/30304/30306;
safe now since these events are not published yet.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
WordStatisticsTag.parse used has(3) but the tag has only 3 elements
(indices 0-2), so the guard never passed and parse always returned null
— silently breaking all Chapter and Chunk event parsing. Correct to
has(2).
Also replace unsafe tag[n].toInt() with toIntOrNull() in WordStatisticsTag
and IndexTag so a malformed numeric field from a relay returns null
instead of throwing NumberFormatException up through the parse loop.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>