feat: semantic logging - edit attribution, debounce, vpath resolution - #29
Draft
petergaultney wants to merge 2 commits into
Draft
petergaultney wants to merge 2 commits into
petergaultney wants to merge 2 commits into
Conversation
…pression Three behavioral additions, all backward compatible: 1. allowed_client_versions (relay.toml [server] field): when non-empty, doc websocket connections must report one of the listed plugin versions via the `v` query param. Server tokens are exempt. Denial warns are throttled to one per user per 30 minutes. 2. cid query param + relayClientIds awareness field: a plugin can pre-declare the Yjs client ids it mints (e.g. a merge working copy), binding them to its reported version at connect time. Also registers declared ids in PUD at upgrade, so the authenticated user is bound before any update can mis-attribute them. 3. Server-only update suppression: updates authored entirely by the server's own 53-bit client ids (PUD registration writes) skip the normal event callback path, suppressing the webhook dispatch that would otherwise fire for internal bookkeeping. Supporting infrastructure: - client_versions.rs: per-client-id version tracking with declared (owner-minted) and inferred (first-introduction) trust levels - edit_author.rs: client-id extraction from updates, is_server_only_update - AwarenessEntryFacts struct on DocConnection for typed awareness parsing - PUD registration made public so the cid upgrade path can call it - doc_id on DocConnection, so its log lines can name the doc
…, and /client-versions Adds a `semantic_logging` flag (default false) that enables operational visibility features for self-hosters who want to know who edited what: - Edit attribution: resolves the PUD map to name the user behind each update, not just the connection that delivered it. - Debounce: collapses keystroke runs into one logged edit burst, so typing a sentence produces one "Doc edited" line instead of dozens. - Vpath resolution: translates doc GUIDs to vault-relative file paths in log lines, so an operator reads "notes/standup.md" instead of a 73-character GUID. - Folder membership logging: reports adds, removes, and renames as they happen, with the user who made the change. - Large deletion detection: logs when an update grows the delete set by 5000+ clock units. - /client-versions endpoint: server-auth-gated JSON of every known client id, its plugin version, and its display name. - user_names config: an id->name map in relay.toml for log readability. All of these are gated on `semantic_logging = true`. With the default false, the server behaves identically to the base behavioral PR.
dtkav
pushed a commit
that referenced
this pull request
Aug 31, 2026
The event callback's captured user describes whichever connection first loaded the doc, not the edit in hand. The doc itself holds the truth: PermanentUserData records client_id -> user, and an update names the clients it came from. Lifted from #29 into y-sweet-core (rather than relay) so the doc's own update observer can reach it.
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.
Summary
Adds an opt-in
semantic_loggingmode (default off) that gives self-hosters visibility into who is editing what, without exposing user-identifying information unless explicitly configured.When
semantic_logging = truein relay.toml:vpath=daily/2026-08-14.md) instead of raw doc GUIDs.deleted_name/deleted_user/deleted_clients- the owner of the removed entries, which is the only identity a deletion contains./client-versionsendpoint: returns every known client-id-to-version binding as JSON. Server-auth required (Bearer token). Only mounted whensemantic_loggingis on.[server.user_names]table maps relay user ids to human-readable names for log lines. Only consulted whensemantic_loggingis on.When
semantic_logging = false(default), the server behaves identically to the base (PR #23) - no names, no vpaths, no edit lines, no endpoint.Deletion attribution
A yjs update records who wrote blocks, never who deleted them: a deletion is a delete set of (client, clock) ranges, and those client ids are the ids of the deleted blocks' authors. Reading the delete set as "the actor" therefore blames the original writer for someone else's deletion - one person's bulk cleanup of stale files was logged as three different users, each the file's last writer, before this was caught.
So the rules here are:
user=/name=/clients=) are resolved from newly-created blocks only. A move (remove + insert in one transaction) still attributes to the mover through its inserted block.user=-: the deleting client is genuinely not present in the update.deleted_user/deleted_name/deleted_clients, naming whose entries were removed.New modules
edit_bursts.rs- keystroke collapse with configurable quiet period (10s default)vpath_index.rs- cached GUID-to-path resolution from folderfilemeta_v0mapsConfiguration
Relationship to the other open PRs
Depends on #23, which is the one real dependency in this set:
client_versions.declare()takes the display name added there,AwarenessEntryFactsis defined there, and the edit-attribution path reads the PUD registrations it introduces. Cross-fork branches can't be a GitHub base, so this targetsmainand the diff includes #23's commit - review onlyfeat: semantic logging - edit attribution, debounce, vpath resolution, and /client-versions.This PR changes no log levels; the demotions it once carried are in #26.
Test plan
semantic_loggingis false (default)Doc editedlines with correct vpath and user attribution when enableduser=-and names the entry's owner underdeleted_user(regression-tested inedit_author.rs)/client-versionsreturns 404 whensemantic_loggingis false/client-versionsrequires server auth when enabled