User Story
As an app developer wiring the Archived Discussions UI restore action, I want the repository to expose an unarchive(conversationId) primitive that clears the archived flag, so the UI layer can restore an archived discussion and have it reappear in the active Discussions list.
Context
The Archived Discussions view (split from #77) needs a restore action. The foundation slice #93 introduced the archived: Boolean flag on Conversation, retains conversations on archive(), and exposes ConversationFilter.Archived for observing the archived stream. This ticket adds the trivial inverse: a primitive that clears the flag.
It is its own slice rather than bundled into #93 because pairing the inverse with the foundation would push the combined ticket over the AC limit; splitting also let the foundation land independently so the UI restore work (#94) can start as soon as this primitive lands.
Acceptance Criteria
Technical Notes
- Stay consistent with the existing interface: raw
String for conversationId, no ConversationId value type.
- For unknown IDs: mirror
archive()'s behavior, which throws IllegalArgumentException("Unknown conversation: <id>") via the existing unknown() helper in FakeConversationRepository.
- Calling
unarchive on a conversation that isn't currently archived is a no-op-equivalent (the flag is already false); the architect picks whether this is a silent success or an explicit precondition check.
Size Estimate
XS
Depends on
#93 (landed) — introduced the archived flag and the archived-observable stream. Linked via GitHub blocked-by.
Split from
#77
User Story
As an app developer wiring the Archived Discussions UI restore action, I want the repository to expose an
unarchive(conversationId)primitive that clears the archived flag, so the UI layer can restore an archived discussion and have it reappear in the active Discussions list.Context
The Archived Discussions view (split from #77) needs a restore action. The foundation slice #93 introduced the
archived: Booleanflag onConversation, retains conversations onarchive(), and exposesConversationFilter.Archivedfor observing the archived stream. This ticket adds the trivial inverse: a primitive that clears the flag.It is its own slice rather than bundled into #93 because pairing the inverse with the foundation would push the combined ticket over the AC limit; splitting also let the foundation land independently so the UI restore work (#94) can start as soon as this primitive lands.
Acceptance Criteria
ConversationRepositoryinterface exposessuspend fun unarchive(conversationId: String), mirroring the existingarchiveoperationFakeConversationRepository.unarchive(conversationId)clears thearchivedflag on the named conversation (inverse of the flag-basedarchivesemantics)unarchive(id)removes it from theConversationFilter.Archivedstream and adds it to theConversationFilter.Discussions(active) streamTechnical Notes
StringforconversationId, noConversationIdvalue type.archive()'s behavior, which throwsIllegalArgumentException("Unknown conversation: <id>")via the existingunknown()helper inFakeConversationRepository.unarchiveon a conversation that isn't currently archived is a no-op-equivalent (the flag is alreadyfalse); the architect picks whether this is a silent success or an explicit precondition check.Size Estimate
XS
Depends on
#93 (landed) — introduced the
archivedflag and the archived-observable stream. Linked via GitHubblocked-by.Split from
#77