The topic list was validated but not deduplicated, and it is scanned for
every retained event while the log's lock is held, so a request repeating
one topic thousands of times multiplied that work. Repeats collapse and a
list naming all is just all.
Review follow-up on #1766: a backward wall-clock step between the push and the test read made the ordering assertion flaky.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
The event log read the clock through std::time::SystemTime and Instant, which panic on wasm32-unknown-unknown ("time not implemented on this platform"). Every mutating comment.* command appends an event, so the first comment posted in the web build hit it. The log now takes SystemTime, UNIX_EPOCH and Instant from web_time, as the rest of the engine does. A test checks the stamp is a current Unix time read through the same clock.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Comments become the task queue for an attached or headless MCP client: comment.prompt returns a bounded Markdown brief, the Comments panel gains Copy for AI, and the MCP server exposes fix_comments, watch_comments, figcraft://comments and wait_for_changes. Mutating comment.* commands append to a bounded in-memory event log; the control channel's events.poll long-polls it without the UI thread, and a successful batch commits its events only if the whole batch lands. No model, network dependency, asset or file-format change.