The threads of comments of a room: the engine of its comments document
(Issho.Comments). Its browser twin is commentsEngine, held to the
same cases (test/corpus/engine_comments.json).
The state is %{"threads" => [thread]}, in the order they began:
%{
"id" => "t1",
"place" => %{"doc" => "board:42", "at" => %{"node" => "n7"}},
"status" => "open",
"resolved" => nil,
"comments" => [
%{
"id" => "c1",
"author" => %{"key" => "user:ada", "name" => "Ada", "kind" => "human"},
"body" => "Should this go first?",
"mentions" => ["agent:claude"],
"at" => "2026-10-23T10:00:00Z",
"edited" => nil,
"reactions" => %{"👍" => ["user:ken"]}
}
]
}A thread's place is where it is, in a component's own terms
(Issho.Place), or nil for the page as a whole. "resolved" is
%{"by" => key, "at" => time} while it is resolved.
Operations
%{"op" => "start", "thread" => "t1", "place" => place, "comment" => comment}
%{"op" => "reply", "thread" => "t1", "comment" => comment}
%{"op" => "edit", "thread" => "t1", "comment" => "c1", "body" => "...", "mentions" => [], "at" => time}
%{"op" => "delete", "thread" => "t1", "comment" => "c1"}
%{"op" => "react", "thread" => "t1", "comment" => "c1", "emoji" => "👍"}
%{"op" => "unreact", "thread" => "t1", "comment" => "c1", "emoji" => "👍"}
%{"op" => "resolve", "thread" => "t1", "at" => time}
%{"op" => "reopen", "thread" => "t1"}
%{"op" => "place", "thread" => "t1", "place" => place}A new comment ("comment" of start and reply) is %{"id", "author", "body", "mentions", "at"}. Its author's key is the key of whoever made
the transaction (the engine's :author option), and only its author
edits or deletes it; a reaction is the author's own. Deleting a thread's
last comment deletes the thread. Anyone who may comment resolves,
reopens and places a thread (a component places it again as its content
moves).
Concurrent changes merge: a reply, an edit, a reaction to a thread or a
comment that is gone does nothing, as does resolving a resolved thread.
The time of a comment is its writer's: Issho.Comments holds it, and
the author's name, to the writer's signed identity and the server's
clock before the change is accepted.