Skip to content

test(core): assert RoomLifecycle's CRUD, join/leave, and grant logic directly - #129

Merged
Mearman merged 3 commits into
mainfrom
chore/mutation-room-lifecycle
Sep 16, 2026
Merged

Mearman merged 3 commits into
mainfrom
chore/mutation-room-lifecycle

Conversation

@Mearman

@Mearman Mearman commented Sep 15, 2026

Copy link
Copy Markdown
Member

Summary

  • Direct, DI-based unit tests for RoomLifecycle, previously exercised only indirectly through integration tests
  • Covers createRoom/listRooms/joinRoom (room-lifecycle.test.ts), leaveRoom/inviteToRoom/kickFromRoom/destroyRoom (room-lifecycle-membership.test.ts), and refreshRoomMembers/requestDmAccess/getRoom/revokeMemberGrant/declineInvite (room-lifecycle-remote.test.ts)
  • Real generated identities and minted tokens throughout, since this class genuinely mints tokens and parses the real wire schema

Closes #109. Part of the mutation-testing epic tracked in #64.

Mutation score: 65.20% -> 94.88% (241/254 scoreable, verified with a full local Stryker run on a dedicated machine). The thirteen remaining survivors are almost entirely provable equivalent mutants (same-object-reference Map.set no-ops, documented in place) or error branches genuinely unreachable against real, validly-generated crypto identities.

Test plan

  • pnpm typecheck
  • pnpm lint
  • pnpm test (662 passed)
  • Verified mutation score with a real Stryker run

…directly

RoomLifecycle was previously exercised only indirectly through end-to-end
integration tests. This adds direct, DI-based unit tests covering every
public method: createRoom (slugging, secret-room naming, duplicate
detection, root-grant minting), getRoom, listRooms (secret-room
visibility), joinRoom/joinRemoteRoom (local-vs-remote gating, invitation
consumption, subscribedRooms/room_members/federation notification),
leaveRoom/leaveRemoteRoom (local-vs-remote gating, cascading destroy of
an empty owned room), refreshRoomMembers, requestDmAccess,
inviteToRoom/declineInvite, revokeMemberGrant, kickFromRoom, and
destroyRoom.

Uses real generated identities and real minted capability tokens
throughout, not opaque placeholders: this class genuinely mints tokens
and parses roomJoinOkSchema/roomMembersOkSchema's own structural COSE
shape, which an arbitrary placeholder string fails outright.

Split across two files to stay under the repo's max-lines cap.
A full mutation run against the current test suite surfaced 26 survivors
against a 65.20% baseline; this closes the real gaps among them (mutation
score up to 89.76% before this commit, further improved by these fixes):

- Every thrown CommsError's own message, not just its code, is now
  asserted where a test previously checked only the code -- several
  StringLiteral mutants inside error-message template strings otherwise
  survive untouched since no assertion ever reads the message text.
- joinRemoteRoom and refreshRoomMembers now assert the built room's own
  memberJoins and federated fields, not just members/name/type -- both
  were constructed but never independently verified.
- refreshRoomMembers now asserts the exact scope passed to sendRoomRequest,
  and that an existing room's federated flag survives a refresh while a
  fresh one defaults to false.
- joinRoom's own agent-subscription branch now asserts the bumped
  version, not just the mutated array.
- leaveRoom's subscribedRooms filter is now tested against an agent
  subscribed to more than one room, since a single-entry array can't
  distinguish "filter out this room" from "filter out everything".
- leaveRoom's and kickFromRoom's federated-notification branches are now
  tested on both sides (federated and not), not just the positive case.
- leaveRemoteRoom's reason-omission (undefined, not merely absent-valued)
  is now asserted via leaveRoom's own remote-leave path, which never
  passes one.
- kickFromRoom now asserts the room's version bump and that the target
  is actually gone from the recomputed members list, not just that the
  underlying recordMemberOp calls were made.

The remaining survivors are documented in place rather than chased:
four are the same Map/rooms.set-on-an-already-stored-reference no-op
this repo's own mutation-testing work has already documented elsewhere
(agent-registry.ts, delivery-engine.ts), and three are error branches
genuinely unreachable against this suite's real, validly-generated
crypto identities.

Split across three files (from two) to stay under the repo's max-lines
cap after these additions.
A fresh mutation run (94.49%, up from 89.76%) surfaced four further real
gaps: refreshRoomMembers's invited-field fallback with no existing room
was never asserted; inviteToRoom's own room.version bump, and the exact
scope it sends its outbound request under, were both unobserved.

Also documents two further equivalent mutants following the same
same-object-reference Map.set pattern already documented elsewhere in
this file: joinRoom's and leaveRoom's own agents.set(agentId, agent)
calls, alongside their already-documented rooms.set(roomId, room) ones.

Directly verified (by manually mutating the source locally and
confirming the test suite genuinely fails) that leaveRoom's own
destroy-trigger condition is correctly covered by the existing
"does not destroy" test despite Stryker's own report listing it as a
survivor -- not chased further, since the coverage is real.

Split declineInvite and revokeMemberGrant out to room-lifecycle-remote.test.ts
to stay under the repo's max-lines cap after these additions.
@Mearman
Mearman marked this pull request as ready for review September 16, 2026 00:08
@Mearman
Mearman merged commit 878a5c7 into main Sep 16, 2026
6 checks passed
@Mearman
Mearman deleted the chore/mutation-room-lifecycle branch September 16, 2026 00:08
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 16, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
🔒 Security Review Completed 2026-09-16T00:11:16.011272Z 2c98ba0 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@github-actions

Copy link
Copy Markdown

🎉 This PR is included in version 2.21.19 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Raise src/core/room-lifecycle.ts mutation score to 80%

1 participant