on master help sign in
change graph-store diagrams to svg and add missing

- change from png to svg - upload to media.urbit.org - change from html tags to markdown - upload missing diagram and change to media.urbit.org

commit04efc7f31cdc27e0f782b20d83b716f1dd14dd9f authortinnus-napbus <admin@tinnus-napbus.xyz> dateTue 28 Sep 2021, 20:22 (5 years ago) parent6441f64
3 files changed+111−128
content/docs/userspace/graph-store/overview.md+15−21 content/docs/userspace/graph-store/sample-application-overview.md+58−58 content/docs/userspace/graph-store/validator-walkthrough.md+38−49
content/docs/userspace/graph-store/overview.md+15−21
@@ -6,52 +6,47 @@ template = "doc.html"
66insert_anchor_links = "right"
77+++
88
9−
109## Intro
10+
1111Graph store is a non-relational database suitable for use in building social media applications. It is primarily designed for storing text-based content and data that is generally threaded and nested. It is not suitable as a general purpose database for highly structured or pure binary data.
1212
13−<p align="center">
14− <img src="https://media.urbit.org/docs/userspace/graph-store/1_graph_store_overview.png"/>
15−</p>
13+![Graph Store Overview Diagram](https://media.urbit.org/docs/userspace/graph-store/1_graph_store_overview.svg)
1614
1715Graph Store is mainly in charge of two things: data storage and retrieval, and schema validation. There are two related tools: Graph Push Hook, which provides permissioning support to Graph Store and acts as a proxy layer to Graph Store for outside ships to access, and Graph Pull Hook, which can be used to request Graph Store data from other ships. Importantly, Graph Store itself does not have a built-in permissions system (or rather, is permissions-agnostic), and acts in a purely trusted manner, and assumes that all inputs are trusted. However, it only allows local, authenticated connections to communicate with it, meaning that by default, no one else on the network may modify the state of your Graph Store agent. This is why Graph Push Hook exists: to mediate untrusted requests from outside ships to your instance of Graph Store, rejecting invalid ones where a ship should not be able to modify the data.
1816
1917## Data Structures
18+
2019### Posts
2120
22−<p align="center">
23− <img src="https://media.urbit.org/docs/userspace/graph-store/2_post_diagram.png"/>
24−</p>
21+![Post Diagram](https://media.urbit.org/docs/userspace/graph-store/2_post_diagram.svg)
2522
2623Above, we can see a representation of a post on the left, along with its table form on the right.
2724A post is the most basic building block of a graph.
2825Every post is made up of an:
26+
2927- **Author** - who created the post
3028- **Index** - the unique path/identifier of the post on the graph (more on this later)
3129- **Time Sent** - when the post was created
3230- **Contents** - data that the user intended to post
3331
3432Currently, Graph Store supports 5 data types for content that is to be stored within a graph:
33+
3534- **Text** - plain text data
3635- **Url** - specific data type for urls
3736- **Mention** - mentioning another ship
3837- **Code** - a pair of a piece of code that was executed and its result (this is static data, and is not used to execute code on other's ships)
3938- **Reference** - a reference to another post
4039
41−
4240### Graphs and Nodes
4341
44−<p align="center">
45− <img src="https://media.urbit.org/docs/userspace/graph-store/3_graph_node_diagram_a.png"/>
46−</p>
42+![Graph Node Diagram A](https://media.urbit.org/docs/userspace/graph-store/3_graph_node_diagram_a.svg)
4743
48−<p align="center">
49− <img src="https://media.urbit.org/docs/userspace/graph-store/4_graph_node_diagram_b.png"/>
50−</p>
44+![Graph Node Diagram B](https://media.urbit.org/docs/userspace/graph-store/4_graph_node_diagram_b.svg)
5145
5246A graph is a flat, ordered map of nodes, where each node can have a child graph, which is itself a flat ordered map of nodes. Nodes contain a post and a child graph. In the above diagram, we can see an example of a basic graph on the top, along with the underlying structure of the data in table form underneath.
5347
5448A few vocab terms:
49+
5550- **Root graph** refers to the outermost graph, G in this case
5651- **Top level** is a loose term usually used to refer to a node that exists in the root graph. **A** and **D** would be considered nodes at the top level, but **B** and all its descendants would not qualify.
5752- **Sibling nodes** are two nodes that reside next to each other, meaning that they reside in the same `graph`. **A** and **D** are an example of sibling nodes.
@@ -62,27 +57,23 @@ A few vocab terms:
6257
6358### Index
6459
65−<p align="center">
66− <img src="https://media.urbit.org/docs/userspace/graph-store/5_index_diagram.png"/>
67−</p>
60+![Index Diagram](https://media.urbit.org/docs/userspace/graph-store/5_index_diagram.svg)
6861
6962Indexes are a way of uniquely identifying a node within a graph. You can think of `index`es as similar to file paths, although they aren't exactly the same. Roughly, a file path is a unique reference to a file or folder located in the filesystem. Similarly, an index is a unique reference to a node nested within a graph. The written syntax for a full index is very similar to file paths. It consists of every index fragment in order separated by a slash. A node's **level of nesting** refers to how deeply it is nested within the context of the root graph. The level of nesting directly corresponds to the number of items in the index. An index fragment is the atom by which a node is uniquely identified within it's graph, and roughly corresponds to a specific name of a directory along a path. In the diagrams that follow, we'll use the index fragment instead of the index to avoid repeating redundant information, but please note that internally graph-store still store the full index in every node's post.
7063
7164In the above diagram, we would say that nodes **A** and **D** are nested 1 level deep, while **B** would be at the 2nd level of nesting, and **C** would be nested 3 levels deep.
7265
7366Indexes are usually numbers and are stored as such in the database. Most commonly, they can represent:
67+
7468- Date or time of posting
7569- A sequence of numbers starting from 1 increasing
7670- Structural/constant value: values which are associated with a specific meaning in the context of the schema of an application.
7771
7872However, there is no strict requirement for them to be numbers; they can be cords as well as other data types. As we'll see in the later sections, it is up to the app developer to decide this when creating their application.
7973
80−
8174### Structural Nodes vs. Content-Centric Nodes
8275
83−<p align="center">
84− <img src="https://media.urbit.org/docs/userspace/graph-store/6_structural_vs_content_centric_diagram.png"/>
85−</p>
76+![Structural vs Content-centric Diagram](https://media.urbit.org/docs/userspace/graph-store/6_structural_vs_content_centric_diagram.svg)
8677
8778When using Graph Store, there is a notion of **structural nodes** vs. **content-centric nodes**. In the example diagram, we've color coded the different nodes based on what type of node they are. **Content-centric nodes** represent data created or consumed directly by the user. **Structural nodes**, on the other hand do not directly represent user data, and instead represent a higher level relationship between different user data. Structural nodes are used to implement the structure of the schema that is being implemented. In other words, they exist away from the eyes of the user, solely for organizational purposes.
8879
@@ -95,15 +86,18 @@ Every social application has a minimum amount of information it needs to functio
9586In addition, validators can also encode structural permissions. **Structural permissions** govern who is allowed to add or remove a given node (and by extension modify its children) based on the node's characteristics.
9687
9788There are 3 different classes of users:
89+
9890- **Admin** - An owner of a resource or someone who's been delegated similar privileges
9991- **Writer** - Someone who can create and modify their own content but cannot modify others'
10092- **Reader** - Someone who is only given permission to access but not create or modify, except in special cases
10193
10294There are two different types of privileges:
95+
10396- **Add privileges** - permission to create a given node and create any child nodes
10497- **Remove privileges** - permission to remove a given node and remove any of its children
10598
10699There are also three different levels of access a given permission level can have:
100+
107101- **%no** - user does not have add or remove privileges for this node
108102- **%yes** - user has add or remove privileges for this node, whether or not they authored the parent node
109103- **%self** - user has add or remove privileges for child nodes only if they authored the parent node (determined by `author` of post, i.e., they are the author of the post)
content/docs/userspace/graph-store/sample-application-overview.md+58−58
@@ -6,28 +6,26 @@ template = "doc.html"
66insert_anchor_links = "right"
77+++
88
9−
10−
11−Library is a sample social media application in which you can create a collection of books, called a library, which can contain any number of books.
12−You can share individual collections per-ship. The creator of the collection has de-facto admin powers; he is the only one who can add or remove books to/from the library,
13−remove the library itself, and add comments or remove anyone's comments. Guest ships may request access to specific libraries, which if granted,
9+Library is a sample social media application in which you can create a collection of books, called a library, which can contain any number of books.
10+You can share individual collections per-ship. The creator of the collection has de-facto admin powers; he is the only one who can add or remove books to/from the library,
11+remove the library itself, and add comments or remove anyone's comments. Guest ships may request access to specific libraries, which if granted,
1412allows them to request any book from the library.
1513
1614Using this application, you can:
1715
18−- Create libraries, where a library is a collection of books
19−- Add and remove books from a library, if you are the owner
20−- Allow others to view your library based on various permissioning schemes (policies)
21−- Add and remove comments from a library, if you are the owner or were granted access
16+- Create libraries, where a library is a collection of books
17+- Add and remove books from a library, if you are the owner
18+- Allow others to view your library based on various permissioning schemes (policies)
19+- Add and remove comments from a library, if you are the owner or were granted access
2220
2321## Prerequisites
2422
25−This overview is a companion document to the *Library* application, and assumes you are familiar with `%graph-store`. Before continuing, **you must familiarize yourself with the sample application**, which can be found [here](https://github.com/ynx0/library). See the [detailed usage guide](https://github.com/ynx0/library/blob/master/README.md) for download and installation instructions.
26−
23+This overview is a companion document to the _Library_ application, and assumes you are familiar with `%graph-store`. Before continuing, **you must familiarize yourself with the sample application**, which can be found [here](https://github.com/ynx0/library). See the [detailed usage guide](https://github.com/ynx0/library/blob/master/README.md) for download and installation instructions.
2724
2825## Project Structure
2926
3027Here is the directory structure of our app.
28+
3129```
3230├── app
3331│ └── library-proxy.hoon
@@ -58,29 +56,28 @@ Here is the directory structure of our app.
5856
5957- [`install.sh`](https://github.com/ynx0/library/blob/master/install.sh) is a script that automates copying the source files into a ship's pier / home desk.
6058
61−
6259## Implementation Summary
6360
6461The project contains a custom `%graph-store` validator tht specifies the application's schema and a custom gall agent, called `%library-proxy`, which sends `%graph-store` updates between the host ship and subscribers.
65−The gall agent also generates `%graph-store` updates based on commands and actions that a user issues. Commands can only be issued to a proxy by the ship owner,
66−while actions can be issued by any ship, but may fail based on permissions. A host ship's `%library-proxy` talks to the subscriber ship's `%library-proxy` through the normal gall app channels (pokes/peeks)
67−to send them any updates that have taken place on the library graph. It is the host's responsibility to forward all relevant updates to subscribers
62+The gall agent also generates `%graph-store` updates based on commands and actions that a user issues. Commands can only be issued to a proxy by the ship owner,
63+while actions can be issued by any ship, but may fail based on permissions. A host ship's `%library-proxy` talks to the subscriber ship's `%library-proxy` through the normal gall app channels (pokes/peeks)
64+to send them any updates that have taken place on the library graph. It is the host's responsibility to forward all relevant updates to subscribers
6865(kept track of in a data structure defined [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/sur/library.hoon#L14-L15)),
6966while subscribers must only trust graph updates that it receives from the owner of that resource.
7067
7168Here are the proxy's responsibilities:
7269
73−- **Application-specific API** - presents an interface for a user to interact with both his/her own library proxy and others' by directly defining and implementing a user-facing API as pokes and scries,
74− as opposed to forcing the user to deal with the graph-store API directly. The `command`/`action`/`response` poke types are defined [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/sur/library.hoon#L17-L42),
75− while the scries are defined [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/app/library-proxy.hoon#L132).
76−- **Graph store update creation** - creates the appropriate graph update for a given user-facing action
77−- **Graph store update proxying** - handles the networking and subscription logic required to send graph store updates between host and subscriber
78−- **Access control** - allows or denies ships access to libraries, checks for proper permissions before processing a `command` or `action`
70+- **Application-specific API** - presents an interface for a user to interact with both his/her own library proxy and others' by directly defining and implementing a user-facing API as pokes and scries,
71+ as opposed to forcing the user to deal with the graph-store API directly. The `command`/`action`/`response` poke types are defined [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/sur/library.hoon#L17-L42),
72+ while the scries are defined [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/app/library-proxy.hoon#L132).
73+- **Graph store update creation** - creates the appropriate graph update for a given user-facing action
74+- **Graph store update proxying** - handles the networking and subscription logic required to send graph store updates between host and subscriber
75+- **Access control** - allows or denies ships access to libraries, checks for proper permissions before processing a `command` or `action`
7976
8077## Interaction with `%graph-store`
8178
8279There are a couple of ways that our application uses and interacts with `%graph-store`.
83−Firstly, the app subscribes to `%graph-store` in `+on-init` on path `/updates`, meaning it will be notified of every single `graph-update` that occurs on the local ship. (*Recall the type of `graph-update`, defined [here](https://github.com/urbit/urbit/blob/ceed4b78d068d7cb70350b3cd04e7525df1c7e2d/pkg/arvo/sur/graph-store.hoon#L29), the reference for which can be found [here](https://urbit.org/docs/userspace/graph-store/data-structure-overview/#update-part-1)*). We also define a validator for our application that `%graph-store` uses for every *Library* graph. Since `%graph-store` registers all validators under the path `%/graph/validator/<name of app>/hoon`, we don't have to do anything special to register our validator. We just need to correctly name our file, and provide an `+graph-indexed-post` arm which should perform all schema validation.
80+Firstly, the app subscribes to `%graph-store` in `+on-init` on path `/updates`, meaning it will be notified of every single `graph-update` that occurs on the local ship. (_Recall the type of `graph-update`, defined [here](https://github.com/urbit/urbit/blob/ceed4b78d068d7cb70350b3cd04e7525df1c7e2d/pkg/arvo/sur/graph-store.hoon#L29), the reference for which can be found [here](https://urbit.org/docs/userspace/graph-store/data-structure-overview/#update-part-1)_). We also define a validator for our application that `%graph-store` uses for every _Library_ graph. Since `%graph-store` registers all validators under the path `%/graph/validator/<name of app>/hoon`, we don't have to do anything special to register our validator. We just need to correctly name our file, and provide an `+graph-indexed-post` arm which should perform all schema validation.
8481
8582### Synchronizing Graphs Between Ships
8683
@@ -88,7 +85,7 @@ An owner is responsible for forwarding any updates to clients. Whenever the `%li
8885
8986On the receiving end, since we know that we are not the source of the `graph-update`, we handle the update in the `handle-incoming-graph-store` helper arm, which makes sure to only process and forward graph store updates to local graph store that are sent by the owner, and no one else. Once it passes this permissions check, it is poked into the local graph like any other graph-update.
9087
91−\**One could imagine a gossip style protocol where the data is like a fact so it doesn't matter where it came from, but in this app the library host is defined as the source of truth.*
88+\*_One could imagine a gossip style protocol where the data is like a fact so it doesn't matter where it came from, but in this app the library host is defined as the source of truth._
9289
9390## Data Model
9491
@@ -99,7 +96,7 @@ meant to represent a comment on any given book.
9996
10097### Representing Data using `%graph-store`
10198
102−The data types we defined for our application do not fit within `%graph-store` out of the box. `%graph-store` doesn't allow arbitrarily typed data in a node's content field, so we create an ad-hoc representation that we can cleanly convert to and from our own data types and `%graph-store` types.
99+The data types we defined for our application do not fit within `%graph-store` out of the box. `%graph-store` doesn't allow arbitrarily typed data in a node's content field, so we create an ad-hoc representation that we can cleanly convert to and from our own data types and `%graph-store` types.
103100
104101Here is the conversion code: [(link)](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/lib/library.hoon#L12-L19)
105102
@@ -120,28 +117,28 @@ Each arm takes in either a `book` or a `comment`, our application specific data
120117
121118We define 3 core structures:
122119
123−- **Library** - The fundamental data structure. A library is a graph that contains books
124−- **Book** - A data structure that contains an entry of a given book's metadata (i.e. title and isbn) and any comments associated with it. It is represented by a top-level node within a library graph
125−- **Comment** - A node that represents a user's comment on a given book. Represented as a child node of a book's comment container node.
120+- **Library** - The fundamental data structure. A library is a graph that contains books
121+- **Book** - A data structure that contains an entry of a given book's metadata (i.e. title and isbn) and any comments associated with it. It is represented by a top-level node within a library graph
122+- **Comment** - A node that represents a user's comment on a given book. Represented as a child node of a book's comment container node.
126123
127124We then define the layout of the data as follows:
128125
129−* Library
130− - Book
131− + Metadata Revision Container
132− * Specific Metadata Revision
133− + Comments Container
134− * Specific Comment
126+- Library
127+ - Book
128+ - Metadata Revision Container
129+ - Specific Metadata Revision
130+ - Comments Container
131+ - Specific Comment
135132
136−Every graph created with the `%graph-validator-library` is a *Library* graph, and thus it has the following characteristics:
133+Every graph created with the `%graph-validator-library` is a _Library_ graph, and thus it has the following characteristics:
137134
138−- Every Library graph represents a library, or a collection of books
139−- Every top level node in a library represents a book and all related contents
140−- Within a book there are always two structural nodes: a container node for metadata revisions, and a container node that holds all comments, modeling a comments section
135+- Every Library graph represents a library, or a collection of books
136+- Every top level node in a library represents a book and all related contents
137+- Within a book there are always two structural nodes: a container node for metadata revisions, and a container node that holds all comments, modeling a comments section
141138
142139To make things more concrete, let's look at an example of an actual graph.
143140
144−(*For the sake of clarity, we have replaced each index with its representation in its original aura in following output.*)
141+(_For the sake of clarity, we have replaced each index with its representation in its original aura in following output._)
145142
146143```
147144[ p=[entity=~zod name=%library1]
@@ -261,17 +258,17 @@ To make things more concrete, let's look at an example of an actual graph.
261258]
262259```
263260
264−![](https://lh5.googleusercontent.com/UTCnXumWvuPpFtduxgzmxIR_vhn9N3SylJ9h-MoUjYWiCT4AZo4BXY1mWceu0iHcJjesWoBDzMVO9QYWbnqtsGWa4nt4GlIRAtiC2zSXLkDUEttTmlMDLS7XRZ7ZhJyEayaMMl2r)
261+![Library App Schema Diagram](https://media.urbit.org/docs/userspace/graph-store/library-app-schema-diagram.svg)
265262
266−* The above graph represents a library that has a single book, whose metadata is stored under the `%meta` revision container. The metadata associated with this specific book entry is currently with title: `"Dune"` and isbn `"0441172717"`.
263+- The above graph represents a library that has a single book, whose metadata is stored under the `%meta` revision container. The metadata associated with this specific book entry is currently with title: `"Dune"` and isbn `"0441172717"`.
267264 The reason we have a revision container for the book metadata is so that in case someone makes an error, they may correct it. A potential frontend could then simply show the most recent version.
268−* Each comment is simply a node under a book's `%comment` node with a single `%text` content.
265+- Each comment is simply a node under a book's `%comment` node with a single `%text` content.
269266 We skipped revision containers for comments to keep schema simple, but you could imagine duplicating the same logic for comments as well.
270−* Every book node has an index the datetime of when it was created.
271−* Each structural node in a book has a constant index fragment, either `%meta` for the metadata revision container node,
267+- Every book node has an index the datetime of when it was created.
268+- Each structural node in a book has a constant index fragment, either `%meta` for the metadata revision container node,
272269 or `%comments` for the comments container node.
273−* Every comment has an index of the datetime of when it was posted.
274−* The metadata revisions are a single incrementing number starting from 1, so the initial metadata has a revision count of `1`, and a subsequent edit has a revision count of `2`, and so on.
270+- Every comment has an index of the datetime of when it was posted.
271+- The metadata revisions are a single incrementing number starting from 1, so the initial metadata has a revision count of `1`, and a subsequent edit has a revision count of `2`, and so on.
275272
276273### Schema Enforcement
277274
@@ -280,12 +277,12 @@ Take a moment to read through it and cross-check your understanding with the fol
280277
281278**Validator logic summary**
282279
283−- None of the structural nodes require data, so we simply assert that their contents are empty
284−- For a *Specific Comment Node*, a post with an index matching the structure `[@ %comments @ ~]`, we assert that `contents` only contains a single `%text` content.
285− This choice is arbitrary but meant to keep the application simple and so that a potential frontend does not have to do complex rendering.
286−- For a *Specific Metadata Revision*, a post with index matching the structure `[@ %meta @ ~]`, we first ensure that it's contents only contain two `%text` content instances.
287− We then use two helper arms `+is-title-valid` and `+is-isbn-valid` to validate the two values. For us, any title value is accepted, while only strings with length 10 or 13 are valid ISBNs.
288− (We don't do any true ISBN validation for simplicity's sake)
280+- None of the structural nodes require data, so we simply assert that their contents are empty
281+- For a _Specific Comment Node_, a post with an index matching the structure `[@ %comments @ ~]`, we assert that `contents` only contains a single `%text` content.
282+ This choice is arbitrary but meant to keep the application simple and so that a potential frontend does not have to do complex rendering.
283+- For a _Specific Metadata Revision_, a post with index matching the structure `[@ %meta @ ~]`, we first ensure that it's contents only contain two `%text` content instances.
284+ We then use two helper arms `+is-title-valid` and `+is-isbn-valid` to validate the two values. For us, any title value is accepted, while only strings with length 10 or 13 are valid ISBNs.
285+ (We don't do any true ISBN validation for simplicity's sake)
289286
290287## Access Control
291288
@@ -296,6 +293,7 @@ which are set by the user per-library at the time of creation (stored [here](htt
296293These specify who can or cannot gain access to a library.
297294
298295Here's what `policy` looks like:
296+
299297```
300298+$ policy
301299 $% [%open ~] :: any ship is allowed
@@ -307,13 +305,14 @@ Here's what `policy` looks like:
307305There are also implicit rules, defined as follows:
308306
309307For any given library that one owns,
308+
310309- An owner can:
311− + add a top level book node to any library
312− + add a metadata revision to any book
313− + add or remove any comment on any book
310+ - add a top level book node to any library
311+ - add a metadata revision to any book
312+ - add or remove any comment on any book
314313- A reader, that is, a another ship granted access to the library, can:
315− + add a comment to any book that they have requested
316− + remove any comment that they are the author of
314+ - add a comment to any book that they have requested
315+ - remove any comment that they are the author of
317316
318317Implicitly, all readers are given permission to get any book when granted access to the library.
319318
@@ -323,6 +322,7 @@ Implicitly, all readers are given permission to get any book when granted access
323322
324323- The `+is-allowed` arm, (found [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/lib/library.hoon#L21))
325324 implements each `policy`'s behavior, and is reproduced below.
325+
326326 ```
327327 ++ is-allowed
328328 |= [requester=ship host=ship =policy:library]
@@ -335,8 +335,8 @@ Implicitly, all readers are given permission to get any book when granted access
335335 %whitelist (~(has in ships.policy) requester)
336336 ==
337337 ```
338− Given the host ship of a resource and the policy to be enforced for a resource, `+is-allowed` returns a boolean for whether or not a requesting ship should be allowed access to that resource.
339338
339+ Given the host ship of a resource and the policy to be enforced for a resource, `+is-allowed` returns a boolean for whether or not a requesting ship should be allowed access to that resource.
340340
341341- `+is-allowed` is used in `+on-watch` [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/app/library-proxy.hoon#L113), where it only allows a ship to subscribe to a library if it passes the permissions check.
342342- It is also used [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/app/library-proxy.hoon#L299) and [here](https://github.com/ynx0/library/blob/9104145bb24e8ec949a5e9685139665b07161dd6/app/library-proxy.hoon#L310), so that when a ship wants to know about what libraries and books exist, only data they are allowed to see gets revealed to them.
@@ -354,7 +354,7 @@ The permissioning scheme was also implemented relatively simple; it has some lim
354354### Comparison between `%library-proxy` and `%graph-push-hook`
355355
356356`%library-proxy` performs the functions of both `%graph-push-hook` and `%graph-pull-hook`.
357−`%graph-pull-hook` is responsible for asking other `%graph-push-hook`s for graph data
357+`%graph-pull-hook` is responsible for asking other `%graph-push-hook`s for graph data
358358by trying to initiate a subscription on the host ship's `%graph-push-hook`, which the host only allows if they have permissions.
359359When it succeeds, `%graph-push-hook` then sends out all `graph-updates` to those subscribers who need to hear about it.
360360`%graph-pull-hook` then merges in graph updates it hears into the local `%graph-store`.
content/docs/userspace/graph-store/validator-walkthrough.md+38−49
@@ -6,33 +6,32 @@ template = "doc.html"
66insert_anchor_links = "right"
77+++
88
9−
109## Schema and Permissioning Implementation
11−In this section, we will analyze various applications and see how they implement their schema and permissions.
1210
11+In this section, we will analyze various applications and see how they implement their schema and permissions.
1312
1413### Current State of Permissioning
14+
1515Please note that as it stands today, the current permissioning system is likely subject to change. It is by no means the only manner in which to set up permissionings. For many applications, writing a small and bespoke permissioning library may be suitable as an alternative to the `graph-push-hook` permissioning scheme which is what will be covered in the following examples.
1616
1717Also, please be aware that the current set of applications use a special type known as `vip-metadata`, which stands for "variation in permission".
1818It is extra metadata attached to a post that is available to the permissioning arms that is mainly used to specify whether reader comments are enabled or disabled.
1919Here's the source if you want to explore: [`sur/metadata-store.hoon#L20-L30`](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/sur/metadata-store.hoon#L20-L30)
2020
21−
2221### Chat
22+
2323#### Schema
24+
2425Here's what the schema of chat looks like:
2526
26−<p align="center">
27− <img src="https://media.urbit.org/docs/userspace/graph-store/7_chat_schema_diagram.png"/>
28−</p>
27+![Chat Schema Diagram](https://media.urbit.org/docs/userspace/graph-store/7_chat_schema_diagram.svg)
2928
3029A chat is a flat graph, where all chat messages are nodes appended to the root of the graph.
3130The graph represents a chat channel and contains all chat messages in order. A chat message is a child node of the root graph.
3231
33−
3432Here's the definition of the schema in the chat validator mark:
3533File: [`mar/graph/validator/chat.hoon`](https://github.com/urbit/urbit/blob/fbd85abf4e41d580654606a6defb764f6a97256d/pkg/arvo/mar/graph/validator/chat.hoon#L33-L40)
34+
3635```hoon
3736++ grab
3837 |%
@@ -46,6 +45,7 @@ File: [`mar/graph/validator/chat.hoon`](https://github.com/urbit/urbit/blob/fbd8
4645```
4746
4847Here are the steps:
48+
49491. Given a noun (we expect an indexed-post)
50501. Try to coerce p to an indexed-post, crash if it doesn't cast
51511. Assert that the index of the post of the indexed post is only a single atom, i.e., that it is only nested one level deep
@@ -57,13 +57,12 @@ Since the schema of the chat application is simple enough, it has no need for st
5757
5858#### Permissioning
5959
60−<p align="center">
61− <img src="https://media.urbit.org/docs/userspace/graph-store/8_chat_permissions_diagram.png"/>
62−</p>
60+![Chat Permissions Diagram](https://media.urbit.org/docs/userspace/graph-store/8_chat_permissions_diagram.svg)
6361
6462Let's take a look at the permissions table in the diagram.
6563
6664Chat Message `[@ ~]`
65+
6766- Add Privileges
6867 - Admins and Writers have `%yes` add permissions for all nodes at the top level, meaning that they have the ability to post chat messages, even if they did not create the chat channel
6968 - Readers have `%no` add privileges for any nodes at the root level, so they do not have the ability to post chat messages
@@ -77,6 +76,7 @@ For example, it wouldn't make sense to give readers `%self`, because they do not
7776Let's see how this permissioning system is implemented in the validator code.
7877
7978Here is the `grow` arm of [`mar/validator/chat.hoon`](https://github.com/urbit/urbit/blob/fbd85abf4e41d580654606a6defb764f6a97256d/pkg/arvo/mar/graph/validator/chat.hoon#L7-L20)
79+
8080```hoon
8181|_ i=indexed-post :: A
8282++ grow
@@ -100,13 +100,13 @@ Here is the `grow` arm of [`mar/validator/chat.hoon`](https://github.com/urbit/u
100100In line A, we accept an `indexed-post` that is used in the rest of the `grow` arm.
101101
102102`graph-permissions-add`
103+
1031041. Accept a noun `vip` of type `vip-metadata`
1041052. Switch on the index of the post found in `i`, crashing if no successful matches occur
1051063. If the index is nested one level deep
1061074. Return a `permissions` noun defined as: [admin: %yes, writer: %yes, reader: %no]
107108
108−
109− `graph-permissions-remove`
109+ `graph-permissions-remove`
110110
1111115. Accept a noun `vip` of type vip-metadata
1121126. Switch on the index, crashing if no successful matches occur
@@ -115,23 +115,21 @@ In line A, we accept an `indexed-post` that is used in the rest of the `grow` ar
115115
116116In this example, a switch statement is used to determine the `permissions` values based on the index of the post.
117117
118−
119118### Links
119+
120120#### Schema
121121
122−<p align="center">
123− <img src="https://media.urbit.org/docs/userspace/graph-store/9_link_schema_diagram.png"/>
124−</p>
122+![Link Schema Diagram](https://media.urbit.org/docs/userspace/graph-store/9_link_schema_diagram.svg)
125123
126124The root graph represents the whole Links collection. Every Links entry is a child node of this graph. Every Links entry is made up of:
125+
127126- The link and its description
128127- A comments section
129128
130−
131129The comments section holds all individual comment nodes, but comments are not simple leaf nodes. An individual comment is actually a structural node that acts as a revision container, storing the comment's full edit history by storing each edit as a child node. The front-end is responsible for properly displaying the latest revision of the comment.
132130
133−
134131Here's the validator, located at [`mar/graph/validator/link.hoon`](https://github.com/urbit/urbit/blob/fbd85abf4e41d580654606a6defb764f6a97256d/pkg/arvo/mar/graph/validator/link.hoon#L49-L73):
132+
135133```hoon
136134++ grab
137135 |%
@@ -160,7 +158,6 @@ Here's the validator, located at [`mar/graph/validator/link.hoon`](https://githu
160158 --
161159```
162160
163−
164161<ol>
165162 <li>Get the post as a noun</li>
166163 <li>Force cast to indexed post</li>
@@ -181,22 +178,17 @@ Here's the validator, located at [`mar/graph/validator/link.hoon`](https://githu
181178 </li>
182179</ol>
183180
184−
185181It is important to note that you cannot directly edit the url or link afterwards, only the whole link entry itself. This is because you can only add or remove nodes to a graph, not modify them. Comments, however, can be “edited”. This is possible by using a technique called a revision container. Instead of having a single leaf node holding the comment text in its contents, a node with empty contents is created. All revisions of the comment are added as children to this note, and the frontend simply shows the most recent one only.
186182
187183#### Permissioning
188184
189−<p align="center">
190− <img src="https://media.urbit.org/docs/userspace/graph-store/10_links_permissions_diagram_a.png"/>
191−</p>
185+![Links Permissions Diagram A](https://media.urbit.org/docs/userspace/graph-store/10_links_permissions_diagram_a.svg)
192186
193−<p align="center">
194− <img src="https://media.urbit.org/docs/userspace/graph-store/11_links_permissions_diagram_b.png"/>
195−</p>
187+![Links Permissions Diagram B](https://media.urbit.org/docs/userspace/graph-store/11_links_permissions_diagram_b.svg)
196188
197189Let's analyze the permissions structure.
198190
199−**TODO** *stubbed out awaiting potential changes in source*
191+**TODO** _stubbed out awaiting potential changes in source_
200192
201193Here's how it is implemented [(source)](https://github.com/urbit/urbit/blob/master/pkg/arvo/mar/graph/validator/link.hoon#L2-L27):
202194
@@ -222,13 +214,14 @@ Here's how it is implemented [(source)](https://github.com/urbit/urbit/blob/mast
222214 ?=(%reader-comments vip)
223215 ?+ index.p.i !! :: 6
224216 [@ ~] [%yes %self %self] :: 6a
225− [@ @ ~] [%yes %self %self] ::
226− [@ @ @ ~] [%yes %self %self] ::
217+ [@ @ ~] [%yes %self %self] ::
218+ [@ @ @ ~] [%yes %self %self] ::
227219 ==
228220 ::
229221```
230222
231223`graph-permissions-add`
224+
232225<ol>
233226 <li>Accept a noun <code>vip</code> of type vip-metadata
234227 <ul>
@@ -259,8 +252,8 @@ Here's how it is implemented [(source)](https://github.com/urbit/urbit/blob/mast
259252 </li>
260253</ol>
261254
262−
263255`graph-permissions-remove`
256+
264257<ol>
265258 <li>Accept a noun <code>vip</code> of type vip-metadata</li>
266259 <li>Declare a variable <code>reader</code>, a flag which is true if reader comments are enabled, false otherwise</li>
@@ -274,19 +267,16 @@ Here's how it is implemented [(source)](https://github.com/urbit/urbit/blob/mast
274267 </li>
275268</ol>
276269
277−
278−
279270### Publish
280271
281272#### Schema
282273
283−<p align="center">
284− <img src="https://media.urbit.org/docs/userspace/graph-store/12_publish_schema_diagram.png"/>
285−</p>
274+![Publish Schema Diagram](https://media.urbit.org/docs/userspace/graph-store/12_publish_schema_diagram.svg)
286275
287276Here, a notebook, which is a collection of blog posts (called notes), is represented by the root graph. All data associated with the blog post is represented by the top level node, which is the note itself along with the associated comments. One level deeper, we see two container structures. The first one is the post revision container; it holds the edit history of your blog post. Every child node of this corresponds to the actual title and text of your blog post. The second one is the comments container. This represents the comment section of your blog post. Every child node of this is not a comment, but a comment revision container, which, as before, contains the edit history of your comment.
288277
289278Here's its validator, located at [`mar/graph/validator.hoon`](https://github.com/urbit/urbit/blob/master/pkg/arvo/mar/graph/validator/publish.hoon#L56-L97)
279+
290280```hoon
291281 ++ noun
292282 |= p=* :: 1
@@ -330,7 +320,6 @@ Here's its validator, located at [`mar/graph/validator.hoon`](https://github.com
330320
331321Walkthrough
332322
333−
334323<ol>
335324 <li>Get the post as a noun</li>
336325 <li>Force cast to indexed post</li>
@@ -366,17 +355,13 @@ Notably, the revision container for the blog post itself allows the post to be e
366355
367356#### Permissioning
368357
369−<p align="center">
370− <img src="https://media.urbit.org/docs/userspace/graph-store/13_publish_permissions_diagram_a.png"/>
371−</p>
358+![Publish Permissions Diagram A](https://media.urbit.org/docs/userspace/graph-store/13_publish_permissions_diagram_a.svg)
372359
373−<p align="center">
374− <img src="https://media.urbit.org/docs/userspace/graph-store/14_publish_permissions_diagram_b.png"/>
375−</p>
360+![Publish Permissions Diagram B](https://media.urbit.org/docs/userspace/graph-store/14_publish_permissions_diagram_b.svg)
376361
377362Let's take a look at the permissioning structure for Publish.
378363
379−**TODO** *stubbed out awaiting potential changes in source*
364+**TODO** _stubbed out awaiting potential changes in source_
380365
381366[(source)](https://github.com/urbit/urbit/blob/fbd85abf4e41d580654606a6defb764f6a97256d/pkg/arvo/mar/graph/validator/publish.hoon#L6-L24)
382367
@@ -399,8 +384,8 @@ Let's take a look at the permissioning structure for Publish.
399384 ?+ index.p.i !! :: 4
400385 [@ ~] [%yes %self %self] :: 4a
401386 [@ %1 @ @ ~] [%yes %self %self] ::
402− [@ %2 @ ~] [%yes %self %self] ::
403− [@ %2 @ @ ~] [%yes %self %self] ::
387+ [@ %2 @ ~] [%yes %self %self] ::
388+ [@ %2 @ @ ~] [%yes %self %self] ::
404389 ==
405390::
406391```
@@ -440,8 +425,8 @@ Let's take a look at the permissioning structure for Publish.
440425 </li>
441426</ol>
442427
443−
444428`graph-permissions-remove`
429+
445430<ol>
446431 <li>Accept a noun <code>vip</code> of type <code>vip-metadata</code></li>
447432 <li>Declare a variable <code>reader</code>, a flag which is true if reader comments are enabled, false otherwise</li>
@@ -456,9 +441,13 @@ Let's take a look at the permissioning structure for Publish.
456441</ol>
457442
458443## General Patterns and Best Practices
444+
459445### General Patterns
446+
460447#### Schemas
448+
461449The general pattern for enforcing a schema in a validator is to:
450+
4624511. Cast the incoming data as an `indexed-post`
4634521. Switch on the index, matching by its depth and structure
4644531. Validate the structure of the contents of the post based on what we expect to see at that level of nesting. This logic can definitely be more involved than simply presence or absence of data.
@@ -467,11 +456,12 @@ When designing your schema, it may help to decide first what data the user will
467456
468457In general, validators can be as robust and expressive as desired, because the mark system already sets proper limitations of what you can and cannot do, with the main restriction being no side effects can be produced by a mark.
469458
470−
471459#### Permissions
460+
472461In general, you want to first have your schema finalized, then at every node ask the question: who should be able to modify (add/remove) this node, and its children if present in your schema. You may find that you don't need to set permission for every single type of node afterwards, although being thorough can help to find bugs in permissioning early on. Writing out the permissions in plain words and bullet points, sketching them out in the form of a table, then splitting it up into the code can also make the design process easier.
473462
474463### Earth/Mars Interface Details
464+
475465There are a few general ways to talk to a Graph Store gall agent. You can either interact with the agent in the form of pokes/scries/spiders either directly from the dojo, or through HTTP requests via Eyre.
476466
477467- All graph store applications are going to have a mark, which are applied to data going in or coming out
@@ -479,9 +469,8 @@ There are a few general ways to talk to a Graph Store gall agent. You can either
479469- In the case of data going in, you pass in a `marked-graph` which the Graph Store agent uses to validate the whole `graph` with. In the case of adding a node to a graph, the node will simply be checked for validity using the existing mark since the mark is already set on a per-graph basis
480470- In the case of data coming out, Eyre forcibly tries to convert the hoon noun into json, and silently fails if no json conversion exists. This process is handled by Graph Store under the hood because all graphs have a well-defined en-json/de-json format, so you never have to worry about making your own de/serialization arms.
481471
482−
483472Code References
473+
484474- [`interface/src/logic/api/base.ts#L62`](https://github.com/urbit/urbit/blob/master/pkg/interface/src/logic/api/base.ts#L62)
485475- [`mar/graph/update.hoon`](https://github.com/urbit/urbit/blob/e2ad6e3e9219c8bfad62f27f05c7cac94c9effa8/pkg/arvo/mar/graph/update.hoon)
486476- [`sys/vane/eyre.hoon#L1617-L1625`](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/sys/vane/eyre.hoon#L1617-L1625) shows how Eyre applies marks
487−