Skip to content

feat(data): retain conversations on archive() + expose archived filter + seed (#93)#110

Merged
ilmoniemi merged 3 commits into
mainfrom
feature/93
May 14, 2026
Merged

feat(data): retain conversations on archive() + expose archived filter + seed (#93)#110
ilmoniemi merged 3 commits into
mainfrom
feature/93

Conversation

@ilmoniemi
Copy link
Copy Markdown
Contributor

What

  • Conversation gains an archived: Boolean = false field (default keeps every existing construction site source-compatible).
  • FakeConversationRepository.archive(id) flips from removing the conversation to setting archived = true via state.update { … }. Throws IllegalArgumentException for unknown ids (unchanged contract); idempotent on repeat calls.
  • ConversationFilter gains Archived. Filter matrix:
    • All — everything (no predicate)
    • ChannelsisPromoted && !archived
    • Discussions!isPromoted && !archived
    • Archivedarchived
  • One archived discussion seeded (seed-discussion-archived, lastUsedAt = 2026-04-15T12:00:00Z) so the archived stream is non-empty for manual verification.

Issue

Closes #93. Unblocks the Archived Discussions UI split from #77. unarchive() is intentionally out of scope (sibling ticket).

Testing

  • ./gradlew test
  • ./gradlew lint
  • ./gradlew assembleDebug
  • ./gradlew connectedAndroidTest — not run (no device/emulator connected; this is pure data-layer code with no instrumented coverage needed).

Test changes in FakeConversationRepositoryTest:

  • Bumped All seed assertion 5→6 and added Archived = 1 assertion.
  • Bumped createDiscussion_appearsIn_observeConversations_All from 6→7.
  • Rewrote archive_removes_from_observeConversationsarchive_movesConversation_from_Discussions_to_Archived_andRetainsInStore per AC.
  • Extended seededDiscussions_remainEmpty id list to include the new archived seed.
  • New tests: seededArchivedDiscussion_appearsIn_Archived_butNotIn_Discussions, archive_onUnknownId_throws, archive_isIdempotent.

ChannelListViewModelTest.stubRepo gains an Archived -> TODO("not used") branch to keep the when exhaustive. DiscussionListViewModelTest stubs don't switch on the enum and are unchanged.

Architecture compliance

Follows docs/specs/architecture/93-…md verbatim: new enum variant rather than a parallel method; !archived added to Channels and Discussions for symmetry; archive() preserves lastUsedAt and isPromoted; no ConversationId value type introduced; unarchive() deferred.

🤖 Generated with Claude Code

ilmoniemi and others added 2 commits May 14, 2026 08:45
…r + seed (#93)

Add `Conversation.archived` flag and flip `FakeConversationRepository.archive()`
from removal to a flag mutation, so the upcoming Archived Discussions UI has an
observable stream to subscribe to. Extend `ConversationFilter` with an `Archived`
variant; `Channels` and `Discussions` predicates gain `!archived` so the existing
lists keep their meaning. Seed one archived discussion for manual verification.

Closes #93

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ilmoniemi
Copy link
Copy Markdown
Contributor Author

Code Review: #93

Decision: PASS

Findings

None.

Summary

Clean, spec-compliant implementation of the XS data-layer slice.

  • Conversation.archived: Boolean = false keeps every existing construction site source-compatible (no other call sites needed updates — verified via grep across .copy(...) and named-arg Conversation(...) sites).
  • ConversationFilter.Archived added; predicates correctly tightened: Channels -> isPromoted && !archived, Discussions -> !isPromoted && !archived, Archived -> archived. All remains unfiltered.
  • archive() now flips the flag via state.update { ... }, preserving the IllegalArgumentException contract on unknown ids and behaving idempotently (no duplicate emission).
  • New seed seed-discussion-archived with lastUsedAt = 2026-04-15T12:00:00Z (intentionally older than live discussions, per spec).
  • seedDiscussion(...) gained a defaulted archived: Boolean = false param — keeps the seed list readable and avoids a near-duplicate helper.
  • Tests: counts bumped (All 5→6, post-create All 6→7, Archived 1); the rewritten archive_movesConversation_from_Discussions_to_Archived_andRetainsInStore covers the full pre/post matrix (in Discussions, not Archived → not in Discussions/Channels, in Archived, retained in All); new coverage for the archived seed's three-stream visibility, unknown-id throw, and idempotency. seededDiscussions_remainEmpty extended to include the new seed.
  • ChannelListViewModelTest.stubRepo gained the exhaustive ConversationFilter.Archived -> TODO("not used") branch. DiscussionListViewModelTest and erroringRepo stubs don't switch exhaustively on the enum, so no update needed there — correctly left alone.
  • ./gradlew test and ./gradlew lint both pass locally. Single pre-existing deprecation warning in DiscussionListScreen.kt:165 is unrelated to this PR.
  • data/ remains free of android.* imports — Compose-Multiplatform-safe.

The architecture spec is also committed at docs/specs/architecture/93-archived-conversation-retention.md. The sibling unarchive(...) ticket is correctly deferred.

…ed (#93)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@ilmoniemi ilmoniemi merged commit ca9c955 into main May 14, 2026
1 check passed
@ilmoniemi ilmoniemi deleted the feature/93 branch May 14, 2026 05:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(data): retain conversations on archive() + expose archived filter + seed

1 participant