Protocol‎ > ‎Design Documents‎ > ‎

Explicit blip contributors design proposal

    January 2010

    Alex North (anorth@google.com), Dan Danilatos (danilatos@google.com)

    Objective

    This design proposes to replace implicit low-level blip contributors with a representation explicitly within wave data and an interpretation in the conversation model. This removes contributors from the worthiness calculation and makes ops which affect contributors properly invertible.

    Representing contributors explicitly introduces flexibility in attribution. In general an editor will be responsible for adding their own contributor entry. This also introduces some risk of abuse. This design proposes that authoritative author information will always be available in the deltas; for users this will initially be available in playback and may be highlighted where it differs from the contributor list list.

    Background

    Blip contributors are currently calculated by servers and clients from the authors of deltas containing ops applying to a blip. When an op is applied to a blip and the op is deemed "worthy" then the author of the op is added to the blip's contributor list. In-memory reverse operations remove contributors for mechanisms like playback but this information is not represented on the wire. Our ops are not invertible partly because whether the contributor list changes is not represented in the op. We can't change our definition of worthiness without invalidating all stored snapshots.

    Related to this proposal are designs to remove or explicitly represent all other blip metadata: last modified versions, last modified time, etc.

    Requirements

    Contributor information provided by operations should be invertible; that is, for any operation we must be able to calculate, without reference to the target of the op, an inverse operation which exactly reverses the original op's effect on a wavelet state. Metadata calculated when an op is applied to a wave is not invertible because the state before the op is required to calculate its effect.

    It is useful for some operations from some clients not to result in contributor attribution. The current mechanism for this is the worthiness predicate: if an op is not worthy (of making a wave become unread) then its author is not made a contributor. This conflation of the mechanisms of read/unread with contribution has thus far been acceptable, but is inflexible and relies on a static, globally shared worthiness predicate. Along with metadata, the worthiness predicate should be lifted from the operational core and made an application-level concept.

    A number of other mechanisms have been proposed for hiding contributors:

    • delegation would have ops from annotators like spelly attributed to the user for whom they act
    • a special system address such as "@googlewave.com" (with no user part) could be used and ignored by browser clients

    Regardless of how contributors are hidden from a default view, authoritative attribution must be available at a user's request. The deltas will always contain this authoritative information so we require means of exposing this to clients.

    Design Ideas

    From here on the term "contributor" refers to an explicit contribution, and the term "author" refers to the author of a delta which touches a blip. A blip's authors are the union of all delta authors for that blip.

    Contributors in the blip head

    Contributors are represented as a list associated with a blip. The ConversationBlip interface will be extended to support contributor addition and iteration, and provide events for contributor changes.

    interface ConversationBlip {

    // ...

    Iterable<ParticipantId> getContributors();

    // No-op if the contributor already exists

    void addContributor(ParticipantId contributor);

    }

    interface ObservableConversationBlip {

    interface Listener {

    // ...

    void contributorAdded(ParticipantId p);

    void contributorRemoved(ParticipantId p); // for playback

    }

    }


    The contributor list is represented in the <head> section in each blip document.

    <head>

    <contributors>

    <contributor a="fred@example.com" />

    <contributor a="bob@acmewave.com" />

    </contributors>

    </head>

    <body>

    <line/> ...

    </body>


    Each entry has a single attribute which is a wave address.

    The contributor list is interpreted as a list without duplicates. The first contributor in the list is the first added. If a duplicate contributor entry appears (possible under concurrent edits) the first entry is the canonical and others may be ignored or removed.

    By convention, a client is responsible for adding a contributor entry, if there is not one already, when submitting meaningful changes to a blip. A contributor is added by appending an element to the contributor list. A contributor is removed by removing all elements with that contributors address from the list (but there is no use case for this yet).

    Contributors are represented in the blip header as the contributor list forms part of what might be considered the "final state" of a blip (as opposed to, say, sessions which are transient state). Being part of the per-blip "content" rather than structure, the blip document is a more appropriate and simpler location than in the conversation manifest. A consequence of this representation is that a client needs to load a blip's content in order to process its contributors.

    Creating blips

    When creating a blip, clients (via the conversation model) create the <head> and empty <contributors> elements along with the <body><line/></body> preamble as part of the first write to the blip's document. In the unlikely event of multiple clients attempting to initialise the same blip, the first <head> entry, in document order (which, after an upcoming change to transform will be the first one to reach the server), is taken to be the canonical one and any others ignored. This is an example of a general resolution strategy for duplicated "singleton" elements.

    Extensibility

    The contributor representation is extensible. Either attributes or child elements may be added to the contributor entries to support future functionality. The conversation model will ignore all unexpected attributes or child elements.

    Enforcement

    This design proposes no enforcement of explicit contributor representation. That is, it is not enforced that clients must add themselves as contributors before editing or must add an address matching the operation author. This decision is made in favour of flexibility for current and future applications (but see below for authoritative attribution).

    The design does not preclude enforcement though. Various rules could be enforced alongside access control by servers.

    Authoritative attribution

    With an explicit contributor representation there is scope for abuse through neglecting to add a contributor entry, adding an entry falsely, adding an entry with an incorrect address and removing existing contributors. In some cases these actions are desirable (e.g. hiding system contributors, proxied addresses which are not real participants), but there are many that are not. This design mitigates abuse by providing authoritative attribution of changes without unreasonably restricting flexibility.

    The true authors of a document are always available as a union of the authors of deltas touching the document. It is not feasible to store these authors in blip metadata since such information is not invertible, but it may be calculated from any sequence of deltas.

    For a web client, the author list is calculated when snapshots are created. No worthiness predicate is used: all delta authors are included. The author list may be persisted since it need never be inverted. A web client may inspect the author list and compare it with the blip's explicit contributor list. Client policies beyond the scope of this design may choose to highlight when these lists differ depending on per-user trust preferences.

    Alternatives Considered

    Contributors could be stored in a separate document from the blip document. This would allow blip contributors to be processed, e.g. by access control or playback mechanisms, without processing the whole blip. Current use cases do not require this ability.

    Contributors could be stored in the conversation manifest document. This would also allow contributors to be processed without loading each blip's content. However, the conversation manifest describes only the structure of the conversation and nothing about its content, so blip contributors would be out of place represented here.

    Rather than representing them explicitly, another alternative considered is to remove explicit contributors entirely, calculating them always from deltas and using trust models to filter uninteresting ones. While simple, this reduces flexibility. It lacks the ability to proxy for another address or otherwise fake a contributor. It removes the ability for editors to specify whether they think their contribution is worth attributing, leaving the decision only to clients.