feat(mcp): report who wrote each scene component - #9547
Draft
eordano wants to merge 1 commit into
Draft
Conversation
The scene tools report what a scene's state says, never who put it there. For a networked scene that state is a merge — the scene's own JavaScript writes to it, and so does every peer in the scene room, including an authoritative game's server — and once merged the rows are indistinguishable. So "the crate moved" cannot answer "did the server move it, or did a client assert that it had?". Scenes on @dcl/sdk/network decide exactly that in validateBeforeChange, comparing the sender against 'authoritative-server'; nothing outside the scene could see the provenance those guards act on. Record it at the scene-room ingress, where the transport has already authenticated the sender, and surface it on the two tools that answer questions about scene state: - get_scene_state -> scene.networkWriters and scene.authoritativeMultiplayer - get_entity_details -> networkWrites, the last writer per component CrdtWriterLog walks the inbound CRDT batch read-only, applying CRDTFilter.ShouldDropIncoming (extracted from the existing filter, no behaviour change) so it never attributes a write the scene never received. It is inert until a consumer enables it — only the MCP server does — so a normal session pays one branch per inbound message. Two things the log must not claim: An answer to a CRDT state request replays writes its sender did not necessarily author, including the server's — which is how a client joining mid-game hydrates. Crediting those rows to the relaying peer would break the authorship test this feature exists for, so they carry viaStateSync, count into stateSyncWrites rather than writes, and never report isAuthoritativeServer. Both per-scene budgets (4096 components, 128 addresses) are checked before either table is written, so an entity can never name an address the scene-level summary omits, and every refused write is counted into droppedWriteRecords rather than silently forgotten. Only inbound network writes are recorded: a component absent from the report was written locally by the scene, not never written. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016tUtGrug72v6SK8Mv5qmpV
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The scene tools report what a scene's state says, never who put it there. For a networked scene that state is a merge — the scene's own JavaScript writes to it, and so does every peer in the scene room, including an authoritative game's server — and once merged the rows are indistinguishable. So "the crate moved" cannot answer "did the server move it, or did a client assert that it had?". Scenes on @dcl/sdk/network decide exactly that in validateBeforeChange, comparing the sender against 'authoritative-server'; nothing outside the scene could see the provenance those guards act on.
Record it at the scene-room ingress, where the transport has already authenticated the sender, and surface it on the two tools that answer questions about scene state:
CrdtWriterLog walks the inbound CRDT batch read-only, applying CRDTFilter.ShouldDropIncoming (extracted from the existing filter, no behaviour change) so it never attributes a write the scene never received. It is inert until a consumer enables it — only the MCP server does — so a normal session pays one branch per inbound message.
Two things the log must not claim:
An answer to a CRDT state request replays writes its sender did not necessarily author, including the server's — which is how a client joining mid-game hydrates. Crediting those rows to the relaying peer would break the authorship test this feature exists for, so they carry viaStateSync, count into stateSyncWrites rather than writes, and never report isAuthoritativeServer.
Both per-scene budgets (4096 components, 128 addresses) are checked before either table is written, so an entity can never name an address the scene-level summary omits, and every refused write is counted into droppedWriteRecords rather than silently forgotten.
Only inbound network writes are recorded: a component absent from the report was written locally by the scene, not never written.