Speclets

Intent

The intent of this document is to provide us with informal specifications for a bunch of small features that are, individually, light on technical detail, but nevertheless have a large group of features to be considered. This is here to make sure that we stay on the same page with regard to these specifications as we implement other things.

Groups

Thoughts

There will eventually be 2 kinds of groups within Quotient. The first type of group is an LJ-style "community", which is a SubStore, holds public data, etc. It is similar to a user you can't log in to, and there will be a root "group" powerup which maintains a pool of far-references to all of its members, so that the group can perform actions which update the members.

The other kind of group is much simpler, and that is the first one we are going to focus on: a pool of people that is aggregated within a person's address book. These kinds of "groups" have no web-space of their own, they're not active, and membership is decided upon entirely by the holder of the addressbook.

For the purposes of this spec I will suggest calling the former kind of group "community" and the latter "group", although I don't really like that terminology.

Requirements

There are two purposes that an address-book-based group needs to be able to serve: it should be possible to broadcast a message (typically over email) to the group, and it should be possible to assign the group a particular capability to the user's personal data (and later revoke it).

It should be easy to create and destroy groups on the fly, and they ought to be lightweight enough that there are no hard limits on the user's creation of groups. This is important because the user should be creating the finest-grained capabilities that are convenient for them, which may mean a variety of different levels / roles of trust encompassed by a large collection of groups.

Implementation Suggestions

There's not too much here except for "pool of people", but for two small problems. Because we want to be able to send email to the group, we have to suggest a primary email address for each group. For this reason it may be necessary to actually create a pool of objects which refer to a specific contact card on a person, which are for most purposes just people, but act as if the person they referred to only had one contact card. Visually it would be best if this were selectable from within the pool browser - it would be really cool if one of the columns in the pool had a dropdown on it.

The other thing to keep in mind is that communities may have multiple mailing lists associated with them, and the address-book abstraction should be the same.

Spammer Removal from Addressbook

Requirements

The addressbook should be as uncluttered as possible. Spammers should never show up. People that you heard from once probably shouldn't show up either.

Implementation Suggestions

It's a good idea to keep the addressbook clean, but it's bad to lose information. We should have 3 pools of people: people, spammers, and addressbook. "People" is a list of every person ever identified in any way by the system. This is a way for the system to remember things and recognize patterns. For the most part it is not user visible because it contains a lot of records. However, when doing things like generating statistics about your top senders, it would be useful to notice if one of your top senders was a spammer and still have them show up on your list.

The 'spammers' pool contains all known spammers. These are blacklisted people that you absolutely will never want to hear from (sorry, big@boss.com) and who you would like to penalize for sending you mail as much as possible. Nobody is ever immediately added to the spammers pool, because spammers may easily fake email addresses. However, there should be some threshhold (say, 100 messages categorized as spam with at least 20 read by the user) where this does happen.

The 'addressbook' pool is where the user keeps the first tier of users they actually care about. It's the lowest level of the VIP list. When they're typing an email address in the 'to' field of a client which can autocomplete (fingers crossed, here), the first autocompletions should all come from the addressbook pool. The easiest link to get to from the main UI should be the addressbook pool. This way, chances are that you'll find the person you're looking for more quickly, unless they're some very esoteric contact that you only spoke with once, but they're still only a few clicks away.

Journals for Modified objects

Thoughts

When certain things change, it's important to have metadata about those changes. Who changed it, when, a comment about the changed and what changed are all useful things to know.

Requirements

Several systems in Quotient, in particular Anvil, require the ability to see who changed what when. Since many systems guess about objects and then make changes to them, it should be possible to see what the "system actor" has done to a mutable application object as well.

These logs should be generated, viewed, and managed in a uniform way across different applications, so that the concept of a command journal is portrayed in as understandable a fashion as possible for the user.

Implementation Suggestions

Although this has non-trivial storage considerations, considering how important this kind of information is, it is probably worthwhile to persist every entry in the journal as a full-fledged item of its own in a pool. The journal entries should be command objects complete, if possible, both an 'undo' method which will attempt to reverse the action at any point (and NOT just roll back all subsequent actions). Those actions which do not have an undo should be clearly marked as such.

We should also create a survey (probably put into this document later) of all the different types of objects that require such a journal, and those which definiitely do not. It would be useful to classify what kind of mutations are best suited towards being journalled, and which objects are totally immutable in storage and we do not need to consider. (This would also have some nice benefits for caching.)

The "undo" capacity is important because in both the "multiuser" and the "system guess" situations, some changes might have been made to an object that the owner is really unhappy with. They should not have to manually revert the object unless there is no possible way to un-do and re-do the command. Also, the command should be able to stick around for a while, potentially being re-applyable or at least being visible for the original changer to come along, look at, and create a different change which is similar without losing their work.

A good mental exercise to figure out a wide variety of do/undo situations (and queries) that make sense would be considering code patches as command objects.

Capability Exchange

Requirements

A user should be able to give another user permission to modify their objects in certain ways, and also to do certain things on their behalf. The system for doing this should all be through capabilities, which is to say, rather than providing an access grid of a small, fixed number of operations (such as Read, Write, Execute) the operations should be invidivually named and spread throughout the system. This makes it easy to define security rules because rather than looking at a "security" screen and designing a UI to accomodate every exchange of role ever, the behavior of exchange is most closely associated with the object actually being affected.

These exchanges must be secure. It should be very easy for a user to give out permissions for simple operations such as allowing many other users to post to their blog. For example, issuing a capability to a group defined in their addressbook or defined in a community should be very easy. It should not be similarly easy to accidentally provide administrator privileges to someone else. Revoking access should be similarly easy.

Implementation Suggestions

Every capability-based action should be 'far' - avatar objects should never assume they're on the same server. However, capabilities should be objects which reside in a particular powerup-on-the-granted-user's pool and visible on a URL in the '/me' hierarchy; the /users/ URL tree is public, and is accessible with or without a session.

The goal of this URL structure is that, by requiring all users' security-oriented actions to be performed with a session, and within their own store (therefore with different URLs based on storeIDs, etc) all capability exchange will be explicitly in-system. In-system exchange is good because the E way of doing things, with copy-pasteable URLs, is only a good idea if the user's tools for moving URLs around between systems were generally secure, which they are certainly not.

Application code that wants to grant a capability should look something like this: IFarIndex(self.store).far(ICapabilityContainer, "grantCapability", self.createModifyingCapWithJournalName('nickname-for-user-being-granted-to')). In other words, it should bake any metadata that will be associated through the capability into the capability itself, and not rely on context at the time of the call. The 'serialization' mechanism to get from the granting object to the receiving avatar should preserve enough information to refer to the object directly by storeID to call it, but the only information exposed to the user in URLs should be storeIDs within their own store.

Although the central "permissions" screen for assigning permissions is difficult to do with a feature-rich system like this, a high-level view of all permissions which have been issued and to whom they have been issued is likely the best way to implement capability revocation.

End of Day Report

Requirements

At the end of their local-timezone-specified day, the user should receive a message summarizing what Quotient did for them that day, and what the user has left for themselves to do. The report should be concise, but pleasant to read. The desired effect of these reports is that the user feels as though the software is providing useful functionality, since much of it is otherwise invisible, and has a better memory of what they have to do throughout their day.

It might be nice to generate these at various different time intervals to see which is most useful.

The report should include: