on master help sign in
Merge branch 'master' into auras-ref
commitfea0834c4a965ad5dca89e11ac30b06f02dc20d6 authorpoprox <51337059+drbeefsupreme@users.noreply.github.com> dateThu 18 Mar 2021, 11:58 (6 years ago) parentd052aa8e6f4b90
67 files changed+4054−4249
_index.md+17−13 arvo/_index.md+20−27 arvo/ames/ames-api.md+1−1 arvo/ames/ames.md+1−1 arvo/clay/_index.md+30 arvo/clay/architecture.md+254 arvo/clay/clay.md+23−2708 arvo/clay/data-types.md+760 arvo/clay/foreign.md+412 arvo/clay/local-reads.md+783 arvo/clay/local-sub.md+249 arvo/clay/using.md+209 arvo/concepts/_index.md+12 arvo/concepts/subscriptions.md+162 arvo/dill/dill-api.md+3−3 arvo/eyre/_index.md+9 development/integrating-api.md → arvo/eyre/using-eyre.md+14−8 arvo/ford/ford.md+214−2 arvo/gall/tutorial.md+14 arvo/io.md−471 arvo/jael/jael-api.md+1−1 arvo/arvo.md → arvo/overview.md+2−4 arvo/tutorials/_index.md+8 arvo/move-trace.md → arvo/tutorials/move-trace.md+6−6 azimuth/azimuth.md+1−1 development/_index.md+12−11 development/airlock.md−135 development/community-projects.md−20 development/develop.md+107−96 development/environment.md+62 development/grants.md+85 development/precepts.md+5−1 development/project-repositories.md+49 glossary/arvo.md+1−1 glossary/azimuth.md+1−1 glossary/comet.md+1−1 glossary/dojo.md−1 glossary/keyfile.md+1−1 glossary/moon.md+2−1 glossary/ship.md+1−1 glossary/vane.md+1−1 hoon/_index.md+4−2 hoon/hoon-school/_index.md+28−7 hoon/hoon-school/behn.md+1−1 hoon/hoon-school/setup.md+3−3 hoon/hoon-school/workbook/_index.md−17 hoon/hoon-school/workbook/bomb.md−140 hoon/hoon-school/workbook/digits.md−113 hoon/hoon-school/workbook/eightball.md−158 hoon/hoon-school/workbook/traffic-light.md−155 hoon/whyhoon.md → hoon/overview.md+7 hoon/reference/advanced.md+23−20 hoon/reference/auras.md+1−1 hoon/reference/rune/sig.md+4−1 landscape/_index.md+6−2 landscape/arch.md−19 landscape/overview.md+195 landscape/apiref/_index.md → landscape/reference/_index.md+1−1 landscape/apiref/graph.md → landscape/reference/graph-store.md+6−4 system-overview/_index.md+12−9 system-overview/arvo.md+13−13 system-overview/azimuth.md+5−8 system-overview/hoon.md+8−16 system-overview/nock.md+8−19 system-overview/vere.md+12−23 tutorials/azure-container-instances.md+120 tutorials/urbit-azure.jq+64
_index.md+17−13
@@ -1,28 +1,32 @@
11+++
2−title = "Docs"
2+title = "Development Docs"
33weight = 1
44template = "sections/docs.html"
55+++
66
7−Welcome to the documentation for the Urbit project. This documentation is maintained by [Tlon](https://tlon.io) in a public [Github repository](https://github.com/urbit/docs). Issues and contributions are welcome.
7+Welcome to the developer documentation for the Urbit project. This documentation
8+is maintained by [Tlon](https://tlon.io) and the Urbit community in a public
9+[Github repository](https://github.com/urbit/docs). Issues and contributions are
10+welcome.
811
9−If you already know what you're looking for, the easiest way to find it is with the search box located on the left.
12+This documentation provides a series of explainers, guides, tutorials and
13+reference material for assisting you in developing on the Urbit platform, or
14+contributing to the Urbit project. If you're looking for documentation on how to
15+*use* your Urbit ship, see our [usage docs](@/using/_index.md).
1016
17+### [Development](@/docs/development/_index.md)
18+
19+The Development section is recommended reading for developers interested in
20+contributing to Urbit itself, or building apps on top of Urbit. It serves as a
21+high-level orientation to how to set up a development environment, the various
22+codebases that comprise the project, our grants program, and the precepts that
23+drive the development of Urbit.
1124
1225### [System Overview](@/docs/system-overview/_index.md)
1326
1427This section gives a high-level overview to all the major components of the
1528Urbit tech stack - namely, the operating system Arvo, the programming languages
16−Nock and Hoon, the runtime Vere, the decentralized ID system Azimuth, and Tlon's
17−flagship client Landscape.
18−
19−### [Development](@/docs/development/_index.md)
20−
21−The Development section is recommended reading for developers interested in
22−contributing to Urbit itself, or building apps on top of Urbit. It serves as a
23−high-level orientation to how to set up a development environment, how to
24−interact with Urbit from outside protocols, community projects, and precepts
25−that drive the development of Urbit.
29+Nock and Hoon, the runtime Vere, and the decentralized ID system Azimuth.
2630
2731### [Arvo (Urbit OS)](@/docs/arvo/_index.md)
2832
arvo/_index.md+20−27
@@ -6,57 +6,50 @@ template = "sections/docs/chapters.html"
66aliases = ["/docs/learn/arvo/"]
77+++
88
9+Resources about the Urbit OS.
910
10−## [Arvo](@/docs/arvo/arvo.md)
11+## [Overview](@/docs/arvo/overview.md)
1112
12−Arvo is Urbit's functional operating system, written in [Hoon](@/docs/hoon/hoon-school/_index.md). It's composed of modules called _vanes_:
13+Arvo is Urbit's functional operating system, written in [Hoon](@/docs/hoon/hoon-school/_index.md). It's composed of modules called _vanes_, each of which has its own folder:
1314
14−
15−## Tutorials
16−
17−### [Move Trace](@/docs/arvo/move-trace.md)
18−
19−A walkthrough of what the Arvo kernel does to respond to a simple command.
20−
21−
22−## Concepts
23−
24−### [Input/Output](@/docs/arvo/io.md)
25−
26−Conceptual overview of how Arvo handles input and output.
27−
28−
29−## Vanes
30−
31−### [Ames](@/docs/arvo/ames/ames.md)
15+## [Ames](@/docs/arvo/ames/ames.md)
3216
3317Ames is the name of our network and the vane that communicates over it. It's an encrypted P2P network composed of instances of the Arvo operating system.
3418
35−### [Behn](@/docs/arvo/behn/behn.md)
19+## [Behn](@/docs/arvo/behn/behn.md)
3620
3721Behn is our timer. It allows vanes and applications to set and timer events, which are managed in a simple priority queue.
3822
39−### [Clay](@/docs/arvo/clay/clay.md)
23+## [Clay](@/docs/arvo/clay/clay.md)
4024
4125Clay is our filesystem and revision-control system.
4226
43−### [Dill](@/docs/arvo/dill/dill.md)
27+## [Dill](@/docs/arvo/dill/dill.md)
4428
4529Dill is our terminal driver. Unix sends keyboard events to dill from the terminal, and dill produces terminal output.
4630
47−### [Eyre](@/docs/arvo/eyre/eyre.md)
31+## [Eyre](@/docs/arvo/eyre/eyre.md)
4832
4933Eyre is our HTTP server. Unix sends HTTP messages to `%eyre`, and `%eyre` produces HTTP messages in response.
5034
51−### [Ford](@/docs/arvo/ford/ford.md)
35+## [Ford](@/docs/arvo/ford/ford.md)
5236
5337Ford is our build system. It handles resources and publishing.
5438
55−### [Gall](@/docs/arvo/gall/gall.md)
39+## [Gall](@/docs/arvo/gall/gall.md)
5640
5741Gall is the vane for controlling userspace apps.
5842
59−### Iris
43+## [Iris](@/docs/arvo/iris/iris-api.md)
6044
6145Iris is our HTTP client.
6246
47+## [Concepts](@/docs/arvo/concepts/_index.md)
48+
49+Explanations of design decisions that are pervasive throughout Arvo.
50+
51+## [Tutorials](@/docs/arvo/tutorials/_index.md)
52+
53+Walkthroughs that teach you more about how Arvo works.
54+
55+
arvo/ames/ames-api.md+1−1
@@ -189,7 +189,7 @@ Ames does not `give` a `gift` in response to a `%crud` `task`, but it does
189189## `%init`
190190
191191`%init` is called a single time during the very first boot process, immediately
192−after the [larval stage](@/docs/arvo/arvo.md#larval-stage-core)
192+after the [larval stage](@/docs/arvo/overview.md#larval-stage-core)
193193is completed. This initializes the vane. Jael is initialized first, followed by
194194other vanes such as Ames.
195195
arvo/ames/ames.md+1−1
@@ -28,7 +28,7 @@ vane or app, is defined in Ames.
2828This section summarizes the design of Ames. Beyond this section are deeper
2929elaborations on the concepts presented here.
3030
31−Ames extends [Arvo's](@/docs/arvo/arvo.md) `%pass`/`%give` `move` semantics across the network.
31+Ames extends [Arvo's](@/docs/arvo/overview.md) `%pass`/`%give` `move` semantics across the network.
3232
3333Ames receives packets as Arvo events and emits packets as Arvo
3434effects. The runtime is responsible for transferring the bytes in
arvo/clay/_index.md+30
@@ -4,3 +4,33 @@ weight = 30
44sort_by = "weight"
55template = "sections/docs/chapters.html"
66+++
7+
8+[Overview](@/docs/arvo/clay/clay.md)
9+
10+High-level overview of Clay.
11+
12+[Architecture](@/docs/arvo/clay/architecture.md)
13+
14+A conceptual overview of how Clay was designed.
15+
16+[Using Clay](@/docs/arvo/clay/using.md)
17+
18+A quick overview of how the most common tasks involving Clay are performed:
19+reading and subscribing, syncing to Unix, and merging.
20+
21+[Data Types](@/docs/arvo/clay/data-types.md)
22+
23+Explanations of the many data types found throughout Clay.
24+
25+[Local Reads and Writes](@/docs/arvo/clay/local-reads.md)
26+
27+How local reads and writes work.
28+
29+[Local Subscriptions](@/docs/arvo/clay/local-sub.md)
30+
31+How local subscriptions work.
32+
33+[Foreign Requests](@/docs/arvo/clay/foreign.md)
34+
35+How foreign reads and subscriptions work.
36+
arvo/clay/architecture.mdnew file+254
@@ -0,0 +1,254 @@
1+++
2+title = "Architecture"
3+weight = 2
4+template = "doc.html"
5+++
6+
7+Clay is the primary filesystem for the [Arvo](@/docs/Arvo/overview.md) operating system,
8+which is the [core](/docs/glossary/core/) of an urbit. The architecture of Clay is
9+intrinsically connected with Arvo, but for this section we assume no knowledge of
10+either Arvo or Urbit. We will point out only those features of
11+Arvo that are necessary for an understanding of Clay, and we will
12+do so only when they arise.
13+
14+The first relevant feature of Arvo is that it is a deterministic
15+system where input and output are defined as a series of events
16+and effects. The state of Arvo is simply a pure function of its event
17+log. None of the effects from an event are emitted until the
18+event is entered in the log and persisted, either to disk or
19+another trusted source of persistence, such as a Kafka cluster.
20+Consequently, Arvo is a single-level store: everything in its
21+state is persistent.
22+
23+In a more traditional OS, everything in RAM can be erased at any
24+time by power failure, and is always erased on reboot. Thus, a
25+primary purpose of a filesystem is to ensure files persist across
26+power failures and reboots. In Arvo, both power failures and
27+reboots are special cases of suspending computation, which is
28+done safely since our event log is already persistent. Therefore,
29+Clay is not needed in Arvo for persistence. Why, then, do we have a
30+filesystem? There are two answers to this question.
31+
32+First, Clay provides a filesystem tree, which is a convenient
33+user interface for some applications. Unix has the useful concept
34+of virtual filesystems, which are used for everything from direct
35+access to devices, to random number generators, to the /proc
36+tree. It is easy and intuitive to read from and write to a
37+filesystem tree.
38+
39+Second, Clay has a distributed revision-control system baked into
40+it. Traditional filesystems are not revision controlled, so
41+userspace software -- such as git -- is written on top of them to
42+do so. Clay natively provides the same functionality as modern
43+DVCSes, and more.
44+
45+Clay has two other unique properties that we'll cover later on:
46+it supports typed data and is referentially transparent.
47+
48+### Revision Control
49+
50+Every urbit has one or more `desk`s, which are independently
51+revision-controlled branches. Each `desk` contains its own `mark`
52+definitions, apps, and so forth.
53+
54+Traditionally, an urbit has at least a `%home` `desk` and `%kids` `desk`. The
55+`%home` `desk` has all the system software from the distribution, along with your
56+personal files. The `%home` `desk` is a fork of the `%kids` desk of whichever ship
57+you download [OTAs](@/docs/glossary/ota-updates.md) from - typically your sponsor,
58+but theoretically may be any ship. You will also find references to a `%base`
59+`desk` - which is not a real `desk`, rather it just a hash associated to the
60+`desk` from which your `%home` `desk` was forked.
61+
62+A `desk` is a series of numbered commits, the most recent of which
63+represents the current state of the `desk`. A commit is composed of
64+(1) an absolute time when it was created, (2) a list of zero or
65+more parents, and (3) a map from paths to data.
66+
67+Most commits have exactly one parent, but the initial commit on a
68+`desk` may have zero parents, and merge commits have more than one
69+parent.
70+
71+The non-metadata is stored as a `map` of `path`s to data. It's
72+worth noting that no constraints are put on this `map`, so, for
73+example, both `/a/b` and `/a/b/c` could have data. This is impossible
74+in a traditional Unix filesystem since it means that `/a/b` is both
75+a file and a directory. Conventionally, the final element in the
76+path is its `mark` -- much like a filename extension in Unix. Thus,
77+`/doc/readme.md` in Unix is stored as `/doc/readme/md` in urbit.
78+
79+The data is not stored directly in the `map`; rather, a hash of the
80+data is stored, and we maintain a master blob store. Thus, if the
81+same data is referred to in multiple commits (as, for example,
82+when a file doesn't change between commits), only the hash is
83+duplicated.
84+
85+In the master blob store, we either store the data directly, or
86+else we store a diff against another blob. The hash is dependent
87+only on the data within and not on whether or not it's stored
88+directly, so we may on occasion rearrange the contents of the
89+blob store for performance reasons.
90+
91+Recall that a `desk` is a series of numbered commits. Not every
92+commit in a `desk` must be numbered. For example, if the base `desk`
93+has had 50 commits since home was forked from it, then a merge
94+from base to home will only add a single revision number to home,
95+although the full commit history will be accessible by traversing
96+the parentage of the individual commits.
97+
98+We do guarantee that the first commit is numbered 1, commits are
99+numbered consecutively after that (i.e. there are no "holes"),
100+the topmost commit is always numbered, and every numbered commit
101+is an ancestor of every later numbered commit.
102+
103+There are three ways to refer to particular commits in the
104+revision history. Firstly, one can use the revision number.
105+Secondly, one can use any absolute time between the one numbered
106+commit and the next (inclusive of the first, exclusive of the
107+second). Thirdly, every `desk` has a `map` of labels to revision
108+numbers. These labels may be used to refer to specific commits.
109+
110+Additionally, Clay is a global filesystem, so data on other urbits
111+is easily accessible the same way as data on our local urbit. In
112+general, the path to a particular revision of a `desk` is
113+`/~urbit-name/desk-name/revision`. Thus, to get `/try/readme/md`
114+from revision 5 of the home `desk` on `~sampel-sipnym`, we refer to
115+`/~sampel-sipnym/home/5/try/readme/md`. Clay's namespace is thus
116+global and referentially transparent.
117+
118+### A Typed Filesystem
119+
120+Since Clay is a general filesystem for storing data of arbitrary
121+types, in order to revision control correctly it needs to be
122+aware of types all the way through. Traditional revision control
123+does an excellent job of handling source code, so for source code
124+we act very similar to traditional revision control. The
125+challenge is to handle other data similarly well.
126+
127+For example, modern VCSs generally support "binary files", which
128+are files for which the standard textual diffing, patching, and
129+merging algorithms are not helpful. A "diff" of two binary files
130+is just a pair of the files, "patching" this diff is just
131+replacing the old file with the new one, and "merging"
132+non-identical diffs is always a conflict, which can't even be
133+helpfully annotated. Without knowing anything about the structure
134+of a blob of data, this is the best we can do.
135+
136+Often, though, "binary" files have some internal structure, and
137+it is possible to create diff, patch, and merge algorithms that
138+take advantage of this structure. An image may be the result of a
139+base image with some set of operations applied. With algorithms
140+aware of this set of operations, not only can revision control
141+software save space by not having to save every revision of the
142+image individually, these transformations can be made on parallel
143+branches and merged at will.
144+
145+Suppose Alice is tasked with touching up a picture, improving the
146+color balance, adjusting the contrast, and so forth, while Bob
147+has the job of cropping the picture to fit where it's needed and
148+adding textual overlay. Without type-aware revision control,
149+these changes must be made serially, requiring Alice and Bob to
150+explicitly coordinate their efforts. With type-aware revision
151+control, these operations may be performed in parallel, and then
152+the two changesets can be merged programmatically.
153+
154+Of course, even some kinds of text files may be better served by
155+diff, patch, and merge algorithms aware of the structure of the
156+files. Consider a file containing a pretty-printed JSON object.
157+Small changes in the JSON object may result in rather significant
158+changes in how the object is pretty-printed (for example, by
159+addding an indentation level, splitting a single line into
160+multiple lines).
161+
162+A text file wrapped at 80 columns also reacts suboptimally with
163+unadorned Hunt-McIlroy diffs. A single word inserted in a
164+paragraph may push the final word or two of the line onto the
165+next line, and the entire rest of the paragraph may be flagged as
166+a change. Two diffs consisting of a single added word to
167+different sentences may be flagged as a conflict. In general,
168+prose should be diffed by sentence, not by line.
169+
170+As far as we are aware, Clay is the first generalized,
171+type-aware revision control system. We'll go into the workings
172+of this system in some detail.
173+
174+### Marks
175+
176+Central to a typed filesystem is the idea of types. In Clay, we
177+call these `mark`s. A `mark` is a file that defines a type,
178+conversion routines to and from the `mark`, and diff, patch, and
179+merge routines.
180+
181+For example, a `%txt` mark may be a list of lines of text, and it
182+may include conversions to `%mime` to allow it to be serialized
183+and sent to a browser or to the Unix filesystem. It will also
184+include Hunt-McIlroy diff, patch, and merge algorithms.
185+
186+A `%json` `mark` would be defined as a JSON object in the code, and
187+it would have a parser to convert from `%txt` and a printer to
188+convert back to `%txt`. The diff, patch, and merge algorithms are
189+fairly straightforward for JSON, though they're very different
190+from the text ones.
191+
192+More formally, a `mark` is a core with three [arms](/docs/glossary/arm/): `+grab`,
193+`+grow`, and `+grad`. In `+grab` is a series of functions to
194+convert from other `mark`s to the given `mark`. In `+grow` is a
195+series of functions to convert from the given `mark` to other
196+`mark`s. In `+grad` is `+diff`, `+pact`, `+join`, and `+mash`, and
197+`+form`.
198+
199+The types are as follows, in an informal pseudocode:
200+
201+```
202+ ++ grab:
203+ ++ mime: <mime> -> <mark-type>
204+ ++ txt: <txt> -> <mark-type>
205+ ...
206+ ++ grow:
207+ ++ mime: <mark-type> -> <mime>
208+ ++ txt: <mark-type> -> <txt>
209+ ...
210+ ++ grad
211+ ++ form: <mark-type>
212+ ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
213+ ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
214+ ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
215+ ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
216+```
217+
218+These types are basically what you would expect. Not every `mark`
219+has each of these functions defined -- all of them are optional
220+in the general case.
221+
222+In general, for a particular `mark`, the `+grab` and `+grow` entries
223+(if they exist) should be inverses of each other.
224+
225+In `+grad`, `+diff` takes two instances of a `mark` and produces a diff of them
226+whose `mark` is given by `+form`. `+pact` takes an instance of a `mark` and
227+patches it with the given diff. `+join` takes two diffs and attempts to merge
228+them into a single diff. If there are conflicts, it produces null. `+mash` takes
229+two diffs and forces a merge, annotating any conflicts.
230+
231+In general, if `+diff` called with A and B produces diff D, then
232+`+pact` called with A and D should produce B. Also, if `+join`
233+of two diffs does not produce null, then `+mash` of the same
234+diffs should produce the same result.
235+
236+Alternately, instead of `+diff`, `+pact`, `+join`, and
237+`+mash`, a `mark` can provide the same functionality by defining
238+`+grad` to be the name of another `mark` to which we wish to
239+delegate the revision control responsibilities. Then, before
240+running any of those functions, Clay will convert to the other
241+`mark`, and convert back afterward. For example, the `%hoon` `mark`
242+is revision-controlled in the same way as `%txt`, so its `+grad`
243+is simply `++ grad %txt`. Of course, `+txt` must be defined in
244+`+grow` and `+grab` as well.
245+
246+Every file in Clay has a `mark`, and that `mark` must have a
247+fully-functioning `+grad`. `Mark`s are used for more than just
248+Clay, and other `mark`s don't need a `+grad`, but if a piece of
249+data is to be saved to Clay, we must know how to revision-control
250+it.
251+
252+Additionally, if a file is to be synced out to Unix, then it must
253+have conversion routines to and from the `%mime` `mark`.
254+
arvo/clay/clay.md+23−2708
@@ -23,2727 +23,42 @@ zuse. Second is the write, query, and subscription logic. Finally, there
2323is the logic for communicating requests to, and receiving requests from,
2424foreign ships.
2525
26−## Merge strategies
26+Clay documentation is extensive, but the reader much tread carefully as portions
27+of it are out of date as of March 2021. We are actively working on updating
28+them. If you'd like to help, please reach out to us in the Docs channel on Urbit
29+Community or submit a PR at
30+[https://github.com/urbit/docs](https://github.com/urbit/docs).
2731
28−*This section is up to date as of November 2020*
32+### User documentation
2933
30−Usage:
31−```
32−|merge %destination-desk ~source-ship %source-desk
33−|merge %destination-desk ~source-ship %source-desk, =gem %strategy
34−|merge %destination-desk ~source-ship %source-desk, =cas ud+5
35−```
34+[Filesystem](@/using/os/filesystem.md)
3635
37−Clay supports various merge strategies. A "commit" is a snapshot of
38−the files with a list of parents plus a date. Most commits have
39−one parent; a "merge" commit is a commit with two parents. The
40−%home desk starts with an initial commit with no parents; commits
41−with several parents ("octopus merges") are possible but we don't
42−generate them right now.
43−
44−Unless otherwise specified, all of the following create a new commit
45−with the source and destination commits as parents.
46−
47−Several strategies need a "merge-base". They find it by identifying
48−the most recent common ancestor of the two desks. If none, fail
49−with `%merge-no-merge-base`; if there are two or more, pick one.
50−
51−`%init`: the only way to create a desk. Not a true merge, since it
52−simply assigns the source commit to the destination.
53−
54−`%fine`: if source or destination are in the ancestry of each other,
55−use the newer one; else abort. If the destination is ahead of the
56−source, succeed but do nothing. If the source is ahead of the
57−destination, assign the next revision number to the source commit.
58−Some call this "fast-forward".
59−
60−`%meet`: combine changes, failing if both sides changed the same file.
61−Specifically, take diff(merge-base,source) and
62−diff(merge-base,destination) and combine them as long as those diffs
63−touch different files.
64−
65−`%mate`: combine changes, failing if both sides changed the same part
66−of a file. Identical to `%meet`, except that some marks, like `%hoon`,
67−allow intelligent merge of changes to different parts of a file.
68−
69−`%meld`: combine changes; if both sides changed the same part of a
70−file, use the version of the file in the merge-base.
71−
72−`%only-this`: create a merge commit with exactly the contents of the
73−destination desk.
74−
75−`%only-that`: create a merge commit with exactly the contents of the
76−source commit.
77−
78−`%take-this`: create a merge commit with exactly the contents of the
79−destination desk except take any files from the source commit which
80−are not in the destination desk.
81−
82−`%take-that`: create a merge commit with exactly the contents of the
83−source commit except preserve any files from the destination desk
84−which are not in the source commit.
85−
86−`%meet-this`: merge as in `%meet`, except if both sides changed the same
87−file, use the version in the destination desk.
88−
89−`%meet-that`: merge as in `%meet`, except if both sides changed the same
90−file, use the version in the source commit.
91−
92−### Examples and notes:
93−
94−The most common merge strategy is %mate, which is a normal 3-way
95−merge which aborts on conflict.
96−
97−`%take-that` is useful to "force" an OTA. After running `%take-that`,
98−you're guaranteed to have exactly the files in the source commit plus
99−any files you separately added.
100−
101−We speak of merging into a destination *desk* from a source *commit*
102−because while you can only merge on top of a desk, you can merge from
103−historical commits. For example,
104−```
105−|merge %old our %home, =cas ud+5, =gem %init
106−```
107−will create a new desk called `%old` with the 5th commit in `%home`.
108−You can revert the contents of a desk to what they were yesterday
109−with
110−```
111−|merge %home our %home, =cas da+(sub now ~d1), =gem %only-that
112−```
113−
114−Note this is a normal `%only-that merge`, which means you're creating a
115−*new* commit with the old *contents*.
116−
117−`%meld` is rarely used on its own, however if you specify `%auto` or
118−omit the merge strategy, `%kiln` will run a `%meld` merge into a scratch
119−desk and then annotate the conflicts there.
120−
121−If you resolve merge conflicts manually, for example by mounting the
122−desks, copying the files in Unix and then running `|commit`, you
123−should usually run an `%only-this merge`. This will not change the
124−newly-fixed contents of your desk, but it will record that the merge
125−happened so that those conflicts don't reappear in later merges.
126−
127−If you get a `%merge-no-merge-base` error, this means you're trying to
128−merge two desks which have no common ancestors. You need to give
129−them a common ancestor by choosing a merge strategy which doesn't
130−need a merge-base, like `%only-this`, `%only-that`, `%take-this`, or
131−`%take-that`.
132−
133−`%take-this` could be useful to install 3rd party software, but you
134−couldn't get subsequent updates this way, since the files would
135−already exist in the destination desk. Something like "take only
136−the files which aren't in my OTA source or any other 3rd party app"
137−would be basically correct. This would require a parameter listing
138−the desks to not conflict with.
139−
140−`%meet-this` and `%meet-that` imply the existence of `%mate-this` and
141−`%mate-that`, but those don't exist yet.
36+How to interact with the Clay filesystem via Dojo. This includes basics such as
37+mounting to Unix, changing directory, merging, and listing files.
14238
39+### Developer Documentation
14340
144−*The remainder of this document is out of date as of November 2020, but certain parts are still
145−accurate. Please independently confirm information here before acting on it.*
41+[Architecture](@/docs/arvo/clay/architecture.md)
14642
147−## Architecture
43+A conceptual overview of how Clay was designed. (Up to date as of March 2021)
14844
149−Clay is the primary filesystem for the arvo operating system,
150−which is the [core](/docs/glossary/core/) of an urbit. The architecture of clay is
151−intrinsically connected with arvo, but we assume no knowledge of
152−either arvo or urbit. We will point out only those features of
153−arvo that are necessary for an understanding of clay, and we will
154−do so only when they arise.
45+[Using Clay](@/docs/arvo/clay/using.md)
15546
156−The first relevant feature of arvo is that it is a deterministic
157−system where input and output are defined as a series of events
158−and effects. The state of arvo is simply a function of its event
159−log. None of the effects from an event are emitted until the
160−event is entered in the log and persisted, either to disk or
161−another trusted source of persistence, such as a Kafka cluster.
162−Consequently, arvo is a single-level store: everything in its
163−state is persistent.
47+A quick overview of how the most common tasks involving Clay are performed:
48+reading and subscribing, syncing to Unix, and merging.
16449
165−In a more traditional OS, everything in RAM can be erased at any
166−time by power failure, and is always erased on reboot. Thus, a
167−primary purpose of a filesystem is to ensure files persist across
168−power failures and reboots. In arvo, both power failures and
169−reboots are special cases of suspending computation, which is
170−done safely since our event log is already persistent. Therefore,
171−clay is not needed in arvo for persistence. Why, then, do we have a
172−filesystem? There are two answers to this question.
50+[Data Types](@/docs/arvo/clay/data-types.md)
17351
174−First, clay provides a filesystem tree, which is a convenient
175−user interface for some applications. Unix has the useful concept
176−of virtual filesystems, which are used for everything from direct
177−access to devices, to random number generators, to the /proc
178−tree. It is easy and intuitive to read from and write to a
179−filesystem tree.
52+Explanations of the many data types found throughout Clay.
18053
181−Second, clay has a distributed revision-control system baked into
182−it. Traditional filesystems are not revision controlled, so
183−userspace software -- such as git -- is written on top of them to
184−do so. clay natively provides the same functionality as modern
185−DVCSes, and more.
54+[Local Reads and Writes](@/docs/arvo/clay/local-reads.md)
18655
187−clay has two other unique properties that we'll cover later on:
188−it supports typed data and is referentially transparent.
56+How local reads and writes work.
18957
190−### Revision Control
58+[Local Subscriptions](@/docs/arvo/clay/local-sub.md)
19159
192−Every urbit has one or more "desks", which are independently
193−revision-controlled branches. Each desk contains its own mark
194−definitions, apps, doc, and so forth.
60+How local subscriptions work.
19561
196−Traditionally, an urbit has at least a base and a home desk. The
197−base desk has all the system software from the distribution. the
198−home desk is a fork of base with all the stuff specific to the
199−user of the urbit.
62+[Foreign Requests](@/docs/arvo/clay/foreign.md)
20063
201−A desk is a series of numbered commits, the most recent of which
202−represents the current state of the desk. A commit is composed of
203−(1) an absolute time when it was created, (2) a list of zero or
204−more parents, and (3) a map from paths to data.
205−
206−Most commits have exactly one parent, but the initial commit on a
207−desk may have zero parents, and merge commits have more than one
208−parent.
209−
210−The non-meta data is stored in the map of paths to data. It's
211−worth noting that no constraints are put on this map, so, for
212−example, both /a/b and /a/b/c could have data. This is impossible
213−in a traditional Unix filesystem since it means that /a/b is both
214−a file and a directory. Conventionally, the final element in the
215−path is its mark -- much like a filename extension in Unix. Thus,
216−/doc/readme.md in Unix is stored as /doc/readme/md in urbit.
217−
218−The data is not stored directly in the map; rather, a hash of the
219−data is stored, and we maintain a master blob store. Thus, if the
220−same data is referred to in multiple commits (as, for example,
221−when a file doesn't change between commits), only the hash is
222−duplicated.
223−
224−In the master blob store, we either store the data directly, or
225−else we store a diff against another blob. The hash is dependent
226−only on the data within and not on whether or not it's stored
227−directly, so we may on occasion rearrange the contents of the
228−blob store for performance reasons.
229−
230−Recall that a desk is a series of numbered commits. Not every
231−commit in a desk must be numbered. For example, if the base desk
232−has had 50 commits since home was forked from it, then a merge
233−from base to home will only add a single revision number to home,
234−although the full commit history will be accessible by traversing
235−the parentage of the individual commits.
236−
237−We do guarantee that the first commit is numbered 1, commits are
238−numbered consecutively after that (i.e. there are no "holes"),
239−the topmost commit is always numbered, and every numbered commit
240−is an ancestor of every later numbered commit.
241−
242−There are three ways to refer to particular commits in the
243−revision history. Firstly, one can use the revision number.
244−Secondly, one can use any absolute time between the one numbered
245−commit and the next (inclusive of the first, exclusive of the
246−second). Thirdly, every desk has a map of labels to revision
247−numbers. These labels may be used to refer to specific commits.
248−
249−Additionally, clay is a global filesystem, so data on other urbit
250−is easily accessible the same way as data on our local urbit. In
251−general, the path to a particular revision of a desk is
252−/~urbit-name/desk-name/revision. Thus, to get /try/readme/md
253−from revision 5 of the home desk on ~sampel-sipnym, we refer to
254−/~sampel-sipnym/home/5/try/readme/md. Clay's namespace is thus
255−global and referentially transparent.
256−
257−XXX reactivity here?
258−
259−### A Typed Filesystem
260−
261−Since clay is a general filesystem for storing data of arbitrary
262−types, in order to revision control correctly it needs to be
263−aware of types all the way through. Traditional revision control
264−does an excellent job of handling source code, so for source code
265−we act very similar to traditional revision control. The
266−challenge is to handle other data similarly well.
267−
268−For example, modern VCSs generally support "binary files", which
269−are files for which the standard textual diffing, patching, and
270−merging algorithms are not helpful. A "diff" of two binary files
271−is just a pair of the files, "patching" this diff is just
272−replacing the old file with the new one, and "merging"
273−non-identical diffs is always a conflict, which can't even be
274−helpfully annotated. Without knowing anything about the structure
275−of a blob of data, this is the best we can do.
276−
277−Often, though, "binary" files have some internal structure, and
278−it is possible to create diff, patch, and merge algorithms that
279−take advantage of this structure. An image may be the result of a
280−base image with some set of operations applied. With algorithms
281−aware of this set of operations, not only can revision control
282−software save space by not having to save every revision of the
283−image individually, these transformations can be made on parallel
284−branches and merged at will.
285−
286−Suppose Alice is tasked with touching up a picture, improving the
287−color balance, adjusting the contrast, and so forth, while Bob
288−has the job of cropping the picture to fit where it's needed and
289−adding textual overlay. Without type-aware revision control,
290−these changes must be made serially, requiring Alice and Bob to
291−explicitly coordinate their efforts. With type-aware revision
292−control, these operations may be performed in parallel, and then
293−the two changesets can be merged programmatically.
294−
295−Of course, even some kinds of text files may be better served by
296−diff, patch, and merge algorithms aware of the structure of the
297−files. Consider a file containing a pretty-printed JSON object.
298−Small changes in the JSON object may result in rather significant
299−changes in how the object is pretty-printed (for example, by
300−addding an indentation level, splitting a single line into
301−multiple lines).
302−
303−A text file wrapped at 80 columns also reacts suboptimally with
304−unadorned Hunt-McIlroy diffs. A single word inserted in a
305−paragraph may push the final word or two of the line onto the
306−next line, and the entire rest of the paragraph may be flagged as
307−a change. Two diffs consisting of a single added word to
308−different sentences may be flagged as a conflict. In general,
309−prose should be diffed by sentence, not by line.
310−
311−As far as the author is aware, clay is the first generalized,
312−type-aware revision control system. We'll go into the workings
313−of this system in some detail.
314−
315−### Marks
316−
317−Central to a typed filesystem is the idea of types. In clay, we
318−call these "marks". A mark is a file that defines a type,
319−conversion routines to and from the mark, and diff, patch, and
320−merge routines.
321−
322−For example, a `%txt` mark may be a list of lines of text, and it
323−may include conversions to `%mime` to allow it to be serialized
324−and sent to a browswer or to the unix filesystem. It will also
325−include Hunt-McIlroy diff, patch, and merge algorithms.
326−
327−A `%json` mark would be defined as a json object in the code, and
328−it would have a parser to convert from `%txt` and a printer to
329−convert back to `%txt`. The diff, patch, and merge algorithms are
330−fairly straightforward for json, though they're very different
331−from the text ones.
332−
333−More formally, a mark is a core with three [arms](/docs/glossary/arm/), `++grab`,
334−`++grow`, and `++grad`. In `++grab` is a series of functions to
335−convert from other marks to the given mark. In `++grow` is a
336−series of functions to convert from the given mark to other
337−marks. In `++grad` is `++diff`, `++pact`, `++join`, and `++mash`.
338−
339−The types are as follows, in an informal pseudocode:
340−
341−```
342− ++ grab:
343− ++ mime: <mime> -> <mark-type>
344− ++ txt: <txt> -> <mark-type>
345− ...
346− ++ grow:
347− ++ mime: <mark-type> -> <mime>
348− ++ txt: <mark-type> -> <txt>
349− ...
350− ++ grad
351− ++ diff: (<mark-type>, <mark-type>) -> <diff-type>
352− ++ pact: (<mark-type>, <diff-type>) -> <mark-type>
353− ++ join: (<diff-type>, <diff-type>) -> <diff-type> or NULL
354− ++ mash: (<diff-type>, <diff-type>) -> <diff-type>
355−```
356−
357−These types are basically what you would expect. Not every mark
358−has each of these functions defined -- all of them are optional
359−in the general case.
360−
361−In general, for a particular mark, the `++grab` and `++grow` entries
362−(if they exist) should be inverses of each other.
363−
364−In `++grad`, `++diff` takes two instances of a mark and produces
365−a diff of them. `++pact` takes an instance of a mark and patches
366−it with the given diff. `++join` takes two diffs and attempts to
367−merge them into a single diff. If there are conflicts, it
368−produces null. `++mash` takes two diffs and forces a merge,
369−annotating any conflicts.
370−
371−In general, if `++diff` called with A and B produces diff D, then
372−`++pact` called with A and D should produce B. Also, if `++join`
373−of two diffs does not produce null, then `++mash` of the same
374−diffs should produce the same result.
375−
376−Alternately, instead of `++diff`, `++pact`, `++join`, and
377−`++mash`, a mark can provide the same functionality by defining
378−`++sted` to be the name of another mark to which we wish to
379−delegate the revision control responsibilities. Then, before
380−running any of those functions, clay will convert to the other
381−mark, and convert back afterward. For example, the `%hoon` mark
382−is revision-controlled in the same way as `%txt`, so its `++grad`
383−is simply `++sted %txt`. Of course, `++txt` must be defined in
384−`++grow` and `++grab` as well.
385−
386−Every file in clay has a mark, and that mark must have a
387−fully-functioning `++grad`. Marks are used for more than just
388−clay, and other marks don't need a `++grad`, but if a piece of
389−data is to be saved to clay, we must know how to revision-control
390−it.
391−
392−Additionally, if a file is to be synced out to unix, then it must
393−have conversion routines to and from the `%mime` mark.
394−
395−## Using clay
396−
397−### Reading and Subscribing
398−
399−When reading from Clay, there are three types of requests. A
400−`%sing` request asks for data at single revsion. A `%next`
401−request asks to be notified the next time there's a change to
402−given file. A `%many` request asks to be notified on every
403−change in a desk for a range of changes.
404−
405−For `%sing` and `%next`, there are generally three things to be
406−queried. A `%u` request simply checks for the existence of a
407−file at a path. A `%x` request gets the data in the file at a
408−path. A `%y` request gets a hash of the data in the file at the
409−path combined with all its children and their data. Thus, `%y`
410−of a node changes if it or any of its children change.
411−
412−A `%sing` request is fulfilled immediately if possible. If the
413−requested revision is in the future, or is on another ship for
414−which we don't have the result cached, we don't respond
415−immediately. If the requested revision is in the future, we wait
416−until the revision happens before we respond to the request. If
417−the request is for data on another ship, we pass on the request
418−to the other ship. In general, Clay subscriptions, like most
419−things in Urbit, aren't guaranteed to return immediately.
420−They'll return when they can, and they'll do so in a
421−referentially transparent manner.
422−
423−A `%next` request checks query at the given revision, and it
424−produces the result of the query the next time it changes, along
425−with the revsion number when it changes. Thus, a `%next` of a
426−`%u` is triggered when a file is added or deleted, a `%next` of a
427−`%x` is triggered when a file is added, deleted, or changed, and
428−a `%next` of a `%y` is triggered when a file or any of its
429−children is added, deleted, or changed.
430−
431−A `%many` request is triggered every time the given desk has a
432−new revision. Unlike a `%next`, a `%many` has both a start and
433−an end revsion, after which it stops returning. For `%next`, a
434−single change is reported, and if the caller wishes to hear of
435−the next change, it must resubscribe. For `%many`, every revsion
436−from the start to the end triggers a response. Since a `%many`
437−request doesn't ask for any particular data, there aren't `%u`,
438−`%x`, and `%y` versions for it.
439−
440−### Unix sync
441−
442−One of the primary functions of clay is as a convenient user
443−interface. While tools exist to use clay from within urbit, it's
444−often useful to be able to treat clay like any other filesystem
445−from the Unix perspective -- to "mount" it, as it were.
446−
447−From urbit, you can run `|mount /path/to/directory %mount-point`,
448−and this will mount the given clay directory to the mount-point
449−directory in Unix. Every file is converted to `%mime` before it's
450−written to Unix, and converted back when read from Unix. The
451−entire directory is watched (a la Dropbox), and every change is
452−committed once you run `|commit %mount-point`.
453−
454−### Merging
455−
456−Merging is a fundamental operation for a distributed revision
457−control system. At their root, clay's merges are similar to
458−git's, but with some additions to accomodate typed data. There
459−are seven different merge strategies.
460−
461−Throughout our discussion, we'll say that the merge is from
462−Alice's desk to Bob's. Recall that a commit is a date (for all
463−new commits this will be the current date), a list of parents,
464−and the data itself.
465−
466−A `%init` merge should be used iff it's the first commit to a
467−desk. The head of Alice's desk is used as the number 1 commit to
468−Bob's desk. Obviously, the ancestry remains intact through
469−traversing the parentage of the commit even though previous
470−commits are not numbered for Bob's desk.
471−
472−A `%this` merge means to keep what's in Bob's desk, but join the
473−ancestry. Thus, the new commit has the head of each desk as
474−parents, but the data is exactly what's in Bob's desk. For those
475−following along in git, this is the 'ours' merge strategy, not
476−the '--ours' option to the 'recursive' merge strategy. In other
477−words, even if Alice makes a change that does not conflict with
478−Bob, we throw it away. It's Bob's way or the highway.
479−
480−A `%that` merge means to take what's in Alice's desk, but join
481−the ancestry. This is the reverse of `%this`.
482−
483−A `%fine` merge is a "fast-forward" merge. This succeeds iff one
484−head is in the ancestry of the other. In this case, we use the
485−descendant as our new head.
486−
487−For `%meet`, `%mate`, and `%meld` merges, we first find the most
488−recent common ancestor to use as our merge base. If we have no
489−common ancestors, then we fail. If we have more than one most
490−recent common ancestor, then we have a criss-cross situation,
491−which should be handled delicately. At present, we delicately
492−throw up our hands and give up, but something akin to git's
493−'recursive' strategy should be implemented in the future.
494−
495−There's a functional inclusion ordering on `%fine`, `%meet`,
496−`%mate`, and `%meld` such that if an earlier strategy would have
497−succeeded, then every later strategy will produce the same
498−result. Put another way, every earlier strategy is the same as
499−every later strategy except with a restricted domain.
500−
501−A `%meet` merge only succeeds if the changes from the merge base
502−to Alice's head (hereafter, "Alice's changes") are in different
503−files than Bob's changes. In this case, the parents are both
504−Alice's and Bob's heads, and the data is the merge base plus
505−Alice's changed files plus Bob's changed files.
506−
507−A `%mate` merge attempts to merge changes to the same file when
508−both Alice and bob change it. If the merge is clean, we use it;
509−otherwise, we fail. A merge between different types of changes --
510−for example, deleting a file vs changing it -- is always a
511−conflict. If we succeed, the parents are both Alice's and Bob's
512−heads, and the data is the merge base plus Alice's changed files
513−plus Bob's changed files plus the merged files.
514−
515−A `%meld` merge will succeed even if there are conflicts. If
516−there are conflicts in a file, then we use the merge base's
517−version of that file, and we produce a set of files with
518−conflicts. The parents are both Alice's and Bob's heads, and the
519−data is the merge base plus Alice's changed files plus Bob's
520−changed files plus the successfully merged files plus the merge
521−base's version of the conflicting files.
522−
523−That's the extent of the merge options in clay proper. In
524−userspace there's a final option `%auto`, which is the most
525−common. `%auto` checks to see if Bob's desk exists, and if it
526−doesn't we use a `%init` merge. Otherwise, we progressively try
527−`%fine`, `%meet`, and `%mate` until one succeeds.
528−
529−If none succeed, we merge Bob's desk into a scratch desk. Then,
530−we merge Alice's desk into the scratch desk with the `%meld`
531−option to force the merge. For each file in the produced set of
532−conflicting files, we call the `++mash` function for the
533−appropriate mark, which annotates the conflicts if we know how.
534−
535−Finally, we display a message to the user informing them of the
536−scratch desk's existence, which files have annotated conflicts,
537−and which files have unannotated conflicts. When the user has
538−resolved the conflicts, they can merge the scratch desk back into
539−Bob's desk. This will be a `%fine` merge since Bob's head is in
540−the ancestry of the scratch desk.
541−
542−### Autosync
543−
544−Tracking and staying in sync with another desk is another
545−fundamental operation. We call this "autosync". This doesn't mean
546−simply mirroring a desk, since that wouldn't allow local changes.
547−We simply want to apply changes as they are made upstream, as
548−long as there are no conflicts with local changes.
549−
550−This is implemented by watching the other desk, and, when it has
551−changes, merging these changes into our desk with the usual merge
552−strategies.
553−
554−Note that it's quite reasonable for two desks to be autosynced to
555−each other. This results in any change on one desk being mirrored
556−to the other and vice versa.
557−
558−Additionally, it's fine to set up an autosync even if one desk,
559−the other desk, or both desks do not exist. The sync will be
560−activated when the upstream desk comes into existence and will
561−create the downstream desk if needed.
562−
563−## Commentary
564−
565−The first part of this section will be reference documentation for the data
566−types used by our filesystem. In fact, as a general guide, we recommend
567−reading and attempting to understand the data structures used in any
568−Hoon code before you try to read the code itself. Although complete
569−understanding of the data structures is impossible without seeing them
570−used in the code, an 80% understanding greatly clarifies the code. As
571−another general guide, when reading Hoon, it rarely pays off to
572−understand every line of code when it appears. Try to get the gist of
573−it, and then move on. The next time you come back to it, it'll likely
574−make a lot more sense.
575−
576−After a description of the data models, we'll give an overview of the
577−interface that vanes and applications can use to interact with the
578−filesystem.
579−
580−Finally, we'll dive into the code and the algorithms themselves. You
581−know, the fun part.
582−
583−### Data Models
584−
585−As you're reading through this section, remember you can always come
586−back to this when you run into these types later on. You're not going to
587−remember everything the first time through, but it is worth reading, or
588−at least skimming, this so that you get a rough idea of how our state is
589−organized.
590−
591−The types that are certainly worth reading are `++raft`, `++room`,
592−`++dome:clay`, `++ankh:clay`, `++rung:clay`, `++rang:clay`, `++blob:clay`, `++yaki:clay`, and `++nori:clay`
593−(possibly in that order). All in all, though, this section isn't too
594−long, so many readers may wish to quickly read through all of it. If you
595−get bored, though, just skip to the next section. You can always come
596−back when you need to.
597−
598−### `++raft`, formal state
599−
600−```hoon
601− ++ raft :: filesystem
602− $: fat=(map ship room) :: domestic
603− hoy=(map ship rung) :: foreign
604− ran=rang :: hashes
605− == ::
606−```
607−
608−This is the state of our vane. Anything that must be remembered between
609−calls to clay is stored in this state.
610−
611−`fat` is the set of domestic servers. This stores all the information
612−that is specfic to a particular ship on this pier. The keys to this map
613−are the ships on the current pier. all the information that is specific
614−to a particular foreign ship. The keys to this map are all the ships
615−whose filesystems we have attempted to access through clay.
616−
617−`ran` is the store of all commits and deltas, keyed by hash. The is
618−where all the "real" data we know is stored; the rest is "just
619−bookkeeping".
620−
621−#### `++room`, filesystem per domestic ship
622−
623−```hoon
624− ++ room :: fs per ship
625− $: hun=duct :: terminal duct
626− hez=(unit duct) :: sync duch
627− dos=(map desk dojo) :: native desk
628− == ::
629−```
630−
631−This is the representation of the filesystem of a ship on our pier.
632−
633−`hun` is the duct we use to send messages to dill to display
634−notifications of filesystem changes. Only `%note` gifts should be
635−produced along this duct. This is set by the `%init` kiss.
636−
637−`hez`, if present, is the duct we use to send sync messages to unix so
638−that they end up in the pier unix directory. Only `%ergo` gifts should
639−be producd along this duct. This is set by `%into` and `%invo` kisses.
640−
641−`dos` is a well-known operating system released in 1981. It is also the
642−set of desks on this ship, mapped to their data.
643−
644−#### `++desk`, filesystem branch
645−
646−```hoon
647− ++ desk ,@tas :: ship desk case spur
648−```
649−
650−This is the name of a branch of the filesystem. The default desks are
651−"arvo", "main", and "try". More may be created by simply referencing
652−them. Desks have independent histories and states, and they may be
653−merged into each other.
654−
655−### `++dojo`, domestic desk state
656−
657−```hoon
658− ++ dojo ,[p=cult q=dome] :: domestic desk state
659−```
660−
661−This is the all the data that is specific to a particular desk on a
662−domestic ship. `p` is the set of subscribers to this desk and `q` is the
663−data in the desk.
664−
665−#### `++cult`, subscriptions
666−
667−```hoon
668− ++ cult (map duct rave) :: subscriptions
669−```
670−
671−This is the set of subscriptions to a particular desk. The keys are the
672−ducts from where the subscriptions requests came. The results will be
673−produced along these ducts. The values are a description of the
674−requested information.
675−
676−#### `++rave:clay`, general subscription request
677−
678−```hoon
679− ++ rave :: general request
680− $% [& p=mood] :: single request
681− [| p=moat] :: change range
682− == ::
683−```
684−
685−This represents a subscription request for a desk. The request can be
686−for either a single item in the desk or else for a range of changes on
687−the desk.
688−
689−### `++rove`, stored general subscription request
690−
691−```hoon
692− ++ rove (each mood moot) :: stored request
693−```
694−
695−When we store a request, we store subscriptions with a little extra
696−information so that we can determine whether new versions actually
697−affect the path we're subscribed to.
698−
699−#### `++mood:clay`, single subscription request
700−
701−```hoon
702− ++ mood ,[p=care q=case r=path] :: request in desk
703−```
704−
705−This represents a request for the state of the desk at a particular
706−commit, specfied by `q`. `p` specifies what kind of information is
707−desired, and `r` specifies the path we are requesting.
708−
709−#### `++moat:clay`, range subscription request
710−
711−```hoon
712− ++ moat ,[p=case q=case r=path] :: change range
713−```
714−
715−This represents a request for all changes between `p` and `q` on path
716−`r`. You will be notified when a change is made to the node referenced
717−by the path or to any of its children.
718−
719−### `++moot`, stored range subscription request
720−
721−```hoon
722− ++ moot ,[p=case q=case r=path s=(map path lobe)] ::
723−```
724−
725−This is just a `++moat:clay` plus a map of paths to lobes. This map
726−represents the data at the node referenced by the path at case `p`, if
727−we've gotten to that case (else null). We only send a notification along
728−the subscription if the data at a new revision is different than it was.
729−
730−### `++care:clay`, clay submode
731−
732−```hoon
733− ++ care ?(%u %v %w %x %y %z) :: clay submode
734−```
735−
736−This specifies what type of information is requested in a subscription
737−or a scry.
738−
739−`%u` requests the `++rang:clay` at the current moment. Because this
740−information is not stored for any moment other than the present, we
741−crash if the `++case:clay` is not a `%da` for now.
742−
743−`%v` requests the `++dome:clay` at the specified commit.
744−
745−`%w` requests the revsion number of the desk.
746−
747−`%x` requests the file at a specified path at the specified commit. If
748−there is no node at that path or if the node has no contents (that is,
749−if `q:ankh` is null), then this produces null.
750−
751−`%y` requests a `++arch` of the specfied commit at the specified path.
752−
753−`%z` requests the `++ankh` of the specified commit at the specfied path.
754−
755−### `++arch`, shallow filesystem node
756−
757−```hoon
758− ++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node
759−```
760−
761−This is analogous to `++ankh:clay` except that the we have neither our
762−contents nor the ankhs of our children. The other fields are exactly the
763−same, so `p` is a hash of the associated ankh, `u.q`, if it exists, is a
764−hash of the contents of this node, and the keys of `r` are the names of
765−our children. `r` is a map to null rather than a set so that the
766−ordering of the map will be equivalent to that of `r:ankh`, allowing
767−efficient conversion.
768−
769−#### `++case:clay`, specifying a commit
770−
771−```hoon
772− ++ case :: ship desk case spur
773− $% [%da p=@da] :: date
774− [%tas p=@tas] :: label
775− [%ud p=@ud] :: number
776− == ::
777−```
778−
779−A commit can be referred to in three ways: `%da` refers to the commit
780−that was at the head on date `p`, `%tas` refers to the commit labeled
781−`p`, and `%ud` refers to the commit numbered `p`. Note that since these
782−all can be reduced down to a `%ud`, only numbered commits may be
783−referenced with a `++case:clay`.
784−
785−#### `++dome:clay`, desk data
786−
787−```hoon
788− ++ dome :: project state
789− $: ang=agon :: pedigree
790− ank=ankh :: state
791− let=@ud :: top id
792− hit=(map ,@ud tako) :: changes by id
793− lab=(map ,@tas ,@ud) :: labels
794− == ::
795−```
796−
797−This is the data that is actually stored in a desk.
798−
799−`ang` is unused and should be removed.
800−
801−`ank` is the current state of the desk. Thus, it is the state of the
802−filesystem at revison `let`. The head of a desk is always a numbered
803−commit.
804−
805−`let` is the number of the most recently numbered commit. This is also
806−the total number of numbered commits.
807−
808−`hit` is a map of numerical ids to hashes of commits. These hashes are
809−mapped into their associated commits in `hut:rang:clay`. In general, the keys
810−of this map are exactly the numbers from 1 to `let`, with no gaps. Of
811−course, when there are no numbered commits, `let` is 0, so `hit` is
812−null. Additionally, each of the commits is an ancestor of every commit
813−numbered greater than this one. Thus, each is a descendant of every
814−commit numbered less than this one. Since it is true that the date in
815−each commit (`t:yaki`) is no earlier than that of each of its parents,
816−the numbered commits are totally ordered in the same way by both
817−pedigree and date. Of course, not every commit is numbered. If that
818−sounds too complicated to you, don't worry about it. It basically
819−behaves exactly as you would expect.
820−
821−`lab` is a map of textual labels to numbered commits. Note that labels
822−can only be applied to numbered commits. Labels must be unique across a
823−desk.
824−
825−#### `++ankh`, filesystem node
826−
827−```hoon
828− ++ ankh :: fs node (new)
829− $: p=cash :: recursive hash
830− q=(unit ,[p=cash q=*]) :: file
831− r=(map ,@ta ankh) :: folders
832− == ::
833−```
834−
835−This is a single node in the filesystem. This may be file or a directory
836−or both. In earth filesystems, a node is a file xor a directory. On
837−mars, we're inclusive, so a node is a file ior a directory.
838−
839−`p` is a recursive hash that depends on the contents of the this file or
840−directory and on any children.
841−
842−`q` is the contents of this file, if any. `p.q` is a hash of the
843−contents while `q.q` is the data itself.
844−
845−`r` is the set of children of this node. In the case of a pure file,
846−this is empty. The keys are the names of the children and the values
847−are, recursively, the nodes themselves.
848−
849−#### `++cash`, ankh hash
850−
851−```hoon
852− ++ cash ,@uvH :: ankh hash
853−```
854−
855−This is a 128-bit hash of an ankh. These are mostly stored within ankhs
856−themselves, and they are used to check for changes in possibly-deep
857−hierarchies.
858−
859−#### `++rung`, filesystem per neighbor ship
860−
861−```hoon
862− ++ rung $: rus=(map desk rede) :: neighbor desks
863− == ::
864−```
865−
866−This is the filesystem of a neighbor ship. The keys to this map are all
867−the desks we know about on their ship.
868−
869−#### `++rede`, desk state
870−
871−```hoon
872− ++ rede :: universal project
873− $: lim=@da :: complete to
874− qyx=cult :: subscribers
875− ref=(unit rind) :: outgoing requests
876− dom=dome :: revision state
877− == ::
878−```
879−
880−This is our knowledge of the state of a desk, either foreign or
881−domestic.
882−
883−`lim` is the date of the last full update. We only respond to requests
884−for stuff before this time.
885−
886−`qyx` is the list of subscribers to this desk. For domestic desks, this
887−is simply `p:dojo`, all subscribers to the desk, while in foreign desks
888−this is all the subscribers from our ship to the foreign desk.
889−
890−`ref` is the request manager for the desk. For domestic desks, this is
891−null since we handle requests ourselves.
892−
893−`dom` is the actual data in the desk.
894−
895−#### `++rind`, request manager
896−
897−```hoon
898− ++ rind :: request manager
899− $: nix=@ud :: request index
900− bom=(map ,@ud ,[p=duct q=rave]) :: outstanding
901− fod=(map duct ,@ud) :: current requests
902− haw=(map mood (unit)) :: simple cache
903− == ::
904−```
905−
906−This is the request manager for a foreign desk.
907−
908−`nix` is one more than the index of the most recent request. Thus, it is
909−the next available request number.
910−
911−`bom` is the set of outstanding requests. The keys of this map are some
912−subset of the numbers between 0 and one less than `nix`. The members of
913−the map are exactly those requests that have not yet been fully
914−satisfied.
915−
916−`fod` is the same set as `bom`, but from a different perspective. In
917−particular, the values of `fod` are the same as the values of `bom`, and
918−the `p` out of the values of `bom` are the same as the keys of `fod`.
919−Thus, we can map ducts to their associated request number and `++rave:clay`,
920−and we can map numbers to their associated duct and `++rave:clay`.
921−
922−`haw` is a map from simple requests to their values. This acts as a
923−cache for requests that have already been made. Thus, the second request
924−for a particular `++mood:clay` is nearly instantaneous.
925−
926−#### `++rang:clay`, data store
927−
928−```hoon
929− ++ rang $: hut=(map tako yaki) ::
930− lat=(map lobe blob) ::
931− == ::
932−```
933−
934−This is a set of data keyed by hash. Thus, this is where the "real" data
935−is stored, but it is only meaningful if we know the hash of what we're
936−looking for.
937−
938−`hut` is a map from hashes to commits. We often get the hashes from
939−`hit:dome:clay`, which keys them by logical id. Not every commit has an id.
940−
941−`lat` is a map from hashes to the actual data. We often get the hashes
942−from a `++yaki`, a commit, which references this map to get the data.
943−There is no `++blob:clay` in any `++yaki:clay`. They are only accessible through
944−this map.
945−
946−#### `++tako:clay`, commit reference
947−
948−```hoon
949− ++ tako ,@ :: yaki ref
950−```
951−
952−This is a hash of a `++yaki:clay`, a commit. These are most notably used as
953−the keys in `hut:rang:clay`, where they are associated with the actual
954−`++yaki:clay`, and as the values in `hit:dome:clay`, where sequential ids are
955−associated with these.
956−
957−#### `++yaki:clay`, commit
958−
959−```hoon
960− ++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit
961−```
962−
963−This is a single commit.
964−
965−`p` is a list of the hashes of the parents of this commit. In most
966−cases, this will be a single commit, but in a merge there may be more
967−parents. In theory, there may be an arbitrary number of parents, but in
968−practice merges have exactly two parents. This may change in the future.
969−For commit 1, there is no parent.
970−
971−`q` is a map of the paths on a desk to the data at that location. If you
972−understand what a `++lobe:clay` and a `++blob:clay` is, then the type signature
973−here tells the whole story.
974−
975−`r` is the hash associated with this commit.
976−
977−`t` is the date at which this commit was made.
978−
979−#### `++lobe:clay`, data reference
980−
981−```hoon
982− ++ lobe ,@ :: blob ref
983−```
984−
985−This is a hash of a `++blob:clay`. These are most notably used in `lat:rang:clay`,
986−where they are associated with the actual `++blob:clay`, and as the values in
987−`q:yaki:clay`, where paths are associated with their data in a commit.
988−
989−#### `++blob:clay`, data
990−
991−```hoon
992− ++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q
993− [%direct p=lobe q=* r=umph] ::
994− [%indirect p=lobe q=* r=udon s=lobe] ::
995− == ::
996−```
997−
998−This is a node of data. In every case, `p` is the hash of the blob.
999−
1000−`%delta` is the case where we define the data by a delta on other data.
1001−In practice, the other data is always the previous commit, but nothing
1002−depends on this. `q` is the hash of the parent blob, and `r` is the
1003−delta.
1004−
1005−`%direct` is the case where we simply have the data directly. `q` is the
1006−data itself, and `r` is any preprocessing instructions. These almost
1007−always come from the creation of a file.
1008−
1009−`%indirect` is both of the preceding cases at once. `q` is the direct
1010−data, `r` is the delta, and `s` is the parent blob. It should always be
1011−the case that applying `r` to `s` gives the same data as `q` directly
1012−(with the prepreprocessor instructions in `p.r`). This exists purely for
1013−performance reasons. This is unused, at the moment, but in general these
1014−should be created when there are a long line of changes so that we do
1015−not have to traverse the delta chain back to the creation of the file.
1016−
1017−#### `++udon`, abstract delta
1018−
1019−```hoon
1020− ++ udon :: abstract delta
1021− $: p=umph :: preprocessor
1022− $= q :: patch
1023− $% [%a p=* q=*] :: trivial replace
1024− [%b p=udal] :: atomic indel
1025− [%c p=(urge)] :: list indel
1026− [%d p=upas q=upas] :: tree edit
1027− == ::
1028− == ::
1029−```
1030−
1031−This is an abstract change to a file. This is a superset of what would
1032−normally be called diffs. Diffs usually refer to changes in lines of
1033−text while we have the ability to do more interesting deltas on
1034−arbitrary data structures.
1035−
1036−`p` is any preprocessor instructions.
1037−
1038−`%a` refers to the trival delta of a complete replace of old data with
1039−new data.
1040−
1041−`%b` refers to changes in an opaque atom on the block level. This has
1042−very limited usefulness, and is not used at the moment.
1043−
1044−`%c` refers to changes in a list of data. This is often lines of text,
1045−which is your classic diff. We, however, will work on any list of data.
1046−
1047−`%d` refers to changes in a tree of data. This is general enough to
1048−describe changes to any hoon [noun](/docs/glossary/noun/), but often more special-purpose delta
1049−should be created for different content types. This is not used at the
1050−moment, and may in fact be unimplemented.
1051−
1052−#### `++urge`, list change
1053−
1054−```hoon
1055− ++ urge |*(a=_,* (list (unce a))) :: list change
1056−```
1057−
1058−This is a parametrized type for list changes. For example, `(urge ,@t)`
1059−is a list change for lines of text.
1060−
1061−#### `++unce`, change part of a list.
1062−
1063−```hoon
1064− ++ unce |* a=_,* :: change part
1065− $% [%& p=@ud] :: skip[copy]
1066− [%| p=(list a) q=(list a)] :: p -> q[chunk]
1067− == ::
1068−```
1069−
1070−This is a single change in a list of elements of type `a`. For example,
1071−`(unce ,@t)` is a single change in a lines of text.
1072−
1073−`%&` means the next `p` lines are unchanged.
1074−
1075−`%|` means the lines `p` have changed to `q`.
1076−
1077−#### `++umph`, preprocessing information
1078−
1079−```hoon
1080− ++ umph :: change filter
1081− $| $? %a :: no filter
1082− %b :: jamfile
1083− %c :: LF text
1084− == ::
1085− $% [%d p=@ud] :: blocklist
1086− == ::
1087−```
1088−
1089−This space intentionally left undocumented. This stuff will change once
1090−we get a well-typed clay.
1091−
1092−#### `++upas`, tree change
1093−
1094−```hoon
1095− ++ upas :: tree change (%d)
1096− $& [p=upas q=upas] :: cell
1097− $% [%0 p=axis] :: copy old
1098− [%1 p=*] :: insert new
1099− [%2 p=axis q=udon] :: mutate!
1100− == ::
1101−```
1102−
1103−This space intentionally left undocumented. This stuff is not known to
1104−work, and will likely change when we get a well-typed clay. Also, this
1105−is not a complicated type; it is not difficult to work out the meaning.
1106−
1107−#### `++nori:clay`, repository action
1108−
1109−```hoon
1110− ++ nori :: repository action
1111− $% [& q=soba] :: delta
1112− [| p=@tas] :: label
1113− == ::
1114−```
1115−
1116−This describes a change that we are asking clay to make to the desk.
1117−There are two kinds of changes that may be made: we can modify files or
1118−we can apply a label to a commit.
1119−
1120−In the `|` case, we will simply label the current commit with the given
1121−label. In the `&` case, we will apply the given changes.
1122−
1123−#### `++soba:clay`, delta
1124−
1125−```hoon
1126− ++ soba ,[p=cart q=(list ,[p=path q=miso])] :: delta
1127−```
1128−
1129−This describes a set of changes to make to a desk. The `cart` is simply
1130−a pair of the old hash and the new hash of the desk. The list is a list
1131−of changes keyed by the file they're changing. Thus, the paths are paths
1132−to files to be changed while `miso` is a description of the change
1133−itself.
1134−
1135−#### `++miso:clay`, ankh delta
1136−
1137−```hoon
1138− ++ miso :: ankh delta
1139− $% [%del p=*] :: delete
1140− [%ins p=*] :: insert
1141− [%mut p=udon] :: mutate
1142− == ::
1143−```
1144−
1145−There are three kinds of changes that may be made to a node in a desk.
1146−We can insert a file, in which case `p` is the contents of the new file.
1147−We can delete a file, in which case `p` is the contents of the old file.
1148−Finally, we can mutate that file, in which case the `udon` describes the
1149−changes we are applying to the file.
1150−
1151−#### `++mizu:clay`, merged state
1152−
1153−```hoon
1154− ++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state
1155−```
1156−
1157−This is the input to the `%merg` kiss, which allows us to perform a
1158−merge. The `p` is the number of the new head commit. The `q` is a map
1159−from numbers to commit hashes. This is all the new numbered commits that
1160−are to be inserted. The keys to this should always be the numbers from
1161−`let.dom` plus one to `p`, inclusive. The `r` is the maps of all the new
1162−commits and data. Since these are merged into the current state, no old
1163−commits or data need be here.
1164−
1165−#### `++riff:clay`, request/desist
1166−
1167−```hoon
1168− ++ riff ,[p=desk q=(unit rave)] :: request/desist
1169−```
1170−
1171−This represents a request for data about a particular desk. If `q`
1172−contains a `rave`, then this opens a subscription to the desk for that
1173−data. If `q` is null, then this tells clay to cancel the subscription
1174−along this duct.
1175−
1176−#### `++riot:clay`, response
1177−
1178−```hoon
1179− ++ riot (unit rant) :: response/complete
1180−```
1181−
1182−A riot is a response to a subscription. If null, the subscription has
1183−been completed, and no more responses will be sent. Otherwise, the
1184−`rant` is the produced data.
1185−
1186−#### `++rant:clay`, response data
1187−
1188−```hoon
1189− ++ rant :: namespace binding
1190− $: p=[p=care q=case r=@tas] :: clade release book
1191− q=path :: spur
1192− r=* :: data
1193− == ::
1194−```
1195−
1196−This is the data at a particular node in the filesystem. `p.p` specifies
1197−the type of data that was requested (and is produced). `q.p` gives the
1198−specific version reported (since a range of versions may be requested in
1199−a subscription). `r.p` is the desk. `q` is the path to the filesystem
1200−node. `r` is the data itself (in the format specified by `p.p`).
1201−
1202−### `++nako`, subscription response data
1203−
1204−```hoon
1205− ++ nako $: gar=(map ,@ud tako) :: new ids
1206− let=@ud :: next id
1207− lar=(set yaki) :: new commits
1208− bar=(set blob) :: new content
1209− == ::
1210−```
1211−
1212−This is the data that is produced by a request for a range of revisions
1213−of a desk. This allows us to easily keep track of a remote repository --
1214−all the new information we need is contained in the `nako`.
1215−
1216−`gar` is a map of the revisions in the range to the hash of the commit
1217−at that revision. These hashes can be used with `hut:rang:clay` to find the
1218−commit itself.
1219−
1220−`let` is either the last revision number in the range or the most recent
1221−revision number, whichever is smaller.
1222−
1223−`lar` is the set of new commits, and `bar` is the set of new content.
1224−
1225−## Public Interface
1226−
1227−As with all vanes, there are exactly two ways to interact with clay.
1228−`%clay` exports a namespace accessible through `.^`, which is described
1229−above under `++care:clay`. The primary way of interacting with clay, though,
1230−is by sending kisses and receiving gifts.
1231−
1232−```hoon
1233− ++ gift :: out result <-$
1234− $% [%ergo p=@p q=@tas r=@ud] :: version update
1235− [%note p=@tD q=tank] :: debug message
1236− [%writ p=riot] :: response
1237− == ::
1238− ++ kiss :: in request ->$
1239− $% [%info p=@p q=@tas r=nori] :: internal edit
1240− [%ingo p=@p q=@tas r=nori] :: internal noun edit
1241− [%init p=@p] :: report install
1242− [%into p=@p q=@tas r=nori] :: external edit
1243− [%invo p=@p q=@tas r=nori] :: external noun edit
1244− [%merg p=@p q=@tas r=mizu] :: internal change
1245− [%wart p=sock q=@tas r=path s=*] :: network request
1246− [%warp p=sock q=riff] :: file request
1247− == ::
1248−```
1249−
1250−There are only a small number of possible kisses, so it behooves us to
1251−describe each in detail.
1252−
1253−```hoon
1254− $% [%info p=@p q=@tas r=nori] :: internal edit
1255−
1256− [%into p=@p q=@tas r=nori] :: external edit
1257−```
1258−
1259−These two kisses are nearly identical. At a high level, they apply
1260−changes to the filesystem. Whenever we add, remove, or edit a file, one
1261−of these cards is sent. The `p` is the ship whose filesystem we're
1262−trying to change, the `q` is the desk we're changing, and the `r` is the
1263−request change. For the format of the requested change, see the
1264−documentation for `++nori:clay` above.
1265−
1266−When a file is changed in the unix filesystem, vere will send a `%into`
1267−kiss. This tells clay that the duct over which the kiss was sent is the
1268−duct that unix is listening on for changes. From within Arvo, though, we
1269−should never send a `%into` kiss. The `%info` kiss is exactly identical
1270−except it does not reset the duct.
1271−
1272−```hoon
1273− [%ingo p=@p q=@tas r=nori] :: internal noun edit
1274−
1275− [%invo p=@p q=@tas r=nori] :: external noun edit
1276−```
1277−
1278−These kisses are currently identical to `%info` and `%into`, though this
1279−will not always be the case. The intent is for these kisses to allow
1280−typed changes to clay so that we may store typed data. This is currently
1281−unimplemented.
1282−
1283−```hoon
1284− [%init p=@p] :: report install
1285−```
1286−
1287−Init is called when a ship is started on our pier. This simply creates a
1288−default `room` to go into our `raft`. Essentially, this initializes the
1289−filesystem for a ship.
1290−
1291−```hoon
1292− [%merg p=@p q=@tas r=mizu] :: internal change
1293−```
1294−
1295−This is called to perform a merge. This is most visibly called by
1296−:update to update the filesystem of the current ship to that of its
1297−sein. The `p` and `q` are as in `%info`, and the `r` is the description
1298−of the merge. See `++mizu:clay` above.
1299−
1300−XX
1301−`XX [%wake ~] :: timer activate XX`
1302−XX\
1303−XX This card is sent by unix at the time specified by `++doze`. This
1304−time is XX usually the closest time specified in a subscription request.
1305−When `%wake` is XX called, we update our subscribers if there have been
1306−any changes.
1307−
1308−```hoon
1309− [%wart p=sock q=@tas r=path s=*] :: network request
1310−```
1311−
1312−This is a request that has come across the network for a particular
1313−file. When another ship asks for a file from us, that request comes to
1314−us in the form of a `%wart` kiss. This is handled by trivially turning
1315−it into a `%warp`.
1316−
1317−```hoon
1318− [%warp p=sock q=riff] :: file request
1319−```
1320−
1321−This is a request for information about a particular desk. This is, in
1322−its most general form, a subscription, though in many cases it is the
1323−trivial case of a subscription -- a read. See `++riff:clay` for the format of
1324−the request.
1325−
1326−## Lifecycle of a Local Read
1327−
1328−There are two real types of interaction with a filesystem: you can read,
1329−and you can write. We'll describe each process, detailing both the flow
1330−of control followed by the kernel and the algorithms involved. The
1331−simpler case is that of the read, so we'll begin with that.
1332−
1333−When a vane or an application wishes to read a file from the filesystem,
1334−it sends a `%warp` kiss, as described above. Of course, you may request
1335−a file on another ship and, being a global filesystem, clay will happily
1336−produce it for you. That code pathway will be described in another
1337−section; here, we will restrict ourselves to examining the case of a
1338−read from a ship on our own pier.
1339−
1340−The kiss can request either a single version of a file node or a range
1341−of versions of a desk. Here, we'll deal only with a request for a single
1342−version.
1343−
1344−As in all vanes, a kiss enters clay via a call to `++call`. Scanning
1345−through the arm, we quickly see where `%warp` is handled.
1346−
1347−```hoon
1348− ?: =(p.p.q.hic q.p.q.hic)
1349− =+ une=(un p.p.q.hic now ruf)
1350− =+ wex=(di:une p.q.q.hic)
1351− =+ ^= wao
1352− ?~ q.q.q.hic
1353− (ease:wex hen)
1354− (eave:wex hen u.q.q.q.hic)
1355− =+ ^= woo
1356− abet:wao
1357− [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
1358−```
1359−
1360−We're following the familar patern of producing a list of moves and an
1361−updated state. In this case, the state is `++raft`.
1362−
1363−We first check to see if the sending and receiving ships are the same.
1364−If they're not, then this is a request for data on another ship. We
1365−describe that process later. Here, we discuss only the case of a local
1366−read.
1367−
1368−At a high level, the call to `++un` sets up the core for the domestic
1369−ship that contains the files we're looking for. The call to `++di` sets
1370−up the core for the particular desk we're referring to.
1371−
1372−After this, we perform the actual request. If there is no rave in the
1373−riff, then that means we are cancelling a request, so we call
1374−`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
1375−call `++abet:de` to resolve our various types of output into actual
1376−moves. We produce the moves we found above and the `++un` core resolved
1377−with `++pish:un` (putting the modified desk in the room) and `++abet:un`
1378−(putting the modified room in the raft).
1379−
1380−Much of this is fairly straightforward, so we'll only describe `++ease`,
1381−`++eave`, and `++abet:de`. Feel free to look up the code to the other
1382−steps -- it should be easy to follow.
1383−
1384−Although it's called last, it's usually worth examining `++abet` first,
1385−since it defines in what ways we can cause side effects. Let's do that,
1386−and also a few of the lines at the beginning of `++de`.
1387−
1388−```hoon
1389− =| yel=(list ,[p=duct q=gift])
1390− =| byn=(list ,[p=duct q=riot])
1391− =| vag=(list ,[p=duct q=gift])
1392− =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
1393− =| tag=(list ,[p=duct q=path c=note])
1394− |%
1395− ++ abet
1396− ^- [(list move) rede]
1397− :_ red
1398− ;: weld
1399− %+ turn (flop yel)
1400− |=([a=duct b=gift] [hun %give b])
1401− ::
1402− %+ turn (flop byn)
1403− |=([a=duct b=riot] [a %give [%writ b]])
1404− ::
1405− %+ turn (flop vag)
1406− |=([a=duct b=gift] [a %give b])
1407− ::
1408− %+ turn (flop say)
1409− |= [a=duct b=path c=ship d=[p=@ud q=riff]]
1410− :- a
1411− [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
1412− ::
1413− %+ turn (flop tag)
1414− |=([a=duct b=path c=note] [a %pass b c])
1415− ==
1416−```
1417−
1418−This is very simple code. We see there are exactly five different kinds
1419−of side effects we can generate.
1420−
1421−In `yel` we put gifts that we wish to be sent along the `hun:room` duct
1422−to dill. See the documentation for `++room` above. This is how we
1423−display messages to the terminal.
1424−
1425−In `byn` we put riots that we wish returned to subscribers. Recall that
1426−a riot is a response to a subscription. These are returned to our
1427−subscribers in the form of a `%writ` gift.
1428−
1429−In `vag` we put gifts along with the ducts on which to send them. This
1430−allows us to produce arbitrary gifts, but in practice this is only used
1431−to produce `%ergo` gifts.
1432−
1433−In `say` we put messages we wish to pass to ames. These messages are
1434−used to request information from clay on other piers. We must provide
1435−not only the duct and the request (the riff), but also the return path,
1436−the other ship to talk to, and the sequence number of the request.
1437−
1438−In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
1439−the only notes we pass here are `%wait` and `%rest` to the timer vane.
1440−
1441−Now that we know what kinds of side effects we may have, we can jump
1442−into the handling of requests.
1443−
1444−```hoon
1445− ++ ease :: release request
1446− |= hen=duct
1447− ^+ +>
1448− ?~ ref +>
1449− =+ rov=(~(got by qyx) hen)
1450− =. qyx (~(del by qyx) hen)
1451− (mabe rov (cury best hen))
1452− =. qyx (~(del by qyx) hen)
1453− |- ^+ +>+.$
1454− =+ nux=(~(get by fod.u.ref) hen)
1455− ?~ nux +>+.$
1456− %= +>+.$
1457− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
1458− fod.u.ref (~(del by fod.u.ref) hen)
1459− bom.u.ref (~(del by bom.u.ref) u.nux)
1460− ==
1461−```
1462−
1463−This is called when we're cancelling a subscription. For domestic desks,
1464−`ref` is null, so we're going to cancel any timer we might have created.
1465−We first delete the duct from our map of requests, and then we call
1466−`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
1467−have started a timer. We'll describe `++best` and `++mabe` momentarily.
1468−
1469−Although we said we're not going to talk about foreign requests yet,
1470−it's easy to see that for foreign desks, we cancel any outstanding
1471−requests for this duct and send a message over ames to the other ship
1472−telling them to cancel the subscription.
1473−
1474−```hoon
1475− ++ best
1476− |= [hen=duct tym=@da]
1477− %_(+> tag :_(tag [hen /tyme %t %rest tym]))
1478−```
1479−
1480−This simply pushes a `%rest` note onto `tag`, from where it will be
1481−passed back to arvo to be handled. This cancels the timer at the given
1482−duct (with the given time).
1483−
1484−```hoon
1485− ++ mabe :: maybe fire function
1486− |* [rov=rove fun=$+(@da _+>.^$)]
1487− ^+ +>.$
1488− %- fall :_ +>.$
1489− %- bind :_ fun
1490− ^- (unit ,@da)
1491− ?- -.rov
1492− %&
1493− ?. ?=(%da -.q.p.rov) ~
1494− `p.q.p.rov
1495− %|
1496− =* mot p.rov
1497− %+ hunt
1498− ?. ?=(%da -.p.mot) ~
1499− ?.((lth now p.p.mot) ~ [~ p.p.mot])
1500− ?. ?=(%da -.q.mot) ~
1501− ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
1502− ==
1503−```
1504−
1505−This decides whether the given request can only be satsified in the
1506−future. In that case, we call the given function with the time in the
1507−future when we expect to have an update to give to this request. This is
1508−called with `++best` to cancel timers and with `++bait` to start them.
1509−
1510−For single requests, we have a time if the request is for a particular
1511−time (which is assumed to be in the future). For ranges of requests, we
1512−check both the start and end cases to see if they are time cases. If so,
1513−we choose the earlier time.
1514−
1515−If any of those give us a time, then we call the given funciton with the
1516−smallest time.
1517−
1518−The more interesting case is, of course, when we're not cancelling a
1519−subscription but starting one.
1520−
1521−```hoon
1522− ++ eave :: subscribe
1523− |= [hen=duct rav=rave]
1524− ^+ +>
1525− ?- -.rav
1526− &
1527− ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
1528− ~& [%clay-fail p.q.p.rav %now now]
1529− !!
1530− =+ ver=(aver p.rav)
1531− ?~ ver
1532− (duce hen rav)
1533− ?~ u.ver
1534− (blub hen)
1535− (blab hen p.rav u.u.ver)
1536−```
1537−
1538−There are two types of subscriptions -- either we're requesting a single
1539−file or we're requesting a range of versions of a desk. We'll dicuss the
1540−simpler case first.
1541−
1542−First, we check that we're not requesting the `rang` from any time other
1543−than the present. Since we don't store that information for any other
1544−time, we can't produce it in a referentially transparent manner for any
1545−time other than the present.
1546−
1547−Then, we try to read the requested `mood:clay` `p.rav`. If we can't access
1548−the request data right now, we call `++duce` to put the request in our
1549−queue to be satisfied when the information becomes available.
1550−
1551−This case occurs when we make a request for a case whose (1) date is
1552−after the current date, (2) number is after the current number, or (3)
1553−label is not yet used.
1554−
1555−```hoon
1556− ++ duce :: produce request
1557− |= [hen=duct rov=rove]
1558− ^+ +>
1559− =. qyx (~(put by qyx) hen rov)
1560− ?~ ref
1561− (mabe rov (cury bait hen))
1562− |- ^+ +>+.$ :: XX why?
1563− =+ rav=(reve rov)
1564− =+ ^= vaw ^- rave
1565− ?. ?=([%& %v *] rav) rav
1566− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
1567− =+ inx=nix.u.ref
1568− %= +>+.$
1569− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
1570− nix.u.ref +(nix.u.ref)
1571− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
1572− fod.u.ref (~(put by fod.u.ref) hen inx)
1573− ==
1574−```
1575−
1576−The code for `++duce` is nearly the exact inverse of `++ease`, which in
1577−the case of a domestic desk is very simple -- we simply put the duct and
1578−rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
1579−Recall that `ref` is null for domestic desks and that `++mabe` fires the
1580−given function with the time we need to be woken up at, if we need to be
1581−woken up at a particular time.
1582−
1583−```hoon
1584− ++ bait
1585− |= [hen=duct tym=@da]
1586− %_(+> tag :_(tag [hen /tyme %t %wait tym]))
1587−```
1588−
1589−This sets an alarm by sending a `%wait` card with the given time to the
1590−timer vane.
1591−
1592−Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
1593−subscription. This occurs when we make (1) a `%x` request for a file
1594−that does not exist, (2) a `%w` request with a case that is not a
1595−number, or (3) a `%w` request with a nonempty path. The `++blub` is
1596−exactly what you would expect it to be.
1597−
1598−```hoon
1599− ++ blub :: ship stop
1600− |= hen=duct
1601− %_(+> byn [[hen ~] byn])
1602−```
1603−
1604−We notify the duct that we're cancelling their subscription since it
1605−isn't satisfiable.
1606−
1607−Otherwise, we have received the desired information, so we send it on to
1608−the subscriber with `++blab`.
1609−
1610−```hoon
1611− ++ blab :: ship result
1612− |= [hen=duct mun=mood dat=*]
1613− ^+ +>
1614− +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
1615−```
1616−
1617−The most interesting arm called in `++eave` is, of course, `++aver`,
1618−where we actually try to read the data.
1619−
1620−```hoon
1621− ++ aver :: read
1622− |= mun=mood
1623− ^- (unit (unit ,*))
1624− ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
1625− ~& [%clay-fail p.q.mun %now now]
1626− !!
1627− =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
1628− ?^ ezy ezy
1629− =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
1630− ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
1631−```
1632−
1633−We check immediately that we're not requesting the `rang` for any time
1634−other than the present.
1635−
1636−If this is a foreign desk, then we check our cache for the specific
1637−request. If either this is a domestic desk or we don't have the request
1638−in our cache, then we have to actually go read the data from our dome.
1639−
1640−We need to do two things. First, we try to find the number of the commit
1641−specified by the given case, and then we try to get the data there.
1642−
1643−Here, we jump into `arvo/zuse.hoon`, which is where much of the
1644−algorithmic code is stored, as opposed to the clay interface, which is
1645−stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
1646−
1647−```hoon
1648− ++ case-to-aeon :: case-to-aeon:ze
1649− |= lok=case :: act count through
1650− ^- (unit aeon)
1651− ?- -.lok
1652− %da
1653− ?: (gth p.lok lim) ~
1654− |- ^- (unit aeon)
1655− ?: =(0 let) [~ 0] :: avoid underflow
1656− ?: %+ gte p.lok
1657− =< t
1658− %- tako-to-yaki
1659− %- aeon-to-tako
1660− let
1661− [~ let]
1662− $(let (dec let))
1663− ::
1664− %tas (~(get by lab) p.lok)
1665− %ud ?:((gth p.lok let) ~ [~ p.lok])
1666− ==
1667−```
1668−
1669−We handle each type of `case:clay` differently. The latter two types are
1670−easy.
1671−
1672−If we're requesting a revision by label, then we simply look up the
1673−requested label in `lab` from the given dome. If it exists, that is our
1674−aeon; else we produce null, indicating the requested revision does not
1675−yet exist.
1676−
1677−If we're requesting a revision by number, we check if we've yet reached
1678−that number. If so, we produce the number; else we produce null.
1679−
1680−If we're requesting a revision by date, we check first if the date is in
1681−the future, returning null if so. Else we start from the most recent
1682−revision and scan backwards until we find the first revision committed
1683−before that date, and we produce that. If we requested a date before any
1684−revisions were committed, we produce `0`.
1685−
1686−The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
1687−
1688−```hoon
1689− ++ aeon-to-tako ~(got by hit)
1690−
1691− ++ tako-to-yaki ~(got by hut) :: grab yaki
1692−```
1693−
1694−We simply look up the aeon or tako in their respective maps (`hit` and
1695−`hut`).
1696−
1697−Assuming we got a valid version number, `++aver` calls
1698−`++read-at-aeon:ze`, which reads the requested data at the given
1699−revision.
1700−
1701−```hoon
1702− ++ read-at-aeon :: read-at-aeon:ze
1703− |= [oan=aeon mun=mood] :: seek and read
1704− ^- (unit)
1705− ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
1706− ?^(r.mun ~ [~ oan])
1707− (read:(rewind oan) mun)
1708−```
1709−
1710−If we're requesting the revision number with a case other than by
1711−number, then we go ahead and just produce the number we were given.
1712−Otherwise, we call `++rewind` to rewind our state to the given revision,
1713−and then we call `++read` to get the requested information.
1714−
1715−```hoon
1716− ++ rewind :: rewind:ze
1717− |= oan=aeon :: rewind to aeon
1718− ^+ +>
1719− ?: =(let oan) +>
1720− ?: (gth oan let) !! :: don't have version
1721− +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
1722−```
1723−
1724−If we're already at the requested version, we do nothing. If we're
1725−requesting a version later than our head, we are unable to comply.
1726−
1727−Otherwise, we get the hash of the commit at the number, and from that we
1728−get the commit itself (the yaki), which has the map of path to lobe that
1729−represents a version of the filesystem. We call `++checkout-ankh` to
1730−checkout the commit, and we replace `ank` in our context with the
1731−result.
1732−
1733−```hoon
1734− ++ checkout-ankh :: checkout-ankh:ze
1735− |= hat=(map path lobe) :: checkout commit
1736− ^- ankh
1737− %- cosh
1738− %+ roll (~(tap by hat) ~)
1739− |= [[pat=path bar=lobe] ank=ankh]
1740− ^- ankh
1741− %- cosh
1742− ?~ pat
1743− =+ zar=(lobe-to-noun bar)
1744− ank(q [~ (sham zar) zar])
1745− =+ nak=(~(get by r.ank) i.pat)
1746− %= ank
1747− r %+ ~(put by r.ank) i.pat
1748− $(pat t.pat, ank (fall nak _ankh))
1749− ==
1750−```
1751−
1752−Twice we call `++cosh`, which hashes a commit, updating `p` in an
1753−`ankh`. Let's jump into that algorithm before we describe
1754−`++checkout-ankh`.
1755−
1756−```hoon
1757− ++ cosh :: locally rehash
1758− |= ank=ankh :: NB v/unix.c
1759− ank(p rehash:(zu ank))
1760−```
1761−
1762−We simply replace `p` in the hash with the `cash` we get from a call to
1763−`++rehash:zu`.
1764−
1765−```hoon
1766− ++ zu !: :: filesystem
1767− |= ank=ankh :: filesystem state
1768− =| myz=(list ,[p=path q=miso]) :: changes in reverse
1769− =| ram=path :: reverse path into
1770− |%
1771− ++ rehash :: local rehash
1772− ^- cash
1773− %+ mix ?~(q.ank 0 p.u.q.ank)
1774− =+ axe=1
1775− |- ^- cash
1776− ?~ r.ank _@
1777− ;: mix
1778− (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
1779− $(r.ank l.r.ank, axe (peg axe 2))
1780− $(r.ank r.r.ank, axe (peg axe 3))
1781− ==
1782−```
1783−
1784−`++zu` is a core we set up with a particular filesystem node to traverse
1785−a checkout of the filesystem and access the actual data inside it. One
1786−of the things we can do with it is to create a recursive hash of the
1787−node.
1788−
1789−In `++rehash`, if this node is a file, then we xor the remainder of the
1790−hash with the hash of the contents of the file. The remainder of the
1791−hash is `0` if we have no children, else we descend into our children.
1792−Basically, we do a half SHA-256 of the xor of the axis of this child and
1793−the half SHA-256 of the xor of the name of the child and the hash of the
1794−child. This is done for each child and all the results are xored
1795−together.
1796−
1797−Now we return to our discussion of `++checkout-ankh`.
1798−
1799−We fold over every path in this version of the filesystem and create a
1800−great ankh out of them. First, we call `++lobe-to-noun` to get the raw
1801−data referred to be each lobe.
1802−
1803−```hoon
1804− ++ lobe-to-noun :: grab blob
1805− |= p=lobe :: ^- *
1806− %- blob-to-noun
1807− (lobe-to-blob p)
1808−```
1809−
1810−This converts a lobe into the raw data it refers to by first getting the
1811−blob with `++lobe-to-blob` and converting that into data with
1812−`++blob-to-noun`.
1813−
1814−```hoon
1815− ++ lobe-to-blob ~(got by lat) :: grab blob
1816−```
1817−
1818−This just grabs the blob that the lobe refers to.
1819−
1820−```hoon
1821− ++ blob-to-noun :: grab blob
1822− |= p=blob
1823− ?- -.p
1824− %delta (lump r.p (lobe-to-noun q.p))
1825− %direct q.p
1826− %indirect q.p
1827− ==
1828−```
1829−
1830−If we have either a direct or an indirect blob, then the data is stored
1831−right in the blob. Otherwise, we have to reconstruct it from the diffs.
1832−We do this by calling `++lump` on the diff in the blob with the data
1833−obtained by recursively calling the parent of this blob.
1834−
1835−```hoon
1836− ++ lump :: apply patch
1837− |= [don=udon src=*]
1838− ^- *
1839− ?+ p.don ~|(%unsupported !!)
1840− %a
1841− ?+ -.q.don ~|(%unsupported !!)
1842− %a q.q.don
1843− %c (lurk ((hard (list)) src) p.q.don)
1844− %d (lure src p.q.don)
1845− ==
1846− ::
1847− %c
1848− =+ dst=(lore ((hard ,@) src))
1849− %- roly
1850− ?+ -.q.don ~|(%unsupported !!)
1851− %a ((hard (list ,@t)) q.q.don)
1852− %c (lurk dst p.q.don)
1853− ==
1854− ==
1855−```
1856−
1857−This is defined in `arvo/hoon.hoon` for historical reasons which are
1858−likely no longer applicable. Since the `++umph` structure will likely
1859−change we convert clay to be a typed filesystem, we'll only give a
1860−high-level description of this process. If we have a `%a` udon, then
1861−we're performing a trivial replace, so we produce simply `q.q.don`. If
1862−we have a `%c` udon, then we're performing a list merge (as in, for
1863−example, lines of text). The merge is performed by `++lurk`.
1864−
1865−```hoon
1866− ++ lurk :: apply list patch
1867− |* [hel=(list) rug=(urge)]
1868− ^+ hel
1869− =+ war=`_hel`~
1870− |- ^+ hel
1871− ?~ rug (flop war)
1872− ?- -.i.rug
1873− &
1874− %= $
1875− rug t.rug
1876− hel (slag p.i.rug hel)
1877− war (weld (flop (scag p.i.rug hel)) war)
1878− ==
1879− ::
1880− |
1881− %= $
1882− rug t.rug
1883− hel =+ gur=(flop p.i.rug)
1884− |- ^+ hel
1885− ?~ gur hel
1886− ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
1887− war (weld q.i.rug war)
1888− ==
1889− ==
1890−```
1891−
1892−We accumulate our final result in `war`. If there's nothing more in our
1893−list of merge instructions (unces), we just reverse `war` and produce
1894−it. Otherwise, we process another unce. If the unce is of type `&`, then
1895−we have `p.i.rug` lines of no changes, so we just copy them over from
1896−`hel` to `war`. If the unice is of type `|`, then we verify that the
1897−source lines (in `hel`) are what we expect them to be (`p.i.rug`),
1898−crashing on failure. If they're good, then we append the new lines in
1899−`q.i.rug` onto `war`.
1900−
1901−And that's really it. List merges are pretty easy. Anyway, if you
1902−recall, we were discussing `++checkout-ankh`.
1903−
1904−```hoon
1905− ++ checkout-ankh :: checkout-ankh:ze
1906− |= hat=(map path lobe) :: checkout commit
1907− ^- ankh
1908− %- cosh
1909− %+ roll (~(tap by hat) ~)
1910− |= [[pat=path bar=lobe] ank=ankh]
1911− ^- ankh
1912− %- cosh
1913− ?~ pat
1914− =+ zar=(lobe-to-noun bar)
1915− ank(q [~ (sham zar) zar])
1916− =+ nak=(~(get by r.ank) i.pat)
1917− %= ank
1918− r %+ ~(put by r.ank) i.pat
1919− $(pat t.pat, ank (fall nak _ankh))
1920− ==
1921−```
1922−
1923−If the path is null, then we calculate `zar`, the raw data at the path
1924−`pat` in this version. We produce the given ankh with the correct data.
1925−
1926−Otherwise, we try to get the child we're looking at from our parent
1927−ankh. If it's already been created, this succeeds; otherwise, we simply
1928−create a default blank ankh. We place ourselves in our parent after
1929−recursively computing our children.
1930−
1931−This algorithm really isn't that complicated, but it may not be
1932−immediately obvious why it works. An example should clear everything up.
1933−
1934−Suppose `hat` is a map of the following information.
1935−
1936−```
1937− /greeting --> "customary upon meeting"
1938− /greeting/english --> "hello"
1939− /greeting/spanish --> "hola"
1940− /greeting/russian/short --> "привет"
1941− /greeting/russian/long --> "Здравствуйте"
1942− /farewell/russian --> "до свидания"
1943−```
1944−
1945−Furthermore, let's say that we process them in this order:
1946−
1947−```
1948− /greeting/english
1949− /greeting/russian/short
1950− /greeting/russian/long
1951− /greeting
1952− /greeting/spanish
1953− /farewell/russian
1954−```
1955−
1956−Then, the first path we process is `/greeting/english` . Since our path
1957−is not null, we try to get `nak`, but because our ankh is blank at this
1958−point it doesn't find anything. Thus, update our blank top-level ankh
1959−with a child `%greeting`. and recurse with the blank `nak` to create the
1960−ankh of the new child.
1961−
1962−In the recursion, we our path is `/english` and our ankh is again blank.
1963−We try to get the `english` child of our ankh, but this of course fails.
1964−Thus, we update our blank `/greeting` ankh with a child `english`
1965−produced by recursing.
1966−
1967−Now our path is null, so we call `++lobe-to-noun` to get the actual
1968−data, and we place it in the brand-new ankh.
1969−
1970−Next, we process `/greeting/russian/short`. Since our path is not null,
1971−we try to get the child named `%greeting`, which does exist since we
1972−created it earlier. We put modify this child by recursing on it. Our
1973−path is now `/russian/short`, so we look for a `%russian` child in our
1974−`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
1975−path is now `/short`, so we look for a `%short` child in our
1976−`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
1977−Now our path is null, so we set the contents of this node to `"привет"`,
1978−and we're done processing this path.
1979−
1980−Next, we process `/greeting/russian/long`. This proceeds similarly to
1981−the previous except that now the ankh for `/greeting/russian` already
1982−exists, so we simply reuse it rather than creating a new one. Of course,
1983−we still must create a new `/greeting/russian/long` ankh.
1984−
1985−Next, we process `/greeting`. This ankh already exists, so after we've
1986−recursed once, our path is null, and our ankh is not blank -- it already
1987−has two children (and two grandchildren). We don't touch those, though,
1988−since a node may be both a file and a directory. We just add the
1989−contents of the file -- "customary upon meeting" -- to the existing
1990−ankh.
1991−
1992−Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
1993−already exists, but it doesn't have a `%spanish` child, so we create
1994−that, taking care not to disturb the contents of the `/greeting` file.
1995−We put "hola" into the ankh and call it good.
1996−
1997−Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
1998−doesn't exist, so we create it. Clearly the newly-created ankh doesn't
1999−have any children, so we have to add a `%russian` child, and in this
2000−child we put our last content -- "до свидания".
2001−
2002−We hope it's fairly obvious that the order we process the paths doesn't
2003−affect the final ankh tree. The tree will be constructed in a very
2004−different order depending on what order the paths come in, but the
2005−resulting tree is independent of order.
2006−
2007−At any rate, we were talking about something important, weren't we? If
2008−you recall, that concludes our discussion of `++rewind`, which was
2009−called from `++read-at-aeon`. In summary, `++rewind` returns a context
2010−in which our current state is (very nearly) as it was when the specified
2011−version of the desk was the head. This allows `++read-at-aeon` to call
2012−`++read` to read the requested information.
2013−
2014−```hoon
2015− ++ read :: read:ze
2016− |= mun=mood :: read at point
2017− ^- (unit)
2018− ?: ?=(%v p.mun)
2019− [~ `dome`+<+<.read]
2020− ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
2021− ?^(r.mun ~ [~ let])
2022− ?: ?=(%w p.mun)
2023− =+ ^= yak
2024− %- tako-to-yaki
2025− %- aeon-to-tako
2026− let
2027− ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
2028− ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
2029− (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
2030−```
2031−
2032−If we're requesting the dome, then we just return that immediately.
2033−
2034−If we're requesting the revision number of the desk and we're not
2035−requesting it by number, then we just return the current number of this
2036−desk. Note of course that this was really already handled in
2037−`++read-at-aeon`.
2038−
2039−If we're requesting a `%w` with a specific revision number, then we do
2040−something or other with the commit there. It's kind of weird, and it
2041−doesn't seem to work, so we'll ignore this case.
2042−
2043−Otherwise, we descend into the ankh tree to the given path with
2044−`++descend-path:zu`, and then we handle specific request in `++query`.
2045−
2046−```hoon
2047− ++ descend-path :: descend recursively
2048− |= way=path
2049− ^+ +>
2050− ?~(way +> $(way t.way, +> (descend i.way)))
2051−```
2052−
2053−This is simple recursion down into the ankh tree. `++descend` descends
2054−one level, so this will eventually get us down to the path we want.
2055−
2056−```hoon
2057− ++ descend :: descend
2058− |= lol=@ta
2059− ^+ +>
2060− =+ you=(~(get by r.ank) lol)
2061− +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
2062−```
2063−
2064−`ram` is the path that we're at, so to descend one level we push the
2065−name of this level onto that path. We update the ankh with the correct
2066−one at that path if it exists; else we create a blank one.
2067−
2068−Once we've decscended to the correct level, we need to actually deal
2069−with the request.
2070−
2071−```hoon
2072− ++ query :: query:ze
2073− |= ren=?(%u %v %x %y %z) :: endpoint query
2074− ^- (unit ,*)
2075− ?- ren
2076− %u [~ `rang`+<+>.query]
2077− %v [~ `dome`+<+<.query]
2078− %x ?~(q.ank ~ [~ q.u.q.ank])
2079− %y [~ as-arch]
2080− %z [~ ank]
2081− ==
2082−```
2083−
2084−Now that everything's set up, it's really easy. If they're requesting
2085−the rang, dome, or ankh, we give it to them. If the contents of a file,
2086−we give it to them if it is in fact a file. If the `arch`, then we
2087−calculate it with `++as-arch`.
2088−
2089−```hoon
2090− ++ as-arch :: as-arch:ze
2091− ^- arch :: arch report
2092− :+ p.ank
2093− ?~(q.ank ~ [~ p.u.q.ank])
2094− |- ^- (map ,@ta ,~)
2095− ?~ r.ank ~
2096− [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
2097−```
2098−
2099−This very simply strips out all the "real" data and returns just our own
2100−hash, the hash of the file contents (if we're a file), and a map of the
2101−names of our immediate children.
2102−
2103−## Lifecycle of a Local Subscription
2104−
2105−A subscription to a range of revisions of a desk initially follows the
2106−same path that a single read does. In `++aver`, we checked the head of
2107−the given rave. If the head was `&`, then it was a single request, so we
2108−handled it above. If `|`, then we handle it with the following code.
2109−
2110−```hoon
2111− =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
2112− ?~ nab
2113− ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
2114− (duce hen (rive rav))
2115− =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
2116− ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
2117− (blub hen)
2118− =+ top=?~(huy let.dom u.huy)
2119− =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
2120− =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
2121− =. +>.$
2122− ?: =(sar ear) +>.$
2123− =+ fud=(~(make-nako ze lim dom ran) u.nab top)
2124− (bleb hen u.nab fud)
2125− ?^ huy
2126− (blub hen)
2127− =+ ^= ptr ^- case
2128− [%ud +(let.dom)]
2129− (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
2130− ==
2131−```
2132−
2133−Recall that `++case-to-aeon:ze` produces the revision number that a case
2134−corresponds to, if it corresponds to any. If it doesn't yet correspond
2135−to a revision, then it produces null.
2136−
2137−Thus, we first check to see if we've even gotten to the beginning of the
2138−range of revisions requested. If not, then we assert that we haven't yet
2139−gotten to the end of the range either, because that would be really
2140−strange. If not, then we immediately call `++duce`, which, if you
2141−recall, for a local request, simply puts this duct and rove into our
2142−cult `qyx`, so that we know who to respond to when the revision does
2143−appear.
2144−
2145−If we've already gotten to the first revision, then we can produce some
2146−content immediately. If we've also gotten to the final revision, and
2147−that revision is earlier than the start revision, then it's a bad
2148−request and we call `++blub`, which tells the subscriber that his
2149−subscription will not be satisfied.
2150−
2151−Otherwise, we find the data at the given path at the beginning of the
2152−subscription and at the last available revision in the subscription. If
2153−they're the same, then we don't send a notification. Otherwise, we call
2154−`++gack`, which creates the `++nako` we need to produce. We call
2155−`++bleb` to actually produce the information.
2156−
2157−If we already have the last requested revision, then we also tell the
2158−subscriber with `++blub` that the subscription will receive no further
2159−updates.
2160−
2161−If there will be more revisions in the subscription, then we call
2162−`++duce`, adding the duct to our subscribers. We modify the rove to
2163−start at the next revision since we've already handled all the revisions
2164−up to the present.
2165−
2166−We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
2167−`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
2168−we'll start with that.
2169−
2170−```hoon
2171− ++ bleb :: ship sequence
2172− |= [hen=duct ins=@ud hip=nako]
2173− ^+ +>
2174− (blab hen [%w [%ud ins] ~] hip)
2175−```
2176−
2177−We're given a duct, the beginning revision number, and the nako that
2178−contains the updates since that revision. We use `++blab` to produce
2179−this result to the subscriber. The case is `%w` with a revision number
2180−of the beginning of the subscription, and the data is the nako itself.
2181−
2182−We call `++lobes-at-path:ze` to get the data at the particular path.
2183−
2184−```hoon
2185− ++ lobes-at-path :: lobes-at-path:ze
2186− |= [oan=aeon pax=path] :: data at path
2187− ^- (map path lobe)
2188− ?: =(0 oan) ~
2189− %- mo
2190− %+ skim
2191− %. ~
2192− %~ tap by
2193− =< q
2194− %- tako-to-yaki
2195− %- aeon-to-tako
2196− oan
2197− |= [p=path q=lobe]
2198− ?| ?=(~ pax)
2199− ?& !?=(~ p)
2200− =(-.pax -.p)
2201− $(p +.p, pax +.pax)
2202− == ==
2203−```
2204−
2205−At revision zero, the theoretical common revision between all
2206−repositories, there is no data, so we produce null.
2207−
2208−We get the list of paths (paired with their lobe) in the revision
2209−referred to by the given number and we keep only those paths which begin
2210−with `pax`. Converting to a map, we now have a map from the subpaths at
2211−the given path to the hash of their data. This is simple and efficient
2212−to calculate and compare to later revisions. This allows us to easily
2213−tell if a node or its children have changed.
2214−
2215−Finally, we will describe `++make-nako:ze`.
2216−
2217−```hoon
2218− ++ make-nako :: gack a through b
2219− |= [a=aeon b=aeon]
2220− ^- [(map aeon tako) aeon (set yaki) (set blob)]
2221− :_ :- b
2222− =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
2223− %+ reachable-between-takos
2224− (~(get by hit) a) :: if a not found, a=0
2225− (aeon-to-tako b)
2226− ^- (map aeon tako)
2227− %- mo %+ skim (~(tap by hit) ~)
2228− |= [p=aeon *]
2229− &((gth p a) (lte p b))
2230−```
2231−
2232−We need to produce four things -- the numbers of the new commits, the
2233−number of the latest commit, the new commits themselves, and the new
2234−data itself.
2235−
2236−The first is fairly easy to produce. We simply go over our map of
2237−numbered commits and produce all those numbered greater than `a` and not
2238−greater than `b`.
2239−
2240−The second is even easier to produce -- `b` is clearly our most recent
2241−commit.
2242−
2243−The third and fourth are slightly more interesting, though not too
2244−terribly difficult. First, we call `++reachable-between-takos`.
2245−
2246−```hoon
2247− ++ reachable-between-takos
2248− |= [a=(unit tako) b=tako] :: pack a through b
2249− ^- [(set tako) (set lobe)]
2250− =+ ^= sar
2251− ?~ a ~
2252− (reachable-takos r:(tako-to-yaki u.a))
2253− =+ yak=`yaki`(tako-to-yaki b)
2254− %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
2255− |- ^- (set tako) :: walk onto sar
2256− ?: (~(has in sar) r.yak)
2257− ~
2258− =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
2259− %- ~(uni in ber)
2260− ^- (set tako)
2261− %+ roll p.yak
2262− |= [yek=tako bar=(set tako)]
2263− ^- (set tako)
2264− ?: (~(has in bar) yek) :: save some time
2265− bar
2266− %- ~(uni in bar)
2267− ^$(yak (tako-to-yaki yek))
2268−```
2269−
2270−We take a possible starting commit and a definite ending commit, and we
2271−produce the set of commits and the set of data between them.
2272−
2273−We let `sar` be the set of commits reachable from `a`. If `a` is null,
2274−then obviously no commits are reachable. Otherwise, we call
2275−`++reachable-takos` to calculate this.
2276−
2277−```hoon
2278− ++ reachable-takos :: reachable
2279− |= p=tako :: XX slow
2280− ^- (set tako)
2281− =+ y=(tako-to-yaki p)
2282− =+ t=(~(put in _(set tako)) p)
2283− %+ roll p.y
2284− |= [q=tako s=_t]
2285− ?: (~(has in s) q) :: already done
2286− s :: hence skip
2287− (~(uni in s) ^$(p q)) :: otherwise traverse
2288−```
2289−
2290−We very simply produce the set of the given tako plus its parents,
2291−recursively.
2292−
2293−Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
2294−the ending commit. With this, we create a set that is the union of `sar`
2295−and all takos reachable from `b`.
2296−
2297−We pass `sar` into `++new-lobes` to get all the lobes referenced by any
2298−tako referenced by `a`. The result is passed into `++new-lobes-takos` to
2299−do the same, but not recomputing those in already calculated last
2300−sentence. This produces the sets of takos and lobes we need.
2301−
2302−```hoon
2303− ++ new-lobes :: object hash set
2304− |= [b=(set lobe) a=(set tako)] :: that aren't in b
2305− ^- (set lobe)
2306− %+ roll (~(tap in a) ~)
2307− |= [tak=tako bar=(set lobe)]
2308− ^- (set lobe)
2309− =+ yak=(tako-to-yaki tak)
2310− %+ roll (~(tap by q.yak) ~)
2311− |= [[path lob=lobe] far=_bar]
2312− ^- (set lobe)
2313− ?~ (~(has in b) lob) :: don't need
2314− far
2315− =+ gar=(lobe-to-blob lob)
2316− ?- -.gar
2317− %direct (~(put in far) lob)
2318− %delta (~(put in $(lob q.gar)) lob)
2319− %indirect (~(put in $(lob s.gar)) lob)
2320− ==
2321−```
2322−
2323−Here, we're creating a set of lobes referenced in a commit in `a`. We
2324−start out with `b` as the initial set of lobes, so we don't need to
2325−recompute any of the lobes referenced in there.
2326−
2327−The algorithm is pretty simple, so we won't bore you with the details.
2328−We simply traverse every commit in `a`, looking at every blob referenced
2329−there, and, if it's not already in `b`, we add it to `b`. In the case of
2330−a direct blob, we're done. For a delta or an indirect blob, we
2331−recursively add every blob referenced within the blob.
2332−
2333−```hoon
2334− ++ new-lobes-takos :: garg & repack
2335− |= [b=(set lobe) a=(set tako)]
2336− ^- [(set tako) (set lobe)]
2337− [a (new-lobes b a)]
2338−```
2339−
2340−Here, we just update the set of lobes we're given with the commits we're
2341−given and produce both sets.
2342−
2343−This concludes our discussion of a local subscription.
2344−
2345−## Lifecycle of a Foreign Read or Subscription
2346−
2347−Foreign reads and subscriptions are handled in much the same way as
2348−local ones. The interface is the same -- a vane or app sends a `%warp`
2349−kiss with the request. The difference is simply that the `sock` refers
2350−to the foreign ship.
2351−
2352−Thus, we start in the same place -- in `++call`, handling `%warp`.
2353−However, since the two side of the `sock` are different, we follow a
2354−different path.
2355−
2356−```hoon
2357− =+ wex=(do now p.q.hic p.q.q.hic ruf)
2358− =+ ^= woo
2359− ?~ q.q.q.hic
2360− abet:(ease:wex hen)
2361− abet:(eave:wex hen u.q.q.q.hic)
2362− [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
2363−```
2364−
2365−If we compare this to how the local case was handled, we see that it's
2366−not all that different. We use `++do` rather than `++un` and `++de` to
2367−set up the core for the foreign ship. This gives us a `++de` core, so we
2368−either cancel or begin the request by calling `++ease` or `++eave`,
2369−exactly as in the local case. In either case, we call `++abet:de` to
2370−resolve our various types of output into actual moves, as described in
2371−the local case. Finally, we call `++posh` to update our raft, putting
2372−the modified rung into the raft.
2373−
2374−We'll first trace through `++do`.
2375−
2376−```hoon
2377− ++ do
2378− |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
2379− =+ ^= rug ^- rung
2380− =+ rug=(~(get by hoy.ruf) him)
2381− ?^(rug u.rug *rung)
2382− =+ ^= red ^- rede
2383− =+ yit=(~(get by rus.rug) syd)
2384− ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
2385− ((de now ~ ~) [who him] syd red ran.ruf)
2386−```
2387−
2388−If we already have a rung for this foreign ship, then we use that.
2389−Otherwise, we create a new blank one. If we already have a rede in this
2390−rung, then we use that, otherwise we create a blank one. An important
2391−point to note here is that we let `ref` in the rede be `[~ *rind]`.
2392−Recall, for domestic desks `ref` is null. We use this to distinguish
2393−between foreign and domestic desks in `++de`.
2394−
2395−With this information, we create a `++de` core as usual.
2396−
2397−Although we've already covered `++ease` and `++eave`, we'll go through
2398−them quickly again, highlighting the case of foreign request.
2399−
2400−```hoon
2401− ++ ease :: release request
2402− |= hen=duct
2403− ^+ +>
2404− ?~ ref +>
2405− =+ rov=(~(got by qyx) hen)
2406− =. qyx (~(del by qyx) hen)
2407− (mabe rov (cury best hen))
2408− =. qyx (~(del by qyx) hen)
2409− |- ^+ +>+.$
2410− =+ nux=(~(get by fod.u.ref) hen)
2411− ?~ nux +>+.$
2412− %= +>+.$
2413− say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
2414− fod.u.ref (~(del by fod.u.ref) hen)
2415− bom.u.ref (~(del by bom.u.ref) u.nux)
2416− ==
2417−```
2418−
2419−Here, we still remove the duct from our cult (we maintain a cult even
2420−for foreign desks), but we also need to tell the foreign desk to cancel
2421−our subscription. We do this by sending a request (by appending to
2422−`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
2423−the foreign ship to cancel the subscription. Since we don't anymore
2424−expect a response on this duct, we remove it from `fod` and `bom`, which
2425−are the maps between ducts, raves, and request sequence numbers.
2426−Basically, we remove every trace of the subscription from our request
2427−manager.
2428−
2429−In the case of `++eave`, where we're creating a new request, everything
2430−is exactly identical to the case of the local request except `++duce`.
2431−We said that `++duce` simply puts the request into our cult. This is
2432−true for a domestic request, but distinctly untrue for foreign requests.
2433−
2434−```hoon
2435− ++ duce :: produce request
2436− |= [hen=duct rov=rove]
2437− ^+ +>
2438− =. qyx (~(put by qyx) hen rov)
2439− ?~ ref +>.$
2440− |- ^+ +>+.$ :: XX why?
2441− =+ rav=(reve rov)
2442− =+ ^= vaw ^- rave
2443− ?. ?=([%& %v *] rav) rav
2444− [%| [%ud let.dom] `case`q.p.rav r.p.rav]
2445− =+ inx=nix.u.ref
2446− %= +>+.$
2447− say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
2448− nix.u.ref +(nix.u.ref)
2449− bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
2450− fod.u.ref (~(put by fod.u.ref) hen inx)
2451− ==
2452−```
2453−
2454−If we have a request manager (i.e. this is a foreign desk), then we do
2455−the approximate inverse of `++ease`. We create a rave out of the given
2456−request and send it off to the foreign desk by putting it in `say`. Note
2457−that the rave is created to request the information starting at the next
2458−revision number. Since this is a new request, we put it into `fod` and
2459−`bom` to associate the request with its duct and its sequence number.
2460−Since we're using another sequence number, we must increment `nix`,
2461−which represents the next available sequence number.
2462−
2463−And that's really it for this side of the request. Requesting foreign
2464−information isn't that hard. Let's see what it looks like on the other
2465−side. When we get a request from another ship for information on our
2466−ship, that comes to us in the form of a `%wart` from ames.
2467−
2468−We handle a `%wart` in `++call`, right next to where we handle the
2469−`%warp` case.
2470−
2471−```hoon
2472− %wart
2473− ?> ?=(%re q.q.hic)
2474− =+ ryf=((hard riff) s.q.hic)
2475− :_ ..^$
2476− :~ :- hen
2477− :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
2478− %c
2479− [%warp [p.p.q.hic p.p.q.hic] ryf]
2480− ==
2481−```
2482−
2483−Every request we receive should be of type `riff`, so we coerce it into
2484−that type. We just convert this into a new `%warp` kiss that we pass to
2485−ourself. This gets handled like normal, as a local request. When the
2486−request produces a value, it does so like normal as a `%writ`, which is
2487−returned to `++take` along the path we just sent it on.
2488−
2489−```hoon
2490− %writ
2491− ?> ?=([@ @ *] tea)
2492− =+ our=(need (slaw %p i.tea))
2493− =+ him=(need (slaw %p i.t.tea))
2494− :_ ..^$
2495− :~ :- hen
2496− [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
2497− ==
2498−```
2499−
2500−Since we encoded the ship we need to respond to in the path, we can just
2501−pass our `%want` back to ames, so that we tell the requesting ship about
2502−the new data.
2503−
2504−This comes back to the original ship as a `%waft` from ames, which comes
2505−into `++take`, right next to where we handled `%writ`.
2506−
2507−```hoon
2508− %waft
2509− ?> ?=([@ @ ~] tea)
2510− =+ syd=(need (slaw %tas i.tea))
2511− =+ inx=(need (slaw %ud i.t.tea))
2512− =+ ^= zat
2513− =< wake
2514− (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
2515− =^ mos ruf
2516− =+ zot=abet.zat
2517− [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
2518− [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
2519−```
2520−
2521−This gets the desk and sequence number from the path the request was
2522−sent over. This determines exactly which request is being responded to.
2523−We call `++knit:de` to apply the changes to our local desk, and we call
2524−`++wake` to update our subscribers. Then we call `++abet:de` and
2525−`++posh` as normal (like in `++eave`).
2526−
2527−We'll examine `++knit` and `++wake`, in that order.
2528−
2529−```hoon
2530− ++ knit :: external change
2531− |= [inx=@ud rot=riot]
2532− ^+ +>
2533− ?> ?=(^ ref)
2534− |- ^+ +>+.$
2535− =+ ruv=(~(get by bom.u.ref) inx)
2536− ?~ ruv +>+.$
2537− => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
2538− %_ .
2539− bom.u.ref (~(del by bom.u.ref) inx)
2540− fod.u.ref (~(del by fod.u.ref) p.u.ruv)
2541− ==
2542− ?~ rot
2543− =+ rav=`rave`q.u.ruv
2544− %= +>+.$
2545− lim
2546− ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
2547− ::
2548− haw.u.ref
2549− ?. ?=(& -.rav) haw.u.ref
2550− (~(put by haw.u.ref) p.rav ~)
2551− ==
2552− ?< ?=(%v p.p.u.rot)
2553− =. haw.u.ref
2554− (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
2555− ?. ?=(%w p.p.u.rot) +>+.$
2556− |- ^+ +>+.^$
2557− =+ nez=[%w [%ud let.dom] ~]
2558− =+ nex=(~(get by haw.u.ref) nez)
2559− ?~ nex +>+.^$
2560− ?~ u.nex +>+.^$ :: should never happen
2561− =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
2562− ?>(?=(^ ref.roo) roo)
2563− %= $
2564− haw.u.ref (~(del by haw.u.ref) nez)
2565− ==
2566−```
2567−
2568−This is kind of a long [gate](/docs/glossary/gate/), but don't worry, it's not bad at all.
2569−
2570−First, we assert that we're not a domestic desk. That wouldn't make any
2571−sense at all.
2572−
2573−Since we have the sequence number of the request, we can get the duct
2574−and rave from `bom` in our request manager. If we didn't actually
2575−request this data (or the request was canceled before we got it), then
2576−we do nothing.
2577−
2578−Else, we remove the request from `bom` and `fod` unless this was a
2579−subscription request and we didn't receive a null riot (which would
2580−indicate the last message on the subscription).
2581−
2582−Now, if we received a null riot, then if this was a subscription request
2583−by date, then we update `lim` in our request manager (representing the
2584−latest time at which we have complete information for this desk) to the
2585−date that was requested. If this was a single read request, then we put
2586−the result in our simple cache `haw` to make future requests faster.
2587−Then we're done.
2588−
2589−If we received actual data, then we put it into our cache `haw`. Unless
2590−it's a `%w` request, we're done.
2591−
2592−If it is a `%w` request, then we try to get the `%w` at our current head
2593−from the cache. In general, that should be the thing we just put in a
2594−moment ago, but that is not guaranteed. The most common case where this
2595−is different is when we receive desk updates out of order. At any rate,
2596−since we now have new information, we need to apply it to our local copy
2597−of the desk. We do so in `++edis`, and then we remove the stuff we just
2598−applied from the cache, since it's not really a true "single read", like
2599−what should really be in the cache.
2600−
2601−```hoon
2602− ++ edis :: apply subscription
2603− |= nak=nako
2604− ^+ +>
2605− %= +>
2606− hit.dom (~(uni by hit.dom) gar.nak)
2607− let.dom let.nak
2608− lat.ran %+ roll (~(tap in bar.nak) ~)
2609− =< .(yeb lat.ran)
2610− |= [sar=blob yeb=(map lobe blob)]
2611− =+ zax=(blob-to-lobe sar)
2612− %+ ~(put by yeb) zax sar
2613− hut.ran %+ roll (~(tap in lar.nak) ~)
2614− =< .(yeb hut.ran)
2615− |= [sar=yaki yeb=(map tako yaki)]
2616− %+ ~(put by yeb) r.sar sar
2617− ==
2618−```
2619−
2620−This shows, of course, exactly why nako is defined the way it is. To
2621−become completely up to date with the foreign desk, we need to merge
2622−`hit` with the foreign one so that we have all the revision numbers. We
2623−update `let` so that we know which revision is the head.
2624−
2625−We merge the new blobs in `lat`, keying them by their hash, which we get
2626−from a call to `++blob-to-lobe`. Recall that the hash is stored in the
2627−actual blob itself. We do the same thing to the new yakis, putting them
2628−in `hut`, keyed by their hash.
2629−
2630−Now, our local dome should be exactly the same as the foreign one.
2631−
2632−This concludes our discussion of `++knit`. Now the changes have been
2633−applied to our local copy of the desk, and we just need to update our
2634−subscribers. We do so in `++wake:de`.
2635−
2636−```hoon
2637− ++ wake :: update subscribers
2638− ^+ .
2639− =+ xiq=(~(tap by qyx) ~)
2640− =| xaq=(list ,[p=duct q=rove])
2641− |- ^+ ..wake
2642− ?~ xiq
2643− ..wake(qyx (~(gas by *cult) xaq))
2644− ?- -.q.i.xiq
2645− &
2646− =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
2647− ?^ cas
2648− %= $
2649− xiq t.xiq
2650− ..wake ?~ u.cas (blub p.i.xiq)
2651− (blab p.i.xiq p.q.i.xiq u.u.cas)
2652− ==
2653− =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
2654− ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
2655− $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
2656− ::
2657− |
2658− =+ mot=`moot`p.q.i.xiq
2659− =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
2660− ?~ nab
2661− $(xiq t.xiq, xaq [i.xiq xaq])
2662− =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
2663− ?~ huy
2664− =+ ptr=[%ud +(let.dom)]
2665− %= $
2666− xiq t.xiq
2667− xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
2668− ..wake =+ ^= ear
2669− (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
2670− ?: =(s.p.q.i.xiq ear) ..wake
2671− =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
2672− (bleb p.i.xiq let.dom fud)
2673− ==
2674− %= $
2675− xiq t.xiq
2676− ..wake =- (blub:- p.i.xiq)
2677− =+ ^= ear
2678− (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
2679− ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
2680− =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
2681− (bleb p.i.xiq +(u.nab) fud)
2682− ==
2683− ==
2684− --
2685−```
2686−
2687−This is even longer than `++knit`, but it's pretty similar to `++eave`.
2688−We loop through each of our subscribers `xiq`, processing each in turn.
2689−When we're done, we just put the remaining subscribers back in our
2690−subscriber list.
2691−
2692−If the subscriber is a single read, then, if this is a foreign desk
2693−(note that `++wake` is called from other arms, and not only on foreign
2694−desks). Obviously, if we find an identical request there, then we can
2695−produce the result immediately. Referential transparency for the win. We
2696−produce the result with a call to `++blab`. If this is a foreign desk
2697−but the result is not in the cache, then we produce `++blub` (canceled
2698−subscription with no data) for reasons entirely opaque to me. Seriously,
2699−it seems like we should wait until we get an actual response to the
2700−request. If someone figures out why this is, let me know. At any rate,
2701−it seems to work.
2702−
2703−If this is a domestic desk, then we check to see if the case exists yet.
2704−If it doesn't, then we simply move on to the next subscriber, consing
2705−this one onto `xaq` so that we can check again the next time around. If
2706−it does exist, then we call `++balk` to fulfill the request and produce
2707−it.
2708−
2709−`++balk` is very simple, so we'll describe it here before we get to the
2710−subscription case.
2711−
2712−```hoon
2713− ++ balk :: read and send
2714− |= [hen=duct oan=@ud mun=mood]
2715− ^+ +>
2716− =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
2717− ?~ vid (blub hen) (blab hen mun u.vid)
2718−```
2719−
2720−We call `++read-at-aeon` on the given request and aeon. If you recall,
2721−this processes a `mood` at a particular aeon and produces the result, if
2722−there is one. If there is data at the requested location, then we
2723−produce it with `++blab`. Else, we call `++blub` to notify the
2724−subscriber that no data can ever come over this subscriptioin since it
2725−is now impossible for there to ever be data for the given request.
2726−Because referential transparency.
2727−
2728−At any rate, back to `++wake`. If the given rave is a subscription
2729−request, then we proceed similarly to how we do in `++eave`. We first
2730−try to get the aeon referred to by the starting case. If it doesn't
2731−exist yet, then we can't do anything interesting with this subscription,
2732−so we move on to the next one.
2733−
2734−Otherwise, we try to get the aeon referred to by the ending case. If it
2735−doesn't exist yet, then we produce all the information we can. We call
2736−`++lobes-at-path` at the given aeon and path to see if the requested
2737−path has actually changed. If it hasn't, then we don't produce anything;
2738−else, we produce the correct nako by calling `++bleb` on the result of
2739−`++make-nako`, as in `++eave`. At any rate, we move on to the next
2740−subscription, putting back into our cult the current subscription with a
2741−new start case of the next aeon after the present.
2742−
2743−If the aeon referred to by the ending case does exist, then we drop this
2744−subscriber from our cult and satisfy its request immediately. This is
2745−the same as before -- we check to see if the data at the path has
2746−actually changed, producing it if it has; else, we call `++blub` since
2747−no more data can be produced over this subscription.
2748−
2749−This concludes our discussion of foreign requests.
64+How foreign reads and subscriptions work.
arvo/clay/data-types.mdnew file+760
@@ -0,0 +1,760 @@
1++++
2+title = "Data Types"
3+weight = 4
4+template = "doc.html"
5++++
6+
7+This section will be reference documentation for the data types used by our
8+filesystem. Parts of it may be inaccurate as of March 2021. As a general guide,
9+we recommend reading and attempting to understand the data structures used in
10+any Hoon code before you try to read the code itself. Although complete
11+understanding of the data structures is impossible without seeing them used in
12+the code, an 80% understanding greatly clarifies the code. As another general
13+guide, when reading Hoon, it rarely pays off to understand every line of code
14+when it appears. Try to get the gist of it, and then move on. The next time you
15+come back to it, it'll likely make a lot more sense.
16+
17+### Data Models
18+
19+As you're reading through this section, remember you can always come
20+back to this when you run into these types later on. You're not going to
21+remember everything the first time through, but it is worth reading, or
22+at least skimming, this so that you get a rough idea of how our state is
23+organized.
24+
25+The types that are certainly worth reading are `++raft`, `++room`,
26+`++dome:clay`, `++ankh:clay`, `++rung:clay`, `++rang:clay`, `++blob:clay`, `++yaki:clay`, and `++nori:clay`
27+(possibly in that order). All in all, though, this section isn't too
28+long, so many readers may wish to quickly read through all of it. If you
29+get bored, though, just skip to the next section. You can always come
30+back when you need to.
31+
32+### `++raft`, formal state
33+
34+```hoon
35+ ++ raft :: filesystem
36+ $: fat=(map ship room) :: domestic
37+ hoy=(map ship rung) :: foreign
38+ ran=rang :: hashes
39+ == ::
40+```
41+
42+This is the state of our vane. Anything that must be remembered between
43+calls to clay is stored in this state.
44+
45+`fat` is the set of domestic servers. This stores all the information
46+that is specfic to a particular ship on this pier. The keys to this map
47+are the ships on the current pier. all the information that is specific
48+to a particular foreign ship. The keys to this map are all the ships
49+whose filesystems we have attempted to access through clay.
50+
51+`ran` is the store of all commits and deltas, keyed by hash. The is
52+where all the "real" data we know is stored; the rest is "just
53+bookkeeping".
54+
55+#### `++room`, filesystem per domestic ship
56+
57+```hoon
58+ ++ room :: fs per ship
59+ $: hun=duct :: terminal duct
60+ hez=(unit duct) :: sync duch
61+ dos=(map desk dojo) :: native desk
62+ == ::
63+```
64+
65+This is the representation of the filesystem of a ship on our pier.
66+
67+`hun` is the duct we use to send messages to dill to display
68+notifications of filesystem changes. Only `%note` gifts should be
69+produced along this duct. This is set by the `%init` kiss.
70+
71+`hez`, if present, is the duct we use to send sync messages to unix so
72+that they end up in the pier unix directory. Only `%ergo` gifts should
73+be producd along this duct. This is set by `%into` and `%invo` kisses.
74+
75+`dos` is a well-known operating system released in 1981. It is also the
76+set of desks on this ship, mapped to their data.
77+
78+#### `++desk`, filesystem branch
79+
80+```hoon
81+ ++ desk ,@tas :: ship desk case spur
82+```
83+
84+This is the name of a branch of the filesystem. The default desks are
85+"arvo", "main", and "try". More may be created by simply referencing
86+them. Desks have independent histories and states, and they may be
87+merged into each other.
88+
89+### `++dojo`, domestic desk state
90+
91+```hoon
92+ ++ dojo ,[p=cult q=dome] :: domestic desk state
93+```
94+
95+This is the all the data that is specific to a particular desk on a
96+domestic ship. `p` is the set of subscribers to this desk and `q` is the
97+data in the desk.
98+
99+#### `++cult`, subscriptions
100+
101+```hoon
102+ ++ cult (map duct rave) :: subscriptions
103+```
104+
105+This is the set of subscriptions to a particular desk. The keys are the
106+ducts from where the subscriptions requests came. The results will be
107+produced along these ducts. The values are a description of the
108+requested information.
109+
110+#### `++rave:clay`, general subscription request
111+
112+```hoon
113+ ++ rave :: general request
114+ $% [& p=mood] :: single request
115+ [| p=moat] :: change range
116+ == ::
117+```
118+
119+This represents a subscription request for a desk. The request can be
120+for either a single item in the desk or else for a range of changes on
121+the desk.
122+
123+### `++rove`, stored general subscription request
124+
125+```hoon
126+ ++ rove (each mood moot) :: stored request
127+```
128+
129+When we store a request, we store subscriptions with a little extra
130+information so that we can determine whether new versions actually
131+affect the path we're subscribed to.
132+
133+#### `++mood:clay`, single subscription request
134+
135+```hoon
136+ ++ mood ,[p=care q=case r=path] :: request in desk
137+```
138+
139+This represents a request for the state of the desk at a particular
140+commit, specfied by `q`. `p` specifies what kind of information is
141+desired, and `r` specifies the path we are requesting.
142+
143+#### `++moat:clay`, range subscription request
144+
145+```hoon
146+ ++ moat ,[p=case q=case r=path] :: change range
147+```
148+
149+This represents a request for all changes between `p` and `q` on path
150+`r`. You will be notified when a change is made to the node referenced
151+by the path or to any of its children.
152+
153+### `++moot`, stored range subscription request
154+
155+```hoon
156+ ++ moot ,[p=case q=case r=path s=(map path lobe)] ::
157+```
158+
159+This is just a `++moat:clay` plus a map of paths to lobes. This map
160+represents the data at the node referenced by the path at case `p`, if
161+we've gotten to that case (else null). We only send a notification along
162+the subscription if the data at a new revision is different than it was.
163+
164+### `++care:clay`, clay submode
165+
166+```hoon
167+ ++ care ?(%u %v %w %x %y %z) :: clay submode
168+```
169+
170+This specifies what type of information is requested in a subscription
171+or a scry.
172+
173+`%u` requests the `++rang:clay` at the current moment. Because this
174+information is not stored for any moment other than the present, we
175+crash if the `++case:clay` is not a `%da` for now.
176+
177+`%v` requests the `++dome:clay` at the specified commit.
178+
179+`%w` requests the revsion number of the desk.
180+
181+`%x` requests the file at a specified path at the specified commit. If
182+there is no node at that path or if the node has no contents (that is,
183+if `q:ankh` is null), then this produces null.
184+
185+`%y` requests a `++arch` of the specfied commit at the specified path.
186+
187+`%z` requests the `++ankh` of the specified commit at the specfied path.
188+
189+### `++arch`, shallow filesystem node
190+
191+```hoon
192+ ++ arch ,[p=@uvI q=(unit ,@uvI) r=(map ,@ta ,~)] :: fundamental node
193+```
194+
195+This is analogous to `++ankh:clay` except that the we have neither our
196+contents nor the ankhs of our children. The other fields are exactly the
197+same, so `p` is a hash of the associated ankh, `u.q`, if it exists, is a
198+hash of the contents of this node, and the keys of `r` are the names of
199+our children. `r` is a map to null rather than a set so that the
200+ordering of the map will be equivalent to that of `r:ankh`, allowing
201+efficient conversion.
202+
203+#### `++case:clay`, specifying a commit
204+
205+```hoon
206+ ++ case :: ship desk case spur
207+ $% [%da p=@da] :: date
208+ [%tas p=@tas] :: label
209+ [%ud p=@ud] :: number
210+ == ::
211+```
212+
213+A commit can be referred to in three ways: `%da` refers to the commit
214+that was at the head on date `p`, `%tas` refers to the commit labeled
215+`p`, and `%ud` refers to the commit numbered `p`. Note that since these
216+all can be reduced down to a `%ud`, only numbered commits may be
217+referenced with a `++case:clay`.
218+
219+#### `++dome:clay`, desk data
220+
221+```hoon
222+ ++ dome :: project state
223+ $: ang=agon :: pedigree
224+ ank=ankh :: state
225+ let=@ud :: top id
226+ hit=(map ,@ud tako) :: changes by id
227+ lab=(map ,@tas ,@ud) :: labels
228+ == ::
229+```
230+
231+This is the data that is actually stored in a desk.
232+
233+`ang` is unused and should be removed.
234+
235+`ank` is the current state of the desk. Thus, it is the state of the
236+filesystem at revison `let`. The head of a desk is always a numbered
237+commit.
238+
239+`let` is the number of the most recently numbered commit. This is also
240+the total number of numbered commits.
241+
242+`hit` is a map of numerical ids to hashes of commits. These hashes are
243+mapped into their associated commits in `hut:rang:clay`. In general, the keys
244+of this map are exactly the numbers from 1 to `let`, with no gaps. Of
245+course, when there are no numbered commits, `let` is 0, so `hit` is
246+null. Additionally, each of the commits is an ancestor of every commit
247+numbered greater than this one. Thus, each is a descendant of every
248+commit numbered less than this one. Since it is true that the date in
249+each commit (`t:yaki`) is no earlier than that of each of its parents,
250+the numbered commits are totally ordered in the same way by both
251+pedigree and date. Of course, not every commit is numbered. If that
252+sounds too complicated to you, don't worry about it. It basically
253+behaves exactly as you would expect.
254+
255+`lab` is a map of textual labels to numbered commits. Note that labels
256+can only be applied to numbered commits. Labels must be unique across a
257+desk.
258+
259+#### `++ankh`, filesystem node
260+
261+```hoon
262+ ++ ankh :: fs node (new)
263+ $: p=cash :: recursive hash
264+ q=(unit ,[p=cash q=*]) :: file
265+ r=(map ,@ta ankh) :: folders
266+ == ::
267+```
268+
269+This is a single node in the filesystem. This may be file or a directory
270+or both. In earth filesystems, a node is a file xor a directory. On
271+mars, we're inclusive, so a node is a file ior a directory.
272+
273+`p` is a recursive hash that depends on the contents of the this file or
274+directory and on any children.
275+
276+`q` is the contents of this file, if any. `p.q` is a hash of the
277+contents while `q.q` is the data itself.
278+
279+`r` is the set of children of this node. In the case of a pure file,
280+this is empty. The keys are the names of the children and the values
281+are, recursively, the nodes themselves.
282+
283+#### `++cash`, ankh hash
284+
285+```hoon
286+ ++ cash ,@uvH :: ankh hash
287+```
288+
289+This is a 128-bit hash of an ankh. These are mostly stored within ankhs
290+themselves, and they are used to check for changes in possibly-deep
291+hierarchies.
292+
293+#### `++rung`, filesystem per neighbor ship
294+
295+```hoon
296+ ++ rung $: rus=(map desk rede) :: neighbor desks
297+ == ::
298+```
299+
300+This is the filesystem of a neighbor ship. The keys to this map are all
301+the desks we know about on their ship.
302+
303+#### `++rede`, desk state
304+
305+```hoon
306+ ++ rede :: universal project
307+ $: lim=@da :: complete to
308+ qyx=cult :: subscribers
309+ ref=(unit rind) :: outgoing requests
310+ dom=dome :: revision state
311+ == ::
312+```
313+
314+This is our knowledge of the state of a desk, either foreign or
315+domestic.
316+
317+`lim` is the date of the last full update. We only respond to requests
318+for stuff before this time.
319+
320+`qyx` is the list of subscribers to this desk. For domestic desks, this
321+is simply `p:dojo`, all subscribers to the desk, while in foreign desks
322+this is all the subscribers from our ship to the foreign desk.
323+
324+`ref` is the request manager for the desk. For domestic desks, this is
325+null since we handle requests ourselves.
326+
327+`dom` is the actual data in the desk.
328+
329+#### `++rind`, request manager
330+
331+```hoon
332+ ++ rind :: request manager
333+ $: nix=@ud :: request index
334+ bom=(map ,@ud ,[p=duct q=rave]) :: outstanding
335+ fod=(map duct ,@ud) :: current requests
336+ haw=(map mood (unit)) :: simple cache
337+ == ::
338+```
339+
340+This is the request manager for a foreign desk.
341+
342+`nix` is one more than the index of the most recent request. Thus, it is
343+the next available request number.
344+
345+`bom` is the set of outstanding requests. The keys of this map are some
346+subset of the numbers between 0 and one less than `nix`. The members of
347+the map are exactly those requests that have not yet been fully
348+satisfied.
349+
350+`fod` is the same set as `bom`, but from a different perspective. In
351+particular, the values of `fod` are the same as the values of `bom`, and
352+the `p` out of the values of `bom` are the same as the keys of `fod`.
353+Thus, we can map ducts to their associated request number and `++rave:clay`,
354+and we can map numbers to their associated duct and `++rave:clay`.
355+
356+`haw` is a map from simple requests to their values. This acts as a
357+cache for requests that have already been made. Thus, the second request
358+for a particular `++mood:clay` is nearly instantaneous.
359+
360+#### `++rang:clay`, data store
361+
362+```hoon
363+ ++ rang $: hut=(map tako yaki) ::
364+ lat=(map lobe blob) ::
365+ == ::
366+```
367+
368+This is a set of data keyed by hash. Thus, this is where the "real" data
369+is stored, but it is only meaningful if we know the hash of what we're
370+looking for.
371+
372+`hut` is a map from hashes to commits. We often get the hashes from
373+`hit:dome:clay`, which keys them by logical id. Not every commit has an id.
374+
375+`lat` is a map from hashes to the actual data. We often get the hashes
376+from a `++yaki`, a commit, which references this map to get the data.
377+There is no `++blob:clay` in any `++yaki:clay`. They are only accessible through
378+this map.
379+
380+#### `++tako:clay`, commit reference
381+
382+```hoon
383+ ++ tako ,@ :: yaki ref
384+```
385+
386+This is a hash of a `++yaki:clay`, a commit. These are most notably used as
387+the keys in `hut:rang:clay`, where they are associated with the actual
388+`++yaki:clay`, and as the values in `hit:dome:clay`, where sequential ids are
389+associated with these.
390+
391+#### `++yaki:clay`, commit
392+
393+```hoon
394+ ++ yaki ,[p=(list tako) q=(map path lobe) r=tako t=@da] :: commit
395+```
396+
397+This is a single commit.
398+
399+`p` is a list of the hashes of the parents of this commit. In most
400+cases, this will be a single commit, but in a merge there may be more
401+parents. In theory, there may be an arbitrary number of parents, but in
402+practice merges have exactly two parents. This may change in the future.
403+For commit 1, there is no parent.
404+
405+`q` is a map of the paths on a desk to the data at that location. If you
406+understand what a `++lobe:clay` and a `++blob:clay` is, then the type signature
407+here tells the whole story.
408+
409+`r` is the hash associated with this commit.
410+
411+`t` is the date at which this commit was made.
412+
413+#### `++lobe:clay`, data reference
414+
415+```hoon
416+ ++ lobe ,@ :: blob ref
417+```
418+
419+This is a hash of a `++blob:clay`. These are most notably used in `lat:rang:clay`,
420+where they are associated with the actual `++blob:clay`, and as the values in
421+`q:yaki:clay`, where paths are associated with their data in a commit.
422+
423+#### `++blob:clay`, data
424+
425+```hoon
426+ ++ blob $% [%delta p=lobe q=lobe r=udon] :: delta on q
427+ [%direct p=lobe q=* r=umph] ::
428+ [%indirect p=lobe q=* r=udon s=lobe] ::
429+ == ::
430+```
431+
432+This is a node of data. In every case, `p` is the hash of the blob.
433+
434+`%delta` is the case where we define the data by a delta on other data.
435+In practice, the other data is always the previous commit, but nothing
436+depends on this. `q` is the hash of the parent blob, and `r` is the
437+delta.
438+
439+`%direct` is the case where we simply have the data directly. `q` is the
440+data itself, and `r` is any preprocessing instructions. These almost
441+always come from the creation of a file.
442+
443+`%indirect` is both of the preceding cases at once. `q` is the direct
444+data, `r` is the delta, and `s` is the parent blob. It should always be
445+the case that applying `r` to `s` gives the same data as `q` directly
446+(with the prepreprocessor instructions in `p.r`). This exists purely for
447+performance reasons. This is unused, at the moment, but in general these
448+should be created when there are a long line of changes so that we do
449+not have to traverse the delta chain back to the creation of the file.
450+
451+#### `++udon`, abstract delta
452+
453+```hoon
454+ ++ udon :: abstract delta
455+ $: p=umph :: preprocessor
456+ $= q :: patch
457+ $% [%a p=* q=*] :: trivial replace
458+ [%b p=udal] :: atomic indel
459+ [%c p=(urge)] :: list indel
460+ [%d p=upas q=upas] :: tree edit
461+ == ::
462+ == ::
463+```
464+
465+This is an abstract change to a file. This is a superset of what would
466+normally be called diffs. Diffs usually refer to changes in lines of
467+text while we have the ability to do more interesting deltas on
468+arbitrary data structures.
469+
470+`p` is any preprocessor instructions.
471+
472+`%a` refers to the trival delta of a complete replace of old data with
473+new data.
474+
475+`%b` refers to changes in an opaque atom on the block level. This has
476+very limited usefulness, and is not used at the moment.
477+
478+`%c` refers to changes in a list of data. This is often lines of text,
479+which is your classic diff. We, however, will work on any list of data.
480+
481+`%d` refers to changes in a tree of data. This is general enough to
482+describe changes to any hoon [noun](/docs/glossary/noun/), but often more special-purpose delta
483+should be created for different content types. This is not used at the
484+moment, and may in fact be unimplemented.
485+
486+#### `++urge`, list change
487+
488+```hoon
489+ ++ urge |*(a=_,* (list (unce a))) :: list change
490+```
491+
492+This is a parametrized type for list changes. For example, `(urge ,@t)`
493+is a list change for lines of text.
494+
495+#### `++unce`, change part of a list.
496+
497+```hoon
498+ ++ unce |* a=_,* :: change part
499+ $% [%& p=@ud] :: skip[copy]
500+ [%| p=(list a) q=(list a)] :: p -> q[chunk]
501+ == ::
502+```
503+
504+This is a single change in a list of elements of type `a`. For example,
505+`(unce ,@t)` is a single change in a lines of text.
506+
507+`%&` means the next `p` lines are unchanged.
508+
509+`%|` means the lines `p` have changed to `q`.
510+
511+#### `++umph`, preprocessing information
512+
513+```hoon
514+ ++ umph :: change filter
515+ $| $? %a :: no filter
516+ %b :: jamfile
517+ %c :: LF text
518+ == ::
519+ $% [%d p=@ud] :: blocklist
520+ == ::
521+```
522+
523+This space intentionally left undocumented. This stuff will change once
524+we get a well-typed clay.
525+
526+#### `++upas`, tree change
527+
528+```hoon
529+ ++ upas :: tree change (%d)
530+ $& [p=upas q=upas] :: cell
531+ $% [%0 p=axis] :: copy old
532+ [%1 p=*] :: insert new
533+ [%2 p=axis q=udon] :: mutate!
534+ == ::
535+```
536+
537+This space intentionally left undocumented. This stuff is not known to
538+work, and will likely change when we get a well-typed clay. Also, this
539+is not a complicated type; it is not difficult to work out the meaning.
540+
541+#### `++nori:clay`, repository action
542+
543+```hoon
544+ ++ nori :: repository action
545+ $% [& q=soba] :: delta
546+ [| p=@tas] :: label
547+ == ::
548+```
549+
550+This describes a change that we are asking clay to make to the desk.
551+There are two kinds of changes that may be made: we can modify files or
552+we can apply a label to a commit.
553+
554+In the `|` case, we will simply label the current commit with the given
555+label. In the `&` case, we will apply the given changes.
556+
557+#### `++soba:clay`, delta
558+
559+```hoon
560+ ++ soba ,[p=cart q=(list ,[p=path q=miso])] :: delta
561+```
562+
563+This describes a set of changes to make to a desk. The `cart` is simply
564+a pair of the old hash and the new hash of the desk. The list is a list
565+of changes keyed by the file they're changing. Thus, the paths are paths
566+to files to be changed while `miso` is a description of the change
567+itself.
568+
569+#### `++miso:clay`, ankh delta
570+
571+```hoon
572+ ++ miso :: ankh delta
573+ $% [%del p=*] :: delete
574+ [%ins p=*] :: insert
575+ [%mut p=udon] :: mutate
576+ == ::
577+```
578+
579+There are three kinds of changes that may be made to a node in a desk.
580+We can insert a file, in which case `p` is the contents of the new file.
581+We can delete a file, in which case `p` is the contents of the old file.
582+Finally, we can mutate that file, in which case the `udon` describes the
583+changes we are applying to the file.
584+
585+#### `++mizu:clay`, merged state
586+
587+```hoon
588+ ++ mizu ,[p=@u q=(map ,@ud tako) r=rang] :: new state
589+```
590+
591+This is the input to the `%merg` kiss, which allows us to perform a
592+merge. The `p` is the number of the new head commit. The `q` is a map
593+from numbers to commit hashes. This is all the new numbered commits that
594+are to be inserted. The keys to this should always be the numbers from
595+`let.dom` plus one to `p`, inclusive. The `r` is the maps of all the new
596+commits and data. Since these are merged into the current state, no old
597+commits or data need be here.
598+
599+#### `++riff:clay`, request/desist
600+
601+```hoon
602+ ++ riff ,[p=desk q=(unit rave)] :: request/desist
603+```
604+
605+This represents a request for data about a particular desk. If `q`
606+contains a `rave`, then this opens a subscription to the desk for that
607+data. If `q` is null, then this tells clay to cancel the subscription
608+along this duct.
609+
610+#### `++riot:clay`, response
611+
612+```hoon
613+ ++ riot (unit rant) :: response/complete
614+```
615+
616+A riot is a response to a subscription. If null, the subscription has
617+been completed, and no more responses will be sent. Otherwise, the
618+`rant` is the produced data.
619+
620+#### `++rant:clay`, response data
621+
622+```hoon
623+ ++ rant :: namespace binding
624+ $: p=[p=care q=case r=@tas] :: clade release book
625+ q=path :: spur
626+ r=* :: data
627+ == ::
628+```
629+
630+This is the data at a particular node in the filesystem. `p.p` specifies
631+the type of data that was requested (and is produced). `q.p` gives the
632+specific version reported (since a range of versions may be requested in
633+a subscription). `r.p` is the desk. `q` is the path to the filesystem
634+node. `r` is the data itself (in the format specified by `p.p`).
635+
636+### `++nako`, subscription response data
637+
638+```hoon
639+ ++ nako $: gar=(map ,@ud tako) :: new ids
640+ let=@ud :: next id
641+ lar=(set yaki) :: new commits
642+ bar=(set blob) :: new content
643+ == ::
644+```
645+
646+This is the data that is produced by a request for a range of revisions
647+of a desk. This allows us to easily keep track of a remote repository --
648+all the new information we need is contained in the `nako`.
649+
650+`gar` is a map of the revisions in the range to the hash of the commit
651+at that revision. These hashes can be used with `hut:rang:clay` to find the
652+commit itself.
653+
654+`let` is either the last revision number in the range or the most recent
655+revision number, whichever is smaller.
656+
657+`lar` is the set of new commits, and `bar` is the set of new content.
658+
659+## Public Interface
660+
661+As with all vanes, there are exactly two ways to interact with clay.
662+`%clay` exports a namespace accessible through `.^`, which is described
663+above under `++care:clay`. The primary way of interacting with clay, though,
664+is by sending kisses and receiving gifts.
665+
666+```hoon
667+ ++ gift :: out result <-$
668+ $% [%ergo p=@p q=@tas r=@ud] :: version update
669+ [%note p=@tD q=tank] :: debug message
670+ [%writ p=riot] :: response
671+ == ::
672+ ++ kiss :: in request ->$
673+ $% [%info p=@p q=@tas r=nori] :: internal edit
674+ [%ingo p=@p q=@tas r=nori] :: internal noun edit
675+ [%init p=@p] :: report install
676+ [%into p=@p q=@tas r=nori] :: external edit
677+ [%invo p=@p q=@tas r=nori] :: external noun edit
678+ [%merg p=@p q=@tas r=mizu] :: internal change
679+ [%wart p=sock q=@tas r=path s=*] :: network request
680+ [%warp p=sock q=riff] :: file request
681+ == ::
682+```
683+
684+There are only a small number of possible kisses, so it behooves us to
685+describe each in detail.
686+
687+```hoon
688+ $% [%info p=@p q=@tas r=nori] :: internal edit
689+
690+ [%into p=@p q=@tas r=nori] :: external edit
691+```
692+
693+These two kisses are nearly identical. At a high level, they apply
694+changes to the filesystem. Whenever we add, remove, or edit a file, one
695+of these cards is sent. The `p` is the ship whose filesystem we're
696+trying to change, the `q` is the desk we're changing, and the `r` is the
697+request change. For the format of the requested change, see the
698+documentation for `++nori:clay` above.
699+
700+When a file is changed in the unix filesystem, vere will send a `%into`
701+kiss. This tells clay that the duct over which the kiss was sent is the
702+duct that unix is listening on for changes. From within Arvo, though, we
703+should never send a `%into` kiss. The `%info` kiss is exactly identical
704+except it does not reset the duct.
705+
706+```hoon
707+ [%ingo p=@p q=@tas r=nori] :: internal noun edit
708+
709+ [%invo p=@p q=@tas r=nori] :: external noun edit
710+```
711+
712+These kisses are currently identical to `%info` and `%into`, though this
713+will not always be the case. The intent is for these kisses to allow
714+typed changes to clay so that we may store typed data. This is currently
715+unimplemented.
716+
717+```hoon
718+ [%init p=@p] :: report install
719+```
720+
721+Init is called when a ship is started on our pier. This simply creates a
722+default `room` to go into our `raft`. Essentially, this initializes the
723+filesystem for a ship.
724+
725+```hoon
726+ [%merg p=@p q=@tas r=mizu] :: internal change
727+```
728+
729+This is called to perform a merge. This is most visibly called by
730+:update to update the filesystem of the current ship to that of its
731+sein. The `p` and `q` are as in `%info`, and the `r` is the description
732+of the merge. See `++mizu:clay` above.
733+
734+XX
735+`XX [%wake ~] :: timer activate XX`
736+XX\
737+XX This card is sent by unix at the time specified by `++doze`. This
738+time is XX usually the closest time specified in a subscription request.
739+When `%wake` is XX called, we update our subscribers if there have been
740+any changes.
741+
742+```hoon
743+ [%wart p=sock q=@tas r=path s=*] :: network request
744+```
745+
746+This is a request that has come across the network for a particular
747+file. When another ship asks for a file from us, that request comes to
748+us in the form of a `%wart` kiss. This is handled by trivially turning
749+it into a `%warp`.
750+
751+```hoon
752+ [%warp p=sock q=riff] :: file request
753+```
754+
755+This is a request for information about a particular desk. This is, in
756+its most general form, a subscription, though in many cases it is the
757+trivial case of a subscription -- a read. See `++riff:clay` for the format of
758+the request.
759+
760+
arvo/clay/foreign.mdnew file+412
@@ -0,0 +1,412 @@
1++++
2+title = "Foreign Requests"
3+weight = 7
4+template = "doc.html"
5++++
6+
7+Parts of this document may be out of date as of March 2021.
8+
9+Foreign reads and subscriptions are handled in much the same way as
10+local ones. The interface is the same -- a vane or app sends a `%warp`
11+kiss with the request. The difference is simply that the `sock` refers
12+to the foreign ship.
13+
14+Thus, we start in the same place -- in `++call`, handling `%warp`.
15+However, since the two side of the `sock` are different, we follow a
16+different path.
17+
18+```hoon
19+ =+ wex=(do now p.q.hic p.q.q.hic ruf)
20+ =+ ^= woo
21+ ?~ q.q.q.hic
22+ abet:(ease:wex hen)
23+ abet:(eave:wex hen u.q.q.q.hic)
24+ [-.woo (posh q.p.q.hic p.q.q.hic +.woo ruf)]
25+```
26+
27+If we compare this to how the local case was handled, we see that it's
28+not all that different. We use `++do` rather than `++un` and `++de` to
29+set up the core for the foreign ship. This gives us a `++de` core, so we
30+either cancel or begin the request by calling `++ease` or `++eave`,
31+exactly as in the local case. In either case, we call `++abet:de` to
32+resolve our various types of output into actual moves, as described in
33+the local case. Finally, we call `++posh` to update our raft, putting
34+the modified rung into the raft.
35+
36+We'll first trace through `++do`.
37+
38+```hoon
39+ ++ do
40+ |= [now=@da [who=ship him=ship] syd=@tas ruf=raft]
41+ =+ ^= rug ^- rung
42+ =+ rug=(~(get by hoy.ruf) him)
43+ ?^(rug u.rug *rung)
44+ =+ ^= red ^- rede
45+ =+ yit=(~(get by rus.rug) syd)
46+ ?^(yit u.yit `rede`[~2000.1.1 ~ [~ *rind] *dome])
47+ ((de now ~ ~) [who him] syd red ran.ruf)
48+```
49+
50+If we already have a rung for this foreign ship, then we use that.
51+Otherwise, we create a new blank one. If we already have a rede in this
52+rung, then we use that, otherwise we create a blank one. An important
53+point to note here is that we let `ref` in the rede be `[~ *rind]`.
54+Recall, for domestic desks `ref` is null. We use this to distinguish
55+between foreign and domestic desks in `++de`.
56+
57+With this information, we create a `++de` core as usual.
58+
59+Although we've already covered `++ease` and `++eave`, we'll go through
60+them quickly again, highlighting the case of foreign request.
61+
62+```hoon
63+ ++ ease :: release request
64+ |= hen=duct
65+ ^+ +>
66+ ?~ ref +>
67+ =+ rov=(~(got by qyx) hen)
68+ =. qyx (~(del by qyx) hen)
69+ (mabe rov (cury best hen))
70+ =. qyx (~(del by qyx) hen)
71+ |- ^+ +>+.$
72+ =+ nux=(~(get by fod.u.ref) hen)
73+ ?~ nux +>+.$
74+ %= +>+.$
75+ say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
76+ fod.u.ref (~(del by fod.u.ref) hen)
77+ bom.u.ref (~(del by bom.u.ref) u.nux)
78+ ==
79+```
80+
81+Here, we still remove the duct from our cult (we maintain a cult even
82+for foreign desks), but we also need to tell the foreign desk to cancel
83+our subscription. We do this by sending a request (by appending to
84+`say`, which gets resolved in `++abet:de` to a `%want` kiss to ames) to
85+the foreign ship to cancel the subscription. Since we don't anymore
86+expect a response on this duct, we remove it from `fod` and `bom`, which
87+are the maps between ducts, raves, and request sequence numbers.
88+Basically, we remove every trace of the subscription from our request
89+manager.
90+
91+In the case of `++eave`, where we're creating a new request, everything
92+is exactly identical to the case of the local request except `++duce`.
93+We said that `++duce` simply puts the request into our cult. This is
94+true for a domestic request, but distinctly untrue for foreign requests.
95+
96+```hoon
97+ ++ duce :: produce request
98+ |= [hen=duct rov=rove]
99+ ^+ +>
100+ =. qyx (~(put by qyx) hen rov)
101+ ?~ ref +>.$
102+ |- ^+ +>+.$ :: XX why?
103+ =+ rav=(reve rov)
104+ =+ ^= vaw ^- rave
105+ ?. ?=([%& %v *] rav) rav
106+ [%| [%ud let.dom] `case`q.p.rav r.p.rav]
107+ =+ inx=nix.u.ref
108+ %= +>+.$
109+ say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
110+ nix.u.ref +(nix.u.ref)
111+ bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
112+ fod.u.ref (~(put by fod.u.ref) hen inx)
113+ ==
114+```
115+
116+If we have a request manager (i.e. this is a foreign desk), then we do
117+the approximate inverse of `++ease`. We create a rave out of the given
118+request and send it off to the foreign desk by putting it in `say`. Note
119+that the rave is created to request the information starting at the next
120+revision number. Since this is a new request, we put it into `fod` and
121+`bom` to associate the request with its duct and its sequence number.
122+Since we're using another sequence number, we must increment `nix`,
123+which represents the next available sequence number.
124+
125+And that's really it for this side of the request. Requesting foreign
126+information isn't that hard. Let's see what it looks like on the other
127+side. When we get a request from another ship for information on our
128+ship, that comes to us in the form of a `%wart` from ames.
129+
130+We handle a `%wart` in `++call`, right next to where we handle the
131+`%warp` case.
132+
133+```hoon
134+ %wart
135+ ?> ?=(%re q.q.hic)
136+ =+ ryf=((hard riff) s.q.hic)
137+ :_ ..^$
138+ :~ :- hen
139+ :^ %pass [(scot %p p.p.q.hic) (scot %p q.p.q.hic) r.q.hic]
140+ %c
141+ [%warp [p.p.q.hic p.p.q.hic] ryf]
142+ ==
143+```
144+
145+Every request we receive should be of type `riff`, so we coerce it into
146+that type. We just convert this into a new `%warp` kiss that we pass to
147+ourself. This gets handled like normal, as a local request. When the
148+request produces a value, it does so like normal as a `%writ`, which is
149+returned to `++take` along the path we just sent it on.
150+
151+```hoon
152+ %writ
153+ ?> ?=([@ @ *] tea)
154+ =+ our=(need (slaw %p i.tea))
155+ =+ him=(need (slaw %p i.t.tea))
156+ :_ ..^$
157+ :~ :- hen
158+ [%pass ~ %a [%want [our him] [%r %re %c t.t.tea] p.+.q.hin]]
159+ ==
160+```
161+
162+Since we encoded the ship we need to respond to in the path, we can just
163+pass our `%want` back to ames, so that we tell the requesting ship about
164+the new data.
165+
166+This comes back to the original ship as a `%waft` from ames, which comes
167+into `++take`, right next to where we handled `%writ`.
168+
169+```hoon
170+ %waft
171+ ?> ?=([@ @ ~] tea)
172+ =+ syd=(need (slaw %tas i.tea))
173+ =+ inx=(need (slaw %ud i.t.tea))
174+ =+ ^= zat
175+ =< wake
176+ (knit:(do now p.+.q.hin syd ruf) [inx ((hard riot) q.+.q.hin)])
177+ =^ mos ruf
178+ =+ zot=abet.zat
179+ [-.zot (posh q.p.+.q.hin syd +.zot ruf)]
180+ [mos ..^$(ran.ruf ran.zat)] :: merge in new obj
181+```
182+
183+This gets the desk and sequence number from the path the request was
184+sent over. This determines exactly which request is being responded to.
185+We call `++knit:de` to apply the changes to our local desk, and we call
186+`++wake` to update our subscribers. Then we call `++abet:de` and
187+`++posh` as normal (like in `++eave`).
188+
189+We'll examine `++knit` and `++wake`, in that order.
190+
191+```hoon
192+ ++ knit :: external change
193+ |= [inx=@ud rot=riot]
194+ ^+ +>
195+ ?> ?=(^ ref)
196+ |- ^+ +>+.$
197+ =+ ruv=(~(get by bom.u.ref) inx)
198+ ?~ ruv +>+.$
199+ => ?. |(?=(~ rot) ?=(& -.q.u.ruv)) .
200+ %_ .
201+ bom.u.ref (~(del by bom.u.ref) inx)
202+ fod.u.ref (~(del by fod.u.ref) p.u.ruv)
203+ ==
204+ ?~ rot
205+ =+ rav=`rave`q.u.ruv
206+ %= +>+.$
207+ lim
208+ ?.(&(?=(| -.rav) ?=(%da -.q.p.rav)) lim `@da`p.q.p.rav)
209+ ::
210+ haw.u.ref
211+ ?. ?=(& -.rav) haw.u.ref
212+ (~(put by haw.u.ref) p.rav ~)
213+ ==
214+ ?< ?=(%v p.p.u.rot)
215+ =. haw.u.ref
216+ (~(put by haw.u.ref) [p.p.u.rot q.p.u.rot q.u.rot] ~ r.u.rot)
217+ ?. ?=(%w p.p.u.rot) +>+.$
218+ |- ^+ +>+.^$
219+ =+ nez=[%w [%ud let.dom] ~]
220+ =+ nex=(~(get by haw.u.ref) nez)
221+ ?~ nex +>+.^$
222+ ?~ u.nex +>+.^$ :: should never happen
223+ =. +>+.^$ =+ roo=(edis ((hard nako) u.u.nex))
224+ ?>(?=(^ ref.roo) roo)
225+ %= $
226+ haw.u.ref (~(del by haw.u.ref) nez)
227+ ==
228+```
229+
230+This is kind of a long [gate](/docs/glossary/gate/), but don't worry, it's not bad at all.
231+
232+First, we assert that we're not a domestic desk. That wouldn't make any
233+sense at all.
234+
235+Since we have the sequence number of the request, we can get the duct
236+and rave from `bom` in our request manager. If we didn't actually
237+request this data (or the request was canceled before we got it), then
238+we do nothing.
239+
240+Else, we remove the request from `bom` and `fod` unless this was a
241+subscription request and we didn't receive a null riot (which would
242+indicate the last message on the subscription).
243+
244+Now, if we received a null riot, then if this was a subscription request
245+by date, then we update `lim` in our request manager (representing the
246+latest time at which we have complete information for this desk) to the
247+date that was requested. If this was a single read request, then we put
248+the result in our simple cache `haw` to make future requests faster.
249+Then we're done.
250+
251+If we received actual data, then we put it into our cache `haw`. Unless
252+it's a `%w` request, we're done.
253+
254+If it is a `%w` request, then we try to get the `%w` at our current head
255+from the cache. In general, that should be the thing we just put in a
256+moment ago, but that is not guaranteed. The most common case where this
257+is different is when we receive desk updates out of order. At any rate,
258+since we now have new information, we need to apply it to our local copy
259+of the desk. We do so in `++edis`, and then we remove the stuff we just
260+applied from the cache, since it's not really a true "single read", like
261+what should really be in the cache.
262+
263+```hoon
264+ ++ edis :: apply subscription
265+ |= nak=nako
266+ ^+ +>
267+ %= +>
268+ hit.dom (~(uni by hit.dom) gar.nak)
269+ let.dom let.nak
270+ lat.ran %+ roll (~(tap in bar.nak) ~)
271+ =< .(yeb lat.ran)
272+ |= [sar=blob yeb=(map lobe blob)]
273+ =+ zax=(blob-to-lobe sar)
274+ %+ ~(put by yeb) zax sar
275+ hut.ran %+ roll (~(tap in lar.nak) ~)
276+ =< .(yeb hut.ran)
277+ |= [sar=yaki yeb=(map tako yaki)]
278+ %+ ~(put by yeb) r.sar sar
279+ ==
280+```
281+
282+This shows, of course, exactly why nako is defined the way it is. To
283+become completely up to date with the foreign desk, we need to merge
284+`hit` with the foreign one so that we have all the revision numbers. We
285+update `let` so that we know which revision is the head.
286+
287+We merge the new blobs in `lat`, keying them by their hash, which we get
288+from a call to `++blob-to-lobe`. Recall that the hash is stored in the
289+actual blob itself. We do the same thing to the new yakis, putting them
290+in `hut`, keyed by their hash.
291+
292+Now, our local dome should be exactly the same as the foreign one.
293+
294+This concludes our discussion of `++knit`. Now the changes have been
295+applied to our local copy of the desk, and we just need to update our
296+subscribers. We do so in `++wake:de`.
297+
298+```hoon
299+ ++ wake :: update subscribers
300+ ^+ .
301+ =+ xiq=(~(tap by qyx) ~)
302+ =| xaq=(list ,[p=duct q=rove])
303+ |- ^+ ..wake
304+ ?~ xiq
305+ ..wake(qyx (~(gas by *cult) xaq))
306+ ?- -.q.i.xiq
307+ &
308+ =+ cas=?~(ref ~ (~(get by haw.u.ref) `mood`p.q.i.xiq))
309+ ?^ cas
310+ %= $
311+ xiq t.xiq
312+ ..wake ?~ u.cas (blub p.i.xiq)
313+ (blab p.i.xiq p.q.i.xiq u.u.cas)
314+ ==
315+ =+ nao=(~(case-to-aeon ze lim dom ran) q.p.q.i.xiq)
316+ ?~ nao $(xiq t.xiq, xaq [i.xiq xaq])
317+ $(xiq t.xiq, ..wake (balk p.i.xiq u.nao p.q.i.xiq))
318+ ::
319+ |
320+ =+ mot=`moot`p.q.i.xiq
321+ =+ nab=(~(case-to-aeon ze lim dom ran) p.mot)
322+ ?~ nab
323+ $(xiq t.xiq, xaq [i.xiq xaq])
324+ =+ huy=(~(case-to-aeon ze lim dom ran) q.mot)
325+ ?~ huy
326+ =+ ptr=[%ud +(let.dom)]
327+ %= $
328+ xiq t.xiq
329+ xaq [[p.i.xiq [%| ptr q.mot r.mot s.mot]] xaq]
330+ ..wake =+ ^= ear
331+ (~(lobes-at-path ze lim dom ran) let.dom r.p.q.i.xiq)
332+ ?: =(s.p.q.i.xiq ear) ..wake
333+ =+ fud=(~(make-nako ze lim dom ran) u.nab let.dom)
334+ (bleb p.i.xiq let.dom fud)
335+ ==
336+ %= $
337+ xiq t.xiq
338+ ..wake =- (blub:- p.i.xiq)
339+ =+ ^= ear
340+ (~(lobes-at-path ze lim dom ran) u.huy r.p.q.i.xiq)
341+ ?: =(s.p.q.i.xiq ear) (blub p.i.xiq)
342+ =+ fud=(~(make-nako ze lim dom ran) u.nab u.huy)
343+ (bleb p.i.xiq +(u.nab) fud)
344+ ==
345+ ==
346+ --
347+```
348+
349+This is even longer than `++knit`, but it's pretty similar to `++eave`.
350+We loop through each of our subscribers `xiq`, processing each in turn.
351+When we're done, we just put the remaining subscribers back in our
352+subscriber list.
353+
354+If the subscriber is a single read, then, if this is a foreign desk
355+(note that `++wake` is called from other arms, and not only on foreign
356+desks). Obviously, if we find an identical request there, then we can
357+produce the result immediately. Referential transparency for the win. We
358+produce the result with a call to `++blab`. If this is a foreign desk
359+but the result is not in the cache, then we produce `++blub` (canceled
360+subscription with no data) for reasons entirely opaque to me. Seriously,
361+it seems like we should wait until we get an actual response to the
362+request. If someone figures out why this is, let me know. At any rate,
363+it seems to work.
364+
365+If this is a domestic desk, then we check to see if the case exists yet.
366+If it doesn't, then we simply move on to the next subscriber, consing
367+this one onto `xaq` so that we can check again the next time around. If
368+it does exist, then we call `++balk` to fulfill the request and produce
369+it.
370+
371+`++balk` is very simple, so we'll describe it here before we get to the
372+subscription case.
373+
374+```hoon
375+ ++ balk :: read and send
376+ |= [hen=duct oan=@ud mun=mood]
377+ ^+ +>
378+ =+ vid=(~(read-at-aeon ze lim dom ran) oan mun)
379+ ?~ vid (blub hen) (blab hen mun u.vid)
380+```
381+
382+We call `++read-at-aeon` on the given request and aeon. If you recall,
383+this processes a `mood` at a particular aeon and produces the result, if
384+there is one. If there is data at the requested location, then we
385+produce it with `++blab`. Else, we call `++blub` to notify the
386+subscriber that no data can ever come over this subscriptioin since it
387+is now impossible for there to ever be data for the given request.
388+Because referential transparency.
389+
390+At any rate, back to `++wake`. If the given rave is a subscription
391+request, then we proceed similarly to how we do in `++eave`. We first
392+try to get the aeon referred to by the starting case. If it doesn't
393+exist yet, then we can't do anything interesting with this subscription,
394+so we move on to the next one.
395+
396+Otherwise, we try to get the aeon referred to by the ending case. If it
397+doesn't exist yet, then we produce all the information we can. We call
398+`++lobes-at-path` at the given aeon and path to see if the requested
399+path has actually changed. If it hasn't, then we don't produce anything;
400+else, we produce the correct nako by calling `++bleb` on the result of
401+`++make-nako`, as in `++eave`. At any rate, we move on to the next
402+subscription, putting back into our cult the current subscription with a
403+new start case of the next aeon after the present.
404+
405+If the aeon referred to by the ending case does exist, then we drop this
406+subscriber from our cult and satisfy its request immediately. This is
407+the same as before -- we check to see if the data at the path has
408+actually changed, producing it if it has; else, we call `++blub` since
409+no more data can be produced over this subscription.
410+
411+This concludes our discussion of foreign requests.
412+
arvo/clay/local-reads.mdnew file+783
@@ -0,0 +1,783 @@
1++++
2+title = "Local Reads and Writes"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+Parts of this document may be out of date as of March 2021.
8+
9+There are two real types of interaction with a filesystem: you can read,
10+and you can write. We'll describe each process, detailing both the flow
11+of control followed by the kernel and the algorithms involved. The
12+simpler case is that of the read, so we'll begin with that.
13+
14+When a vane or an application wishes to read a file from the filesystem,
15+it sends a `%warp` kiss, as described above. Of course, you may request
16+a file on another ship and, being a global filesystem, clay will happily
17+produce it for you. That code pathway will be described in another
18+section; here, we will restrict ourselves to examining the case of a
19+read from a ship on our own pier.
20+
21+The kiss can request either a single version of a file node or a range
22+of versions of a desk. Here, we'll deal only with a request for a single
23+version.
24+
25+As in all vanes, a kiss enters clay via a call to `++call`. Scanning
26+through the arm, we quickly see where `%warp` is handled.
27+
28+```hoon
29+ ?: =(p.p.q.hic q.p.q.hic)
30+ =+ une=(un p.p.q.hic now ruf)
31+ =+ wex=(di:une p.q.q.hic)
32+ =+ ^= wao
33+ ?~ q.q.q.hic
34+ (ease:wex hen)
35+ (eave:wex hen u.q.q.q.hic)
36+ =+ ^= woo
37+ abet:wao
38+ [-.woo abet:(pish:une p.q.q.hic +.woo ran.wao)]
39+```
40+
41+We're following the familar patern of producing a list of moves and an
42+updated state. In this case, the state is `++raft`.
43+
44+We first check to see if the sending and receiving ships are the same.
45+If they're not, then this is a request for data on another ship. We
46+describe that process later. Here, we discuss only the case of a local
47+read.
48+
49+At a high level, the call to `++un` sets up the core for the domestic
50+ship that contains the files we're looking for. The call to `++di` sets
51+up the core for the particular desk we're referring to.
52+
53+After this, we perform the actual request. If there is no rave in the
54+riff, then that means we are cancelling a request, so we call
55+`++ease:de`. Otherwise, we start a subscription with `++eave:de`. We
56+call `++abet:de` to resolve our various types of output into actual
57+moves. We produce the moves we found above and the `++un` core resolved
58+with `++pish:un` (putting the modified desk in the room) and `++abet:un`
59+(putting the modified room in the raft).
60+
61+Much of this is fairly straightforward, so we'll only describe `++ease`,
62+`++eave`, and `++abet:de`. Feel free to look up the code to the other
63+steps -- it should be easy to follow.
64+
65+Although it's called last, it's usually worth examining `++abet` first,
66+since it defines in what ways we can cause side effects. Let's do that,
67+and also a few of the lines at the beginning of `++de`.
68+
69+```hoon
70+ =| yel=(list ,[p=duct q=gift])
71+ =| byn=(list ,[p=duct q=riot])
72+ =| vag=(list ,[p=duct q=gift])
73+ =| say=(list ,[p=duct q=path r=ship s=[p=@ud q=riff]])
74+ =| tag=(list ,[p=duct q=path c=note])
75+ |%
76+ ++ abet
77+ ^- [(list move) rede]
78+ :_ red
79+ ;: weld
80+ %+ turn (flop yel)
81+ |=([a=duct b=gift] [hun %give b])
82+ ::
83+ %+ turn (flop byn)
84+ |=([a=duct b=riot] [a %give [%writ b]])
85+ ::
86+ %+ turn (flop vag)
87+ |=([a=duct b=gift] [a %give b])
88+ ::
89+ %+ turn (flop say)
90+ |= [a=duct b=path c=ship d=[p=@ud q=riff]]
91+ :- a
92+ [%pass b %a %want [who c] [%q %re p.q.d (scot %ud p.d) ~] q.d]
93+ ::
94+ %+ turn (flop tag)
95+ |=([a=duct b=path c=note] [a %pass b c])
96+ ==
97+```
98+
99+This is very simple code. We see there are exactly five different kinds
100+of side effects we can generate.
101+
102+In `yel` we put gifts that we wish to be sent along the `hun:room` duct
103+to dill. See the documentation for `++room` above. This is how we
104+display messages to the terminal.
105+
106+In `byn` we put riots that we wish returned to subscribers. Recall that
107+a riot is a response to a subscription. These are returned to our
108+subscribers in the form of a `%writ` gift.
109+
110+In `vag` we put gifts along with the ducts on which to send them. This
111+allows us to produce arbitrary gifts, but in practice this is only used
112+to produce `%ergo` gifts.
113+
114+In `say` we put messages we wish to pass to ames. These messages are
115+used to request information from clay on other piers. We must provide
116+not only the duct and the request (the riff), but also the return path,
117+the other ship to talk to, and the sequence number of the request.
118+
119+In `tag` we put arbitrary notes we wish to pass to other vanes. For now,
120+the only notes we pass here are `%wait` and `%rest` to the timer vane.
121+
122+Now that we know what kinds of side effects we may have, we can jump
123+into the handling of requests.
124+
125+```hoon
126+ ++ ease :: release request
127+ |= hen=duct
128+ ^+ +>
129+ ?~ ref +>
130+ =+ rov=(~(got by qyx) hen)
131+ =. qyx (~(del by qyx) hen)
132+ (mabe rov (cury best hen))
133+ =. qyx (~(del by qyx) hen)
134+ |- ^+ +>+.$
135+ =+ nux=(~(get by fod.u.ref) hen)
136+ ?~ nux +>+.$
137+ %= +>+.$
138+ say [[hen [(scot %ud u.nux) ~] for [u.nux syd ~]] say]
139+ fod.u.ref (~(del by fod.u.ref) hen)
140+ bom.u.ref (~(del by bom.u.ref) u.nux)
141+ ==
142+```
143+
144+This is called when we're cancelling a subscription. For domestic desks,
145+`ref` is null, so we're going to cancel any timer we might have created.
146+We first delete the duct from our map of requests, and then we call
147+`++mabe` with `++best` to send a `%rest` kiss to the timer vane if we
148+have started a timer. We'll describe `++best` and `++mabe` momentarily.
149+
150+Although we said we're not going to talk about foreign requests yet,
151+it's easy to see that for foreign desks, we cancel any outstanding
152+requests for this duct and send a message over ames to the other ship
153+telling them to cancel the subscription.
154+
155+```hoon
156+ ++ best
157+ |= [hen=duct tym=@da]
158+ %_(+> tag :_(tag [hen /tyme %t %rest tym]))
159+```
160+
161+This simply pushes a `%rest` note onto `tag`, from where it will be
162+passed back to arvo to be handled. This cancels the timer at the given
163+duct (with the given time).
164+
165+```hoon
166+ ++ mabe :: maybe fire function
167+ |* [rov=rove fun=$+(@da _+>.^$)]
168+ ^+ +>.$
169+ %- fall :_ +>.$
170+ %- bind :_ fun
171+ ^- (unit ,@da)
172+ ?- -.rov
173+ %&
174+ ?. ?=(%da -.q.p.rov) ~
175+ `p.q.p.rov
176+ %|
177+ =* mot p.rov
178+ %+ hunt
179+ ?. ?=(%da -.p.mot) ~
180+ ?.((lth now p.p.mot) ~ [~ p.p.mot])
181+ ?. ?=(%da -.q.mot) ~
182+ ?.((lth now p.q.mot) [~ now] [~ p.q.mot])
183+ ==
184+```
185+
186+This decides whether the given request can only be satsified in the
187+future. In that case, we call the given function with the time in the
188+future when we expect to have an update to give to this request. This is
189+called with `++best` to cancel timers and with `++bait` to start them.
190+
191+For single requests, we have a time if the request is for a particular
192+time (which is assumed to be in the future). For ranges of requests, we
193+check both the start and end cases to see if they are time cases. If so,
194+we choose the earlier time.
195+
196+If any of those give us a time, then we call the given funciton with the
197+smallest time.
198+
199+The more interesting case is, of course, when we're not cancelling a
200+subscription but starting one.
201+
202+```hoon
203+ ++ eave :: subscribe
204+ |= [hen=duct rav=rave]
205+ ^+ +>
206+ ?- -.rav
207+ &
208+ ?: &(=(p.p.rav %u) !=(p.q.p.rav now))
209+ ~& [%clay-fail p.q.p.rav %now now]
210+ !!
211+ =+ ver=(aver p.rav)
212+ ?~ ver
213+ (duce hen rav)
214+ ?~ u.ver
215+ (blub hen)
216+ (blab hen p.rav u.u.ver)
217+```
218+
219+There are two types of subscriptions -- either we're requesting a single
220+file or we're requesting a range of versions of a desk. We'll dicuss the
221+simpler case first.
222+
223+First, we check that we're not requesting the `rang` from any time other
224+than the present. Since we don't store that information for any other
225+time, we can't produce it in a referentially transparent manner for any
226+time other than the present.
227+
228+Then, we try to read the requested `mood:clay` `p.rav`. If we can't access
229+the request data right now, we call `++duce` to put the request in our
230+queue to be satisfied when the information becomes available.
231+
232+This case occurs when we make a request for a case whose (1) date is
233+after the current date, (2) number is after the current number, or (3)
234+label is not yet used.
235+
236+```hoon
237+ ++ duce :: produce request
238+ |= [hen=duct rov=rove]
239+ ^+ +>
240+ =. qyx (~(put by qyx) hen rov)
241+ ?~ ref
242+ (mabe rov (cury bait hen))
243+ |- ^+ +>+.$ :: XX why?
244+ =+ rav=(reve rov)
245+ =+ ^= vaw ^- rave
246+ ?. ?=([%& %v *] rav) rav
247+ [%| [%ud let.dom] `case`q.p.rav r.p.rav]
248+ =+ inx=nix.u.ref
249+ %= +>+.$
250+ say [[hen [(scot %ud inx) ~] for [inx syd ~ vaw]] say]
251+ nix.u.ref +(nix.u.ref)
252+ bom.u.ref (~(put by bom.u.ref) inx [hen vaw])
253+ fod.u.ref (~(put by fod.u.ref) hen inx)
254+ ==
255+```
256+
257+The code for `++duce` is nearly the exact inverse of `++ease`, which in
258+the case of a domestic desk is very simple -- we simply put the duct and
259+rave into `qyx` and possibly start a timer with `++mabe` and `++bait`.
260+Recall that `ref` is null for domestic desks and that `++mabe` fires the
261+given function with the time we need to be woken up at, if we need to be
262+woken up at a particular time.
263+
264+```hoon
265+ ++ bait
266+ |= [hen=duct tym=@da]
267+ %_(+> tag :_(tag [hen /tyme %t %wait tym]))
268+```
269+
270+This sets an alarm by sending a `%wait` card with the given time to the
271+timer vane.
272+
273+Back in `++eave`, if `++aver` returned `[~ ~]`, then we cancel the
274+subscription. This occurs when we make (1) a `%x` request for a file
275+that does not exist, (2) a `%w` request with a case that is not a
276+number, or (3) a `%w` request with a nonempty path. The `++blub` is
277+exactly what you would expect it to be.
278+
279+```hoon
280+ ++ blub :: ship stop
281+ |= hen=duct
282+ %_(+> byn [[hen ~] byn])
283+```
284+
285+We notify the duct that we're cancelling their subscription since it
286+isn't satisfiable.
287+
288+Otherwise, we have received the desired information, so we send it on to
289+the subscriber with `++blab`.
290+
291+```hoon
292+ ++ blab :: ship result
293+ |= [hen=duct mun=mood dat=*]
294+ ^+ +>
295+ +>(byn [[hen ~ [p.mun q.mun syd] r.mun dat] byn])
296+```
297+
298+The most interesting arm called in `++eave` is, of course, `++aver`,
299+where we actually try to read the data.
300+
301+```hoon
302+ ++ aver :: read
303+ |= mun=mood
304+ ^- (unit (unit ,*))
305+ ?: &(=(p.mun %u) !=(p.q.mun now)) :: prevent bad things
306+ ~& [%clay-fail p.q.mun %now now]
307+ !!
308+ =+ ezy=?~(ref ~ (~(get by haw.u.ref) mun))
309+ ?^ ezy ezy
310+ =+ nao=(~(case-to-aeon ze lim dom ran) q.mun)
311+ ?~(nao ~ [~ (~(read-at-aeon ze lim dom ran) u.nao mun)])
312+```
313+
314+We check immediately that we're not requesting the `rang` for any time
315+other than the present.
316+
317+If this is a foreign desk, then we check our cache for the specific
318+request. If either this is a domestic desk or we don't have the request
319+in our cache, then we have to actually go read the data from our dome.
320+
321+We need to do two things. First, we try to find the number of the commit
322+specified by the given case, and then we try to get the data there.
323+
324+Here, we jump into `arvo/zuse.hoon`, which is where much of the
325+algorithmic code is stored, as opposed to the clay interface, which is
326+stored in `arvo/clay.hoon`. We examine `++case-to-aeon:ze`.
327+
328+```hoon
329+ ++ case-to-aeon :: case-to-aeon:ze
330+ |= lok=case :: act count through
331+ ^- (unit aeon)
332+ ?- -.lok
333+ %da
334+ ?: (gth p.lok lim) ~
335+ |- ^- (unit aeon)
336+ ?: =(0 let) [~ 0] :: avoid underflow
337+ ?: %+ gte p.lok
338+ =< t
339+ %- tako-to-yaki
340+ %- aeon-to-tako
341+ let
342+ [~ let]
343+ $(let (dec let))
344+ ::
345+ %tas (~(get by lab) p.lok)
346+ %ud ?:((gth p.lok let) ~ [~ p.lok])
347+ ==
348+```
349+
350+We handle each type of `case:clay` differently. The latter two types are
351+easy.
352+
353+If we're requesting a revision by label, then we simply look up the
354+requested label in `lab` from the given dome. If it exists, that is our
355+aeon; else we produce null, indicating the requested revision does not
356+yet exist.
357+
358+If we're requesting a revision by number, we check if we've yet reached
359+that number. If so, we produce the number; else we produce null.
360+
361+If we're requesting a revision by date, we check first if the date is in
362+the future, returning null if so. Else we start from the most recent
363+revision and scan backwards until we find the first revision committed
364+before that date, and we produce that. If we requested a date before any
365+revisions were committed, we produce `0`.
366+
367+The definitions of `++aeon-to-tako` and `++tako-to-yaki` are trivial.
368+
369+```hoon
370+ ++ aeon-to-tako ~(got by hit)
371+
372+ ++ tako-to-yaki ~(got by hut) :: grab yaki
373+```
374+
375+We simply look up the aeon or tako in their respective maps (`hit` and
376+`hut`).
377+
378+Assuming we got a valid version number, `++aver` calls
379+`++read-at-aeon:ze`, which reads the requested data at the given
380+revision.
381+
382+```hoon
383+ ++ read-at-aeon :: read-at-aeon:ze
384+ |= [oan=aeon mun=mood] :: seek and read
385+ ^- (unit)
386+ ?: &(?=(%w p.mun) !?=(%ud -.q.mun)) :: NB only for speed
387+ ?^(r.mun ~ [~ oan])
388+ (read:(rewind oan) mun)
389+```
390+
391+If we're requesting the revision number with a case other than by
392+number, then we go ahead and just produce the number we were given.
393+Otherwise, we call `++rewind` to rewind our state to the given revision,
394+and then we call `++read` to get the requested information.
395+
396+```hoon
397+ ++ rewind :: rewind:ze
398+ |= oan=aeon :: rewind to aeon
399+ ^+ +>
400+ ?: =(let oan) +>
401+ ?: (gth oan let) !! :: don't have version
402+ +>(ank (checkout-ankh q:(tako-to-yaki (aeon-to-tako oan))), let oan)
403+```
404+
405+If we're already at the requested version, we do nothing. If we're
406+requesting a version later than our head, we are unable to comply.
407+
408+Otherwise, we get the hash of the commit at the number, and from that we
409+get the commit itself (the yaki), which has the map of path to lobe that
410+represents a version of the filesystem. We call `++checkout-ankh` to
411+checkout the commit, and we replace `ank` in our context with the
412+result.
413+
414+```hoon
415+ ++ checkout-ankh :: checkout-ankh:ze
416+ |= hat=(map path lobe) :: checkout commit
417+ ^- ankh
418+ %- cosh
419+ %+ roll (~(tap by hat) ~)
420+ |= [[pat=path bar=lobe] ank=ankh]
421+ ^- ankh
422+ %- cosh
423+ ?~ pat
424+ =+ zar=(lobe-to-noun bar)
425+ ank(q [~ (sham zar) zar])
426+ =+ nak=(~(get by r.ank) i.pat)
427+ %= ank
428+ r %+ ~(put by r.ank) i.pat
429+ $(pat t.pat, ank (fall nak _ankh))
430+ ==
431+```
432+
433+Twice we call `++cosh`, which hashes a commit, updating `p` in an
434+`ankh`. Let's jump into that algorithm before we describe
435+`++checkout-ankh`.
436+
437+```hoon
438+ ++ cosh :: locally rehash
439+ |= ank=ankh :: NB v/unix.c
440+ ank(p rehash:(zu ank))
441+```
442+
443+We simply replace `p` in the hash with the `cash` we get from a call to
444+`++rehash:zu`.
445+
446+```hoon
447+ ++ zu !: :: filesystem
448+ |= ank=ankh :: filesystem state
449+ =| myz=(list ,[p=path q=miso]) :: changes in reverse
450+ =| ram=path :: reverse path into
451+ |%
452+ ++ rehash :: local rehash
453+ ^- cash
454+ %+ mix ?~(q.ank 0 p.u.q.ank)
455+ =+ axe=1
456+ |- ^- cash
457+ ?~ r.ank _@
458+ ;: mix
459+ (shaf %dash (mix axe (shaf %dush (mix p.n.r.ank p.q.n.r.ank))))
460+ $(r.ank l.r.ank, axe (peg axe 2))
461+ $(r.ank r.r.ank, axe (peg axe 3))
462+ ==
463+```
464+
465+`++zu` is a core we set up with a particular filesystem node to traverse
466+a checkout of the filesystem and access the actual data inside it. One
467+of the things we can do with it is to create a recursive hash of the
468+node.
469+
470+In `++rehash`, if this node is a file, then we xor the remainder of the
471+hash with the hash of the contents of the file. The remainder of the
472+hash is `0` if we have no children, else we descend into our children.
473+Basically, we do a half SHA-256 of the xor of the axis of this child and
474+the half SHA-256 of the xor of the name of the child and the hash of the
475+child. This is done for each child and all the results are xored
476+together.
477+
478+Now we return to our discussion of `++checkout-ankh`.
479+
480+We fold over every path in this version of the filesystem and create a
481+great ankh out of them. First, we call `++lobe-to-noun` to get the raw
482+data referred to be each lobe.
483+
484+```hoon
485+ ++ lobe-to-noun :: grab blob
486+ |= p=lobe :: ^- *
487+ %- blob-to-noun
488+ (lobe-to-blob p)
489+```
490+
491+This converts a lobe into the raw data it refers to by first getting the
492+blob with `++lobe-to-blob` and converting that into data with
493+`++blob-to-noun`.
494+
495+```hoon
496+ ++ lobe-to-blob ~(got by lat) :: grab blob
497+```
498+
499+This just grabs the blob that the lobe refers to.
500+
501+```hoon
502+ ++ blob-to-noun :: grab blob
503+ |= p=blob
504+ ?- -.p
505+ %delta (lump r.p (lobe-to-noun q.p))
506+ %direct q.p
507+ %indirect q.p
508+ ==
509+```
510+
511+If we have either a direct or an indirect blob, then the data is stored
512+right in the blob. Otherwise, we have to reconstruct it from the diffs.
513+We do this by calling `++lump` on the diff in the blob with the data
514+obtained by recursively calling the parent of this blob.
515+
516+```hoon
517+ ++ lump :: apply patch
518+ |= [don=udon src=*]
519+ ^- *
520+ ?+ p.don ~|(%unsupported !!)
521+ %a
522+ ?+ -.q.don ~|(%unsupported !!)
523+ %a q.q.don
524+ %c (lurk ((hard (list)) src) p.q.don)
525+ %d (lure src p.q.don)
526+ ==
527+ ::
528+ %c
529+ =+ dst=(lore ((hard ,@) src))
530+ %- roly
531+ ?+ -.q.don ~|(%unsupported !!)
532+ %a ((hard (list ,@t)) q.q.don)
533+ %c (lurk dst p.q.don)
534+ ==
535+ ==
536+```
537+
538+This is defined in `arvo/hoon.hoon` for historical reasons which are
539+likely no longer applicable. Since the `++umph` structure will likely
540+change we convert clay to be a typed filesystem, we'll only give a
541+high-level description of this process. If we have a `%a` udon, then
542+we're performing a trivial replace, so we produce simply `q.q.don`. If
543+we have a `%c` udon, then we're performing a list merge (as in, for
544+example, lines of text). The merge is performed by `++lurk`.
545+
546+```hoon
547+ ++ lurk :: apply list patch
548+ |* [hel=(list) rug=(urge)]
549+ ^+ hel
550+ =+ war=`_hel`~
551+ |- ^+ hel
552+ ?~ rug (flop war)
553+ ?- -.i.rug
554+ &
555+ %= $
556+ rug t.rug
557+ hel (slag p.i.rug hel)
558+ war (weld (flop (scag p.i.rug hel)) war)
559+ ==
560+ ::
561+ |
562+ %= $
563+ rug t.rug
564+ hel =+ gur=(flop p.i.rug)
565+ |- ^+ hel
566+ ?~ gur hel
567+ ?>(&(?=(^ hel) =(i.gur i.hel)) $(hel t.hel, gur t.gur))
568+ war (weld q.i.rug war)
569+ ==
570+ ==
571+```
572+
573+We accumulate our final result in `war`. If there's nothing more in our
574+list of merge instructions (unces), we just reverse `war` and produce
575+it. Otherwise, we process another unce. If the unce is of type `&`, then
576+we have `p.i.rug` lines of no changes, so we just copy them over from
577+`hel` to `war`. If the unice is of type `|`, then we verify that the
578+source lines (in `hel`) are what we expect them to be (`p.i.rug`),
579+crashing on failure. If they're good, then we append the new lines in
580+`q.i.rug` onto `war`.
581+
582+And that's really it. List merges are pretty easy. Anyway, if you
583+recall, we were discussing `++checkout-ankh`.
584+
585+```hoon
586+ ++ checkout-ankh :: checkout-ankh:ze
587+ |= hat=(map path lobe) :: checkout commit
588+ ^- ankh
589+ %- cosh
590+ %+ roll (~(tap by hat) ~)
591+ |= [[pat=path bar=lobe] ank=ankh]
592+ ^- ankh
593+ %- cosh
594+ ?~ pat
595+ =+ zar=(lobe-to-noun bar)
596+ ank(q [~ (sham zar) zar])
597+ =+ nak=(~(get by r.ank) i.pat)
598+ %= ank
599+ r %+ ~(put by r.ank) i.pat
600+ $(pat t.pat, ank (fall nak _ankh))
601+ ==
602+```
603+
604+If the path is null, then we calculate `zar`, the raw data at the path
605+`pat` in this version. We produce the given ankh with the correct data.
606+
607+Otherwise, we try to get the child we're looking at from our parent
608+ankh. If it's already been created, this succeeds; otherwise, we simply
609+create a default blank ankh. We place ourselves in our parent after
610+recursively computing our children.
611+
612+This algorithm really isn't that complicated, but it may not be
613+immediately obvious why it works. An example should clear everything up.
614+
615+Suppose `hat` is a map of the following information.
616+
617+```
618+ /greeting --> "customary upon meeting"
619+ /greeting/english --> "hello"
620+ /greeting/spanish --> "hola"
621+ /greeting/russian/short --> "привет"
622+ /greeting/russian/long --> "Здравствуйте"
623+ /farewell/russian --> "до свидания"
624+```
625+
626+Furthermore, let's say that we process them in this order:
627+
628+```
629+ /greeting/english
630+ /greeting/russian/short
631+ /greeting/russian/long
632+ /greeting
633+ /greeting/spanish
634+ /farewell/russian
635+```
636+
637+Then, the first path we process is `/greeting/english` . Since our path
638+is not null, we try to get `nak`, but because our ankh is blank at this
639+point it doesn't find anything. Thus, update our blank top-level ankh
640+with a child `%greeting`. and recurse with the blank `nak` to create the
641+ankh of the new child.
642+
643+In the recursion, we our path is `/english` and our ankh is again blank.
644+We try to get the `english` child of our ankh, but this of course fails.
645+Thus, we update our blank `/greeting` ankh with a child `english`
646+produced by recursing.
647+
648+Now our path is null, so we call `++lobe-to-noun` to get the actual
649+data, and we place it in the brand-new ankh.
650+
651+Next, we process `/greeting/russian/short`. Since our path is not null,
652+we try to get the child named `%greeting`, which does exist since we
653+created it earlier. We put modify this child by recursing on it. Our
654+path is now `/russian/short`, so we look for a `%russian` child in our
655+`/greeting` ankh. This doesn't exist, so we add it by recursing. Our
656+path is now `/short`, so we look for a `%short` child in our
657+`/greeting/russian` ankh. This doesn't exist, so we add it by recursing.
658+Now our path is null, so we set the contents of this node to `"привет"`,
659+and we're done processing this path.
660+
661+Next, we process `/greeting/russian/long`. This proceeds similarly to
662+the previous except that now the ankh for `/greeting/russian` already
663+exists, so we simply reuse it rather than creating a new one. Of course,
664+we still must create a new `/greeting/russian/long` ankh.
665+
666+Next, we process `/greeting`. This ankh already exists, so after we've
667+recursed once, our path is null, and our ankh is not blank -- it already
668+has two children (and two grandchildren). We don't touch those, though,
669+since a node may be both a file and a directory. We just add the
670+contents of the file -- "customary upon meeting" -- to the existing
671+ankh.
672+
673+Next, we process `/greeting/spanish`. Of course, the `/greeting` ankh
674+already exists, but it doesn't have a `%spanish` child, so we create
675+that, taking care not to disturb the contents of the `/greeting` file.
676+We put "hola" into the ankh and call it good.
677+
678+Finally, we process `/farewell/russian`. Here, the `/farewell` ankh
679+doesn't exist, so we create it. Clearly the newly-created ankh doesn't
680+have any children, so we have to add a `%russian` child, and in this
681+child we put our last content -- "до свидания".
682+
683+We hope it's fairly obvious that the order we process the paths doesn't
684+affect the final ankh tree. The tree will be constructed in a very
685+different order depending on what order the paths come in, but the
686+resulting tree is independent of order.
687+
688+At any rate, we were talking about something important, weren't we? If
689+you recall, that concludes our discussion of `++rewind`, which was
690+called from `++read-at-aeon`. In summary, `++rewind` returns a context
691+in which our current state is (very nearly) as it was when the specified
692+version of the desk was the head. This allows `++read-at-aeon` to call
693+`++read` to read the requested information.
694+
695+```hoon
696+ ++ read :: read:ze
697+ |= mun=mood :: read at point
698+ ^- (unit)
699+ ?: ?=(%v p.mun)
700+ [~ `dome`+<+<.read]
701+ ?: &(?=(%w p.mun) !?=(%ud -.q.mun))
702+ ?^(r.mun ~ [~ let])
703+ ?: ?=(%w p.mun)
704+ =+ ^= yak
705+ %- tako-to-yaki
706+ %- aeon-to-tako
707+ let
708+ ?^(r.mun ~ [~ [t.yak (forge-nori yak)]])
709+ ::?> ?=(^ hit) ?^(r.mun ~ [~ i.hit]) :: what do?? need [@da nori]
710+ (query(ank ank:(descend-path:(zu ank) r.mun)) p.mun)
711+```
712+
713+If we're requesting the dome, then we just return that immediately.
714+
715+If we're requesting the revision number of the desk and we're not
716+requesting it by number, then we just return the current number of this
717+desk. Note of course that this was really already handled in
718+`++read-at-aeon`.
719+
720+If we're requesting a `%w` with a specific revision number, then we do
721+something or other with the commit there. It's kind of weird, and it
722+doesn't seem to work, so we'll ignore this case.
723+
724+Otherwise, we descend into the ankh tree to the given path with
725+`++descend-path:zu`, and then we handle specific request in `++query`.
726+
727+```hoon
728+ ++ descend-path :: descend recursively
729+ |= way=path
730+ ^+ +>
731+ ?~(way +> $(way t.way, +> (descend i.way)))
732+```
733+
734+This is simple recursion down into the ankh tree. `++descend` descends
735+one level, so this will eventually get us down to the path we want.
736+
737+```hoon
738+ ++ descend :: descend
739+ |= lol=@ta
740+ ^+ +>
741+ =+ you=(~(get by r.ank) lol)
742+ +>.$(ram [lol ram], ank ?~(you [*cash ~ ~] u.you))
743+```
744+
745+`ram` is the path that we're at, so to descend one level we push the
746+name of this level onto that path. We update the ankh with the correct
747+one at that path if it exists; else we create a blank one.
748+
749+Once we've decscended to the correct level, we need to actually deal
750+with the request.
751+
752+```hoon
753+ ++ query :: query:ze
754+ |= ren=?(%u %v %x %y %z) :: endpoint query
755+ ^- (unit ,*)
756+ ?- ren
757+ %u [~ `rang`+<+>.query]
758+ %v [~ `dome`+<+<.query]
759+ %x ?~(q.ank ~ [~ q.u.q.ank])
760+ %y [~ as-arch]
761+ %z [~ ank]
762+ ==
763+```
764+
765+Now that everything's set up, it's really easy. If they're requesting
766+the rang, dome, or ankh, we give it to them. If the contents of a file,
767+we give it to them if it is in fact a file. If the `arch`, then we
768+calculate it with `++as-arch`.
769+
770+```hoon
771+ ++ as-arch :: as-arch:ze
772+ ^- arch :: arch report
773+ :+ p.ank
774+ ?~(q.ank ~ [~ p.u.q.ank])
775+ |- ^- (map ,@ta ,~)
776+ ?~ r.ank ~
777+ [[p.n.r.ank ~] $(r.ank l.r.ank) $(r.ank r.r.ank)]
778+```
779+
780+This very simply strips out all the "real" data and returns just our own
781+hash, the hash of the file contents (if we're a file), and a map of the
782+names of our immediate children.
783+
arvo/clay/local-sub.mdnew file+249
@@ -0,0 +1,249 @@
1++++
2+title = "Local Subscriptions"
3+weight = 6
4+template = "doc.html"
5++++
6+
7+Parts of this document may be out of date as of March 2021.
8+
9+A subscription to a range of revisions of a desk initially follows the
10+same path that a single read does. In `++aver`, we checked the head of
11+the given rave. If the head was `&`, then it was a single request, so we
12+handled it above. If `|`, then we handle it with the following code.
13+
14+```hoon
15+ =+ nab=(~(case-to-aeon ze lim dom ran) p.p.rav)
16+ ?~ nab
17+ ?> =(~ (~(case-to-aeon ze lim dom ran) q.p.rav))
18+ (duce hen (rive rav))
19+ =+ huy=(~(case-to-aeon ze lim dom ran) q.p.rav)
20+ ?: &(?=(^ huy) |((lth u.huy u.nab) &(=(0 u.huy) =(0 u.nab))))
21+ (blub hen)
22+ =+ top=?~(huy let.dom u.huy)
23+ =+ sar=(~(lobes-at-path ze lim dom ran) u.nab r.p.rav)
24+ =+ ear=(~(lobes-at-path ze lim dom ran) top r.p.rav)
25+ =. +>.$
26+ ?: =(sar ear) +>.$
27+ =+ fud=(~(make-nako ze lim dom ran) u.nab top)
28+ (bleb hen u.nab fud)
29+ ?^ huy
30+ (blub hen)
31+ =+ ^= ptr ^- case
32+ [%ud +(let.dom)]
33+ (duce hen `rove`[%| ptr q.p.rav r.p.rav ear])
34+ ==
35+```
36+
37+Recall that `++case-to-aeon:ze` produces the revision number that a case
38+corresponds to, if it corresponds to any. If it doesn't yet correspond
39+to a revision, then it produces null.
40+
41+Thus, we first check to see if we've even gotten to the beginning of the
42+range of revisions requested. If not, then we assert that we haven't yet
43+gotten to the end of the range either, because that would be really
44+strange. If not, then we immediately call `++duce`, which, if you
45+recall, for a local request, simply puts this duct and rove into our
46+cult `qyx`, so that we know who to respond to when the revision does
47+appear.
48+
49+If we've already gotten to the first revision, then we can produce some
50+content immediately. If we've also gotten to the final revision, and
51+that revision is earlier than the start revision, then it's a bad
52+request and we call `++blub`, which tells the subscriber that his
53+subscription will not be satisfied.
54+
55+Otherwise, we find the data at the given path at the beginning of the
56+subscription and at the last available revision in the subscription. If
57+they're the same, then we don't send a notification. Otherwise, we call
58+`++gack`, which creates the `++nako` we need to produce. We call
59+`++bleb` to actually produce the information.
60+
61+If we already have the last requested revision, then we also tell the
62+subscriber with `++blub` that the subscription will receive no further
63+updates.
64+
65+If there will be more revisions in the subscription, then we call
66+`++duce`, adding the duct to our subscribers. We modify the rove to
67+start at the next revision since we've already handled all the revisions
68+up to the present.
69+
70+We glossed over the calls to `++lobes-at-path`, `++make-nako`, and
71+`++bleb`, so we'll get back to those right now. `++bleb` is simple, so
72+we'll start with that.
73+
74+```hoon
75+ ++ bleb :: ship sequence
76+ |= [hen=duct ins=@ud hip=nako]
77+ ^+ +>
78+ (blab hen [%w [%ud ins] ~] hip)
79+```
80+
81+We're given a duct, the beginning revision number, and the nako that
82+contains the updates since that revision. We use `++blab` to produce
83+this result to the subscriber. The case is `%w` with a revision number
84+of the beginning of the subscription, and the data is the nako itself.
85+
86+We call `++lobes-at-path:ze` to get the data at the particular path.
87+
88+```hoon
89+ ++ lobes-at-path :: lobes-at-path:ze
90+ |= [oan=aeon pax=path] :: data at path
91+ ^- (map path lobe)
92+ ?: =(0 oan) ~
93+ %- mo
94+ %+ skim
95+ %. ~
96+ %~ tap by
97+ =< q
98+ %- tako-to-yaki
99+ %- aeon-to-tako
100+ oan
101+ |= [p=path q=lobe]
102+ ?| ?=(~ pax)
103+ ?& !?=(~ p)
104+ =(-.pax -.p)
105+ $(p +.p, pax +.pax)
106+ == ==
107+```
108+
109+At revision zero, the theoretical common revision between all
110+repositories, there is no data, so we produce null.
111+
112+We get the list of paths (paired with their lobe) in the revision
113+referred to by the given number and we keep only those paths which begin
114+with `pax`. Converting to a map, we now have a map from the subpaths at
115+the given path to the hash of their data. This is simple and efficient
116+to calculate and compare to later revisions. This allows us to easily
117+tell if a node or its children have changed.
118+
119+Finally, we will describe `++make-nako:ze`.
120+
121+```hoon
122+ ++ make-nako :: gack a through b
123+ |= [a=aeon b=aeon]
124+ ^- [(map aeon tako) aeon (set yaki) (set blob)]
125+ :_ :- b
126+ =- [(takos-to-yakis -<) (lobes-to-blobs ->)]
127+ %+ reachable-between-takos
128+ (~(get by hit) a) :: if a not found, a=0
129+ (aeon-to-tako b)
130+ ^- (map aeon tako)
131+ %- mo %+ skim (~(tap by hit) ~)
132+ |= [p=aeon *]
133+ &((gth p a) (lte p b))
134+```
135+
136+We need to produce four things -- the numbers of the new commits, the
137+number of the latest commit, the new commits themselves, and the new
138+data itself.
139+
140+The first is fairly easy to produce. We simply go over our map of
141+numbered commits and produce all those numbered greater than `a` and not
142+greater than `b`.
143+
144+The second is even easier to produce -- `b` is clearly our most recent
145+commit.
146+
147+The third and fourth are slightly more interesting, though not too
148+terribly difficult. First, we call `++reachable-between-takos`.
149+
150+```hoon
151+ ++ reachable-between-takos
152+ |= [a=(unit tako) b=tako] :: pack a through b
153+ ^- [(set tako) (set lobe)]
154+ =+ ^= sar
155+ ?~ a ~
156+ (reachable-takos r:(tako-to-yaki u.a))
157+ =+ yak=`yaki`(tako-to-yaki b)
158+ %+ new-lobes-takos (new-lobes ~ sar) :: get lobes
159+ |- ^- (set tako) :: walk onto sar
160+ ?: (~(has in sar) r.yak)
161+ ~
162+ =+ ber=`(set tako)`(~(put in `(set tako)`~) `tako`r.yak)
163+ %- ~(uni in ber)
164+ ^- (set tako)
165+ %+ roll p.yak
166+ |= [yek=tako bar=(set tako)]
167+ ^- (set tako)
168+ ?: (~(has in bar) yek) :: save some time
169+ bar
170+ %- ~(uni in bar)
171+ ^$(yak (tako-to-yaki yek))
172+```
173+
174+We take a possible starting commit and a definite ending commit, and we
175+produce the set of commits and the set of data between them.
176+
177+We let `sar` be the set of commits reachable from `a`. If `a` is null,
178+then obviously no commits are reachable. Otherwise, we call
179+`++reachable-takos` to calculate this.
180+
181+```hoon
182+ ++ reachable-takos :: reachable
183+ |= p=tako :: XX slow
184+ ^- (set tako)
185+ =+ y=(tako-to-yaki p)
186+ =+ t=(~(put in _(set tako)) p)
187+ %+ roll p.y
188+ |= [q=tako s=_t]
189+ ?: (~(has in s) q) :: already done
190+ s :: hence skip
191+ (~(uni in s) ^$(p q)) :: otherwise traverse
192+```
193+
194+We very simply produce the set of the given tako plus its parents,
195+recursively.
196+
197+Back in `++reachable-between-takos`, we let `yak` be the yaki of `b`,
198+the ending commit. With this, we create a set that is the union of `sar`
199+and all takos reachable from `b`.
200+
201+We pass `sar` into `++new-lobes` to get all the lobes referenced by any
202+tako referenced by `a`. The result is passed into `++new-lobes-takos` to
203+do the same, but not recomputing those in already calculated last
204+sentence. This produces the sets of takos and lobes we need.
205+
206+```hoon
207+ ++ new-lobes :: object hash set
208+ |= [b=(set lobe) a=(set tako)] :: that aren't in b
209+ ^- (set lobe)
210+ %+ roll (~(tap in a) ~)
211+ |= [tak=tako bar=(set lobe)]
212+ ^- (set lobe)
213+ =+ yak=(tako-to-yaki tak)
214+ %+ roll (~(tap by q.yak) ~)
215+ |= [[path lob=lobe] far=_bar]
216+ ^- (set lobe)
217+ ?~ (~(has in b) lob) :: don't need
218+ far
219+ =+ gar=(lobe-to-blob lob)
220+ ?- -.gar
221+ %direct (~(put in far) lob)
222+ %delta (~(put in $(lob q.gar)) lob)
223+ %indirect (~(put in $(lob s.gar)) lob)
224+ ==
225+```
226+
227+Here, we're creating a set of lobes referenced in a commit in `a`. We
228+start out with `b` as the initial set of lobes, so we don't need to
229+recompute any of the lobes referenced in there.
230+
231+The algorithm is pretty simple, so we won't bore you with the details.
232+We simply traverse every commit in `a`, looking at every blob referenced
233+there, and, if it's not already in `b`, we add it to `b`. In the case of
234+a direct blob, we're done. For a delta or an indirect blob, we
235+recursively add every blob referenced within the blob.
236+
237+```hoon
238+ ++ new-lobes-takos :: garg & repack
239+ |= [b=(set lobe) a=(set tako)]
240+ ^- [(set tako) (set lobe)]
241+ [a (new-lobes b a)]
242+```
243+
244+Here, we just update the set of lobes we're given with the commits we're
245+given and produce both sets.
246+
247+This concludes our discussion of a local subscription.
248+
249+
arvo/clay/using.mdnew file+209
@@ -0,0 +1,209 @@
1++++
2+title = "Using Clay"
3+weight = 3
4+template = "doc.html"
5++++
6+
7+This document covers common uses of Clay for developers. Some parts of it may be
8+out of date as of March 2021.
9+
10+### Reading and Subscribing
11+
12+When reading from Clay, there are three types of requests. A
13+`%sing` request asks for data at single revsion. A `%next`
14+request asks to be notified the next time there's a change to
15+given file. A `%many` request asks to be notified on every
16+change in a desk for a range of changes.
17+
18+For `%sing` and `%next`, there are generally three things to be
19+queried. A `%u` request simply checks for the existence of a
20+file at a path. A `%x` request gets the data in the file at a
21+path. A `%y` request gets a hash of the data in the file at the
22+path combined with all its children and their data. Thus, `%y`
23+of a node changes if it or any of its children change.
24+
25+A `%sing` request is fulfilled immediately if possible. If the
26+requested revision is in the future, or is on another ship for
27+which we don't have the result cached, we don't respond
28+immediately. If the requested revision is in the future, we wait
29+until the revision happens before we respond to the request. If
30+the request is for data on another ship, we pass on the request
31+to the other ship. In general, Clay subscriptions, like most
32+things in Urbit, aren't guaranteed to return immediately.
33+They'll return when they can, and they'll do so in a
34+referentially transparent manner.
35+
36+A `%next` request checks query at the given revision, and it
37+produces the result of the query the next time it changes, along
38+with the revsion number when it changes. Thus, a `%next` of a
39+`%u` is triggered when a file is added or deleted, a `%next` of a
40+`%x` is triggered when a file is added, deleted, or changed, and
41+a `%next` of a `%y` is triggered when a file or any of its
42+children is added, deleted, or changed.
43+
44+A `%many` request is triggered every time the given desk has a
45+new revision. Unlike a `%next`, a `%many` has both a start and
46+an end revsion, after which it stops returning. For `%next`, a
47+single change is reported, and if the caller wishes to hear of
48+the next change, it must resubscribe. For `%many`, every revsion
49+from the start to the end triggers a response. Since a `%many`
50+request doesn't ask for any particular data, there aren't `%u`,
51+`%x`, and `%y` versions for it.
52+
53+For further information, see [Local Reads](@/docs/arvo/clay/local-reads.md),
54+[Local Subscriptions](@/docs/arvo/clay/local-sub.md), and [Foreign
55+Requests](@/docs/arvo/clay/foreign.md)
56+
57+### Unix sync
58+
59+One of the primary functions of clay is as a convenient user
60+interface. While tools exist to use clay from within urbit, it's
61+often useful to be able to treat clay like any other filesystem
62+from the Unix perspective -- to "mount" it, as it were.
63+
64+From urbit, you can run `|mount /path/to/directory %mount-point`,
65+and this will mount the given clay directory to the mount-point
66+directory in Unix. Every file is converted to `%mime` before it's
67+written to Unix, and converted back when read from Unix. The
68+entire directory is watched (a la Dropbox), and every change is
69+committed once you run `|commit %mount-point`.
70+
71+### Merging
72+
73+This section is up to date as of March 2021.
74+
75+Usage:
76+```
77+|merge %destination-desk ~source-ship %source-desk
78+|merge %destination-desk ~source-ship %source-desk, =gem %strategy
79+|merge %destination-desk ~source-ship %source-desk, =cas ud+5
80+```
81+
82+Clay supports various merge strategies. A "commit" is a snapshot of
83+the files with a list of parents plus a date. Most commits have
84+one parent; a "merge" commit is a commit with two parents. The
85+%home desk starts with an initial commit with no parents; commits
86+with several parents ("octopus merges") are possible but we don't
87+generate them right now.
88+
89+Unless otherwise specified, all of the following create a new commit
90+with the source and destination commits as parents.
91+
92+Several strategies need a "merge-base". They find it by identifying
93+the most recent common ancestor of the two desks. If none, fail
94+with `%merge-no-merge-base`; if there are two or more, pick one.
95+
96+#### Strategies
97+
98+**`%init`**: the only way to create a desk. Not a true merge, since it
99+simply assigns the source commit to the destination.
100+
101+**`%fine`**: if source or destination are in the ancestry of each other,
102+use the newer one; else abort. If the destination is ahead of the
103+source, succeed but do nothing. If the source is ahead of the
104+destination, assign the next revision number to the source commit.
105+Some call this "fast-forward".
106+
107+**`%meet`**: combine changes, failing if both sides changed the same file.
108+Specifically, take diff(merge-base,source) and
109+diff(merge-base,destination) and combine them as long as those diffs
110+touch different files.
111+
112+**`%mate`**: combine changes, failing if both sides changed the same part
113+of a file. Identical to `%meet`, except that some marks, like `%hoon`,
114+allow intelligent merge of changes to different parts of a file.
115+
116+**`%meld`**: combine changes; if both sides changed the same part of a
117+file, use the version of the file in the merge-base.
118+
119+**`%only-this`**: create a merge commit with exactly the contents of the
120+destination desk.
121+
122+**`%only-that`**: create a merge commit with exactly the contents of the
123+source commit.
124+
125+**`%take-this`**: create a merge commit with exactly the contents of the
126+destination desk except take any files from the source commit which
127+are not in the destination desk.
128+
129+**`%take-that`**: create a merge commit with exactly the contents of the
130+source commit except preserve any files from the destination desk
131+which are not in the source commit.
132+
133+**`%meet-this`**: merge as in `%meet`, except if both sides changed the same
134+file, use the version in the destination desk.
135+
136+**`%meet-that`**: merge as in `%meet`, except if both sides changed the same
137+file, use the version in the source commit.
138+
139+#### Examples and notes:
140+
141+The most common merge strategy is %mate, which is a normal 3-way
142+merge which aborts on conflict.
143+
144+`%take-that` is useful to "force" an OTA. After running `%take-that`,
145+you're guaranteed to have exactly the files in the source commit plus
146+any files you separately added.
147+
148+We speak of merging into a destination *desk* from a source *commit*
149+because while you can only merge on top of a desk, you can merge from
150+historical commits. For example,
151+```
152+|merge %old our %home, =cas ud+5, =gem %init
153+```
154+will create a new desk called `%old` with the 5th commit in `%home`.
155+You can revert the contents of a desk to what they were yesterday
156+with
157+```
158+|merge %home our %home, =cas da+(sub now ~d1), =gem %only-that
159+```
160+
161+Note this is a normal `%only-that merge`, which means you're creating a
162+*new* commit with the old *contents*.
163+
164+`%meld` is rarely used on its own, however if you specify `%auto` or
165+omit the merge strategy, `%kiln` will run a `%meld` merge into a scratch
166+desk and then annotate the conflicts there.
167+
168+If you resolve merge conflicts manually, for example by mounting the
169+desks, copying the files in Unix and then running `|commit`, you
170+should usually run an `%only-this merge`. This will not change the
171+newly-fixed contents of your desk, but it will record that the merge
172+happened so that those conflicts don't reappear in later merges.
173+
174+If you get a `%merge-no-merge-base` error, this means you're trying to
175+merge two desks which have no common ancestors. You need to give
176+them a common ancestor by choosing a merge strategy which doesn't
177+need a merge-base, like `%only-this`, `%only-that`, `%take-this`, or
178+`%take-that`.
179+
180+`%take-this` could be useful to install 3rd party software, but you
181+couldn't get subsequent updates this way, since the files would
182+already exist in the destination desk. Something like "take only
183+the files which aren't in my OTA source or any other 3rd party app"
184+would be basically correct. This would require a parameter listing
185+the desks to not conflict with.
186+
187+`%meet-this` and `%meet-that` imply the existence of `%mate-this` and
188+`%mate-that`, but those don't exist yet.
189+
190+### Autosync
191+
192+Tracking and staying in sync with another desk is another
193+fundamental operation. We call this "autosync". This doesn't mean
194+simply mirroring a desk, since that wouldn't allow local changes.
195+We simply want to apply changes as they are made upstream, as
196+long as there are no conflicts with local changes.
197+
198+This is implemented by watching the other desk, and, when it has
199+changes, merging these changes into our desk with the usual merge
200+strategies.
201+
202+Note that it's quite reasonable for two desks to be autosynced to
203+each other. This results in any change on one desk being mirrored
204+to the other and vice versa.
205+
206+Additionally, it's fine to set up an autosync even if one desk,
207+the other desk, or both desks do not exist. The sync will be
208+activated when the upstream desk comes into existence and will
209+create the downstream desk if needed.
arvo/concepts/_index.mdnew file+12
@@ -0,0 +1,12 @@
1++++
2+title = "Concepts"
3+weight = 100
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6++++
7+
8+Other concepts related to the way Arvo works.
9+
10+## [Subscriptions](@/docs/arvo/concepts/subscriptions.md)
11+
12+Urbit relies heavily on subscriptions throughout the stack. We strongly prefer reactive data flow compared to querying or polling, which is why for example our equivalent to git natively supports subscriptions to its data.
arvo/concepts/subscriptions.mdnew file+162
@@ -0,0 +1,162 @@
1++++
2+title = "Subscriptions"
3+weight = 50
4+template = "doc.html"
5++++
6+
7+Urbit relies heavily on subscriptions throughout the stack. We strongly
8+prefer reactive data flow compared to querying or polling, which is why
9+for example our equivalent to git natively supports subscriptions to its
10+data.
11+
12+We have many application-level styles of subscription, but we only have
13+three true subscription types in Arvo, named for the vane they're
14+implemented in: Clay subscriptions (filesystem), Gall subscriptions
15+(applications), and Jael subscriptions (Urbit ID info). They're at
16+three different points in the idea maze of subscriptions, and we'll
17+encounter each of them here.
18+
19+For our purposes, a subscription is a stream of events from a publisher
20+to a subscriber, where (1) the publisher has indicated interest in that
21+stream, (2) any update sent to one subscriber is sent to all subscribers
22+on the same stream, and (3) when the publisher has a new update ready,
23+they send it immediately to their subscribers instead of waiting for a
24+later request.
25+
26+## Basic properties
27+
28+### Exactly-once updates
29+
30+Some subscriptions need the subscriber to receive each update separately
31+instead of collapsing them into a single diff. Sometimes a subscription
32+is really a sequence of commands, in which case there's no meaningful
33+way to collapse them. Similarly, software updates may be expected to be
34+applied in order.
35+
36+### Syncing data
37+
38+Other times, it's more natural to think of a subscription as
39+communicating a data structure, where the only goal is to keep the data
40+structure on the subscriber's side up-to-date with what's on the
41+publisher's side. In this case, it's perfectly fine to collapse several
42+updates into one large update, or even to resend the entire data
43+structure. Partial updates exist only as an optimization.
44+
45+For this sort of subscription, we commonly use terms like "diff" instead
46+of "message" or "update", and we say that we "apply a diff" instead of
47+"process an update". We also often identify the subscription with the
48+data structure itself.
49+
50+## Memory pressure
51+
52+Naively implemented, subscriptions pose a memory leak risk if the
53+subscriber can't receive updates as fast as the publisher wants to send
54+them. This commonly happens when the subscriber goes offline for an
55+extended period of time (possibly forever; especially for comets). It's
56+sufficient to bound the amount of memory dedicated to any particular
57+subscriber.
58+
59+In a synchronous system, you don't have to worry about what happens if
60+one side or the other ceases to be available. All of our subscriptions,
61+though, can happen between ships.
62+
63+### Small data
64+
65+For particularly low-volume subscriptions, it may be acceptable to
66+ignore the problem. Jael uses this approach, since the only time it's
67+used across ships is to update moon keys, which is very low-volume and
68+less than 1KB per update. If these subscriptions are used for more,
69+this strategy will have to be revisited.
70+
71+### Buffers
72+
73+A common solution to this problem is the venerable buffer. If more than
74+N updates need to be sent, start dropping updates. There are several
75+options for what to do when the buffer is full and the publisher wishes
76+to send another message:
77+
78+- Drop the oldest message. Particularly suitable for systems where new
79+messages obsolete old ones. For example, if you just need the latest
80+ticker price for an asset, you could use a buffer size of one and
81+replaced it any time you have a new price.
82+
83+- Don't add the new message to the buffer. Semantically this is usually
84+less helpful, but mechanically it can be simpler and reduce memory
85+churn, since the buffer stops changing and new messages are simply
86+ignored.
87+
88+- Drop the newest message and close the subscription. Unlike the
89+previous two, this is compatible with the principle of exactly-once
90+messaging. Specifically, it preserves the guarantee that you won't
91+receive two non-consecutive subscription updates, at the cost of making
92+you resubscribe if you fall behind.
93+
94+Gall subscriptions use the last of these. The buffer is bounded by a
95+simple heuristic, and when a subscription exceeds that buffer, it is
96+closed and the app is expected to resubscribe when they come back
97+online. Note that even though the subscription is closed, messages in
98+flight cannot be removed until they've been acknowledged since Ames
99+guarantees exactly-once messaging, so those last few messages will be
100+stuck in memory until the subscriber comes back online.
101+
102+Buffers are commonly bounded by size, but this puts constraints on the
103+types of messages may be sent. They may also be bounded in time: if the
104+subscriber stops taking messages for at least X time, the buffer is
105+full. Gall taks a hybrid approach; currently the heuristic is that the
106+buffer counts as full if it has at least five messages and it has been
107+30 seconds since a message was acknowledged.
108+
109+### One at a time
110+
111+Another scheme is to avoid multi-message subscriptions. Instead of
112+allowing the subscriber to subscribe to all future updates on a path,
113+allow them to "subscribe" to the *next* update only. When they get that
114+update, they subscribe to the new next update, so that they ultimately
115+get every message.
116+
117+Commonly this is implemented where each update is given a version
118+number, and every time you hear update N you request update N+1 (even
119+though you won't get an answer for an indeterminate period of time).
120+
121+This is near the theoretical ideal for memory usage, since you'll never
122+queue up several messages to send to the subscriber.
123+
124+It also encourages processing each update in order rather than zooming
125+forward from time to time. It's possible (if a little awkward) to
126+simulate this with buffers though, and it's possible to allow zooming
127+forward in the one-at-a-time scheme by having the requests be "most
128+recent after update N" instead of "next after update N".
129+
130+This scheme is at its strongest, then, when you're already storing
131+intermediate states or updates, or when you don't care about
132+intermediate states and always send the most recent one. Otherwise,
133+buffers are a convenient place to temporarily store updates that you
134+don't want to store internally. Of course, if it's semantically
135+important that you give each update separately, buffers won't save you
136+from having to store the intermediate updates, since they may fill up.
137+
138+Another conceptual advantage is that it has no notion of "connectivity".
139+It operates forever in a single mode. By contrast, buffer-based
140+solutions must keep track of whether the buffer is full and react to
141+that. This increases complexity in the system, and complexity is the
142+great evil.
143+
144+The biggest disadvantage of this system is that it takes much longer to
145+process many small updates. With buffers, the publisher could have a
146+dozen small updates in flight at the same time, while in this scheme
147+they would only send one at a time, waiting for a response between each
148+one. Losing this pipelining can be quite significant for some
149+applications, but for low-volume subscriptions (certainly anything that
150+updates less than once per minute) this will have no noticeable effect.
151+
152+Clay uses this scheme. It's low-volume, it stores all previous states
153+anyway (since it's a revision-control system), and it's sometimes
154+important to get updates one at a time (for example when downloading OTA
155+software updates). Ships that send OTA updates often have many ships
156+subscribed to them, and the updates themselves may be large, so it's
157+important they don't queue up when ships inevitably disappear.
158+
159+I tend to think most Gall subscriptions should follow this pattern as
160+well. Our most latency-sensitive subscriptions are chat messages, and
161+while I haven't tested it, I would guess that even those wouldn't be
162+affected by this scheme.
arvo/dill/dill-api.md+3−3
@@ -68,7 +68,7 @@ Dill returns no `gift` in response to a `%blew` `task`.
6868### `%boot`
6969
7070This `task` is used only once, when Arvo first enters the [adult
71−stage](@/docs/arvo/arvo.md#structural-interface-core). Dill is
71+stage](@/docs/arvo/overview.md#structural-interface-core). Dill is
7272technically the first vane to be activated, via the `%boot` `task`, which then
7373send Jael (considered the the "true" first vane) an `%init` `task`, which then goes on to
7474call `%init` `task`s for other vanes (including Dill).
@@ -176,7 +176,7 @@ This `task` is not used.
176176### `%init`
177177
178178This `task` is called only once, when Arvo first enters the [adult
179−stage](@/docs/arvo/arvo.md#structural-interface-core). It performs
179+stage](@/docs/arvo/overview.md#structural-interface-core). It performs
180180initial setup for Dill, such as setting the width of the console.
181181
182182Note that this is not actually the first `task` passed to Dill - see [%boot](#%boot).
@@ -353,7 +353,7 @@ This `task` returns no `gift`s.
353353
354354This `task` toggles verbose mode for all of Arvo, which is located here since
355355Dill is the vane that prints errors. To be precise, `%verb` toggles the laconic
356−bit `lac` in the [Arvo state](@/docs/arvo/arvo.md#the-state).
356+bit `lac` in the [Arvo state](@/docs/arvo/overview.md#the-state).
357357
358358#### Accepts
359359
arvo/eyre/_index.md+9
@@ -4,3 +4,12 @@ weight = 50
44sort_by = "weight"
55template = "sections/docs/chapters.html"
66+++
7+
8+## [Overview](@/docs/arvo/eyre/eyre.md)
9+
10+A high-level overview of `eyre`, Urbit's HTTP server vane.
11+
12+## [Using Eyre](@/docs/arvo/eyre/using-eyre.md)
13+
14+How to use Urbit's HTTP API.
15+
development/integrating-api.md → arvo/eyre/using-eyre.mdrenamed+14−8
@@ -1,23 +1,29 @@
11+++
2−title = "Using the HTTP API"
3−description = "How to use Urbit's API."
2+title = "Using Eyre"
3+description = "How to work with eyre from outside Urbit."
44weight = 20
55template = "doc.html"
66+++
77
88This guide is aimed at developers who have a working knowledge of HTTP grammar (`PUT`, `GET`), and should not require any special knowledge of Urbit's internals. To learn more about a specific application within Urbit, please search for that with the docs once you have finished this guide.
99
10−## Authentication
10+## Prerequisites
1111
12−The first step in creating an application *on* Urbit (to be distinguished from an Urbit application) is to authenticate with the desired ship. This can be a planet, comet, or any other Urbit ship. For the purposes of this example, we will be running a "fakezod" on port 8080. Run this code, substituting the appropriate path to your Urbit binary:
12+You'll need a working development ship to follow along with this guide. It's
13+recommended that you set up a new "fakezod" on port 8080: Run this code,
14+substituting the appropriate path to your Urbit binary:
1315
1416```bash
1517/path/to/urbit -p 8080 -F zod
1618```
1719
18−(for the unfamiliar, this will create a folder named "zod" in your working directory, from which the ship will run. Use `/path/to/urbit -p 8080 zod` in the future)
20+For the unfamiliar, this will create a folder named "zod" in your working directory, from which the ship will run. Use `/path/to/urbit -p 8080 zod` in the future. For more information on this process, see our guide on [Environment Setup](@/docs/development/environment.md).
21+
22+## Authentication
1923
20−You can run `+code` in the dojo to get the key, but a fakezod's key is always `lidlut-tabwed-pillex-ridrup`. This is our password, our API token that we will use.
24+We'll authenticate with a code that can be retrieved from the dojo. You can run
25+`+code` in the dojo to obtain it, but a fakezod's code is always
26+`lidlut-tabwed-pillex-ridrup`.
2127
2228Run this code in your bash terminal (requires cURL):
2329
@@ -29,7 +35,7 @@ Let's explain what this does:
2935 - `-i` displays the headers, so that you can see the cookie that gets sent
3036 - `localhost:8080/~/login` is the URL to which you are POSTing. You will note this is also the URL you visit when you log into Landscape.
3137 - `-X POST` specifies that you are POSTing data, not GETting.
32− - `-d "password=lidlut-tabwed-pillex-ridrup"` specifies the key for your Urbit that we retrieved above. It is sent as form data, as if it were sent from an HTML form input field (which it is in Landscape)
38+ - `-d "password=lidlut-tabwed-pillex-ridrup"` specifies the code for your Urbit that we retrieved above. It is sent as form data, as if it were sent from an HTML form input field (which it is in Landscape)
3339
3440You should see the following:
3541
@@ -52,7 +58,7 @@ Take a look at the `set-cookie` line. This is now your session authentication, a
5258
5359At present there is no way to separate these parts — you must pass a cookie *as* a cookie. This string must be in the `Cookie` header. The `set-cookie` header is only used for this request upon response. It is what browsers expect when receiving a cookie.
5460
55−## Interacting with Urbit
61+## Interacting with Eyre
5662
5763Once authenticated, you will perform all your operations on a channel. You may open as many channels as needed using the same authentication token, but this will increase complexity and memory usage on your Urbit ship.
5864
arvo/ford/ford.md+214−2
@@ -5,7 +5,219 @@ template = "doc.html"
55aliases = ["/docs/learn/arvo/ford/"]
66+++
77
8−> This document is out of date as of 2020.07.20. In the meantime, see the [blog
9−> post](https://urbit.org/blog/ford-fusion/) about Ford Fusion.
8+*The Ford vane was refactored so drastically in 2020 that it was completely
9+ removed as a standalone vane, with its functionality merged into
10+ [clay](@/docs/arvo/clay/clay.md). The following is a reproduced [blog
11+ post](https://urbit.org/blog/ford-fusion/) that documents this transformation,
12+ which we called "Ford Fusion".*
13+
14+Ford Fusion was an overhaul of Urbit's over-the-air upgrade process and a rewrite of its build system. The new update system corrects a few long-standing bugs with the previous one, and the new build system is simpler, smaller (by around 5,000 lines), and easier to manage.
15+
16+Since deployment of Ford Fusion to the livenet in late June, over-the-air updates (OTAs) have been much smoother. Before Ford Fusion, it was common for an OTA to take several hours, use too much memory, and leave ships in inconsistent states. After Ford Fusion, multiple OTAs have been pushed out, including kernelspace changes, and most users didn't even notice.
17+
18+Urbit has always been able to update itself OTA, but this process has often been rocky. Updating an operating system kernel on-the-fly is a difficult problem in general, like performing heart replacement surgery on yourself while running a marathon. Code that allows Linux to update its kernel in this way became a startup called Ksplice, won multiple awards, and sold to Oracle. Even that, as impressive as it is, and as brilliant as its [programmers](https://nelhage.com) are, can only perform certain limited kinds of patches to the kernel.
19+
20+Urbit isn't exactly a traditional operating system, so the comparison is somewhat unfair, but the purpose of better architecture is to create unfair comparisons. In this case, because the Nock layer is frozen, upgrading everything above that layer is easier. Upgrades are also facilitated by pure-functional semantics, transactional event processing, a type system oriented toward concrete data, and orthogonal persistence. These features make it feasible for Urbit to upgrade
21+itself in the general case, not just some special cases.
22+
23+Ford Fusion has fixed the major upgrade issues of the past by guaranteeing three properties that in retrospect are obvious requirements, but, like much of Urbit, took many years and rewrites to identify as such:
24+- Atomic: the update should complete or fail in one transaction. If it
25+ fails, the system shouldn't get stuck.
26+- Self-contained: there must be no implicit dependencies or hysteresis
27+ (dependence on previous system states) when building the new software
28+ from source.
29+- Ordered: updates must be monotonically sequenced from the system's
30+ lowest layer to highest.
31+
32+Let’s walk through them one by one.
33+
34+### Atomic
35+
36+In previous versions of Urbit, updates failed atomicity by deferring parts of the update to later events, which are separate transactions that can fail independently. Generally, each deferral causes an exponential increase in the number of failure states that needed to be handled.
37+
38+We've learned that asynchronicity is an entropic state. A system will tend toward more asynchronicity over time unless effort is put into keeping it synchronous. [As Jonathan Blow has noted](https://youtu.be/pW-SOdj4Kkk?t=2547), the language server protocol has turned every editor plugin into a distributed system, since now it has to communicate asynchronously with the main editor process.
39+
40+Consider an update system that took multiple Arvo events to complete. An ad-hoc higher-level transaction system would need to be built to roll back the effects of the first few events in case of failure. It’s important for various parts of the system to be able to emit effects on upgrade; since those effects would need to be rolled back if a later event in this upgrade fails, the system would need to maintain a queue of those events and only apply them once all the other upgrade events have completed.
41+
42+Note that the asynchronicity has now spread. Some effects that would normally be guaranteed to be processed synchronously might now be asynchronous. Entropy has begun to take hold, chipping away at the set of invariants the system is capable of guaranteeing.
43+
44+This observation is not purely theoretical. False modularity was the cause of internal asynchronicity in Clay where it had to wait for responses in a complex dance with Ford, which was another vane (Arvo kernel module); moving Ford into Clay allowed function calls that were synchronous from Clay’s perspective, which allowed further simplifications, culminating in about a twenty percent reduction of source code size of the Arvo kernelspace.
45+
46+[Steve Yegge's "platform
47+rant"](https://gist.github.com/chitchcock/1281611) describes a Bezosian
48+edict prohibiting synchronous communication among modules through direct
49+linking. This can be seen as an acknowledgment of the difficulty Amazon
50+was going to have when it needed to turn internal services external. If
51+your software needs to run in hell, build it that way from the start.
52+
53+An Urbit ship is not an enterprise SaaS product and does not need to run in this hell; it exists for just one person, with natural pressure pushing it in the opposite direction from Amazon’s web services. Instead of needing a ship’s state and functionality sharded into microservices strewn across multiple clusters, an Urbit instance is easiest to manage as a single server with all its state unified into one data structure and its event log stored as one totally ordered sequence of state updates -- the antithesis of a distributed system.
54+
55+### Self-Contained
56+
57+Before Ford Fusion, each commit to the Clay filesystem validated its files using filetypes (called “marks”) defined by files in the previous commit. This could cause bugs if the filetype definitions had changed in a backward-incompatible manner. It also meant a commit could not add both a new filetype and new files of that type; instead, you needed two commits: one to define the filetypes, and a second to add files of that new type. More theoretically, it caused history-dependence. The validated contents of files in a commit could vary based on the history of commits that led to this one.
58+
59+Another way source code failed to be self-contained was that it had access to symmetry-breaking information at build-time, namely ship, desk (Urbit's answer to a git branch), and (faked) date. A build recipe should be able to shared, cached, and rerun without dependence on local conditions, so user code now no longer learns its ship, desk, or date until runtime.
60+
61+Source code also had build-time access to Urbit's immutable global namespace, called the “scry namespace”, which the kernel makes available as an implicit argument to userspace Hoon code. The scry namespace is immutable and referentially transparent, i.e. a request must always yield the same result for all time, but if an agent asks the kernel for a resource that’s from the future, hosted on another ship, or to which that agent doesn’t have permission, the kernel will deny the request.
62+
63+If the kernel denies a scry request that user code made during the build process, the build system has no choice but to treat it as a nondeterministic error. Nondeterministic errors can never be fully eradicated, if for no other reason than that the user always has the option to defenestrate the machine—there's nothing deterministic about that. But we try to minimize them, and especially to minimize uncertainty as to under what conditions they might occur.
64+
65+No build should be killed by the absence of files outside the desk, so as of this update, user code can no longer scry at build time. Once built, userspace programs can scry if run in a context with a scry handler; a Gall agent's runtime scry requests still work just fine.
66+
67+### Ordered
68+
69+The final kind of failure fixed by Ford Fusion was the lack of ordered layering during a software update. The most common form of this failure was that old Ford had a tendency to try to build userspace code using the previous version's standard library. This didn't work too well, unsurprisingly.
70+
71+Emerging from this underworld required making a number of changes to the Arvo kernel, Clay, Gall, and the procedure for kernel updates. To avoid turning into a pillar of salt, I'll skip the details of how the old system worked and instead describe the new update procedure.
72+
73+## How Updates Work Now
74+
75+These are the layers of the stack that update themselves on the fly, from lowest to highest:
76+
77++ hoon: the hoon language definition and compiler, defined in `/sys/hoon/hoon`
78++ arvo: the arvo kernel proper and related type definitions, in `/sys/arvo/hoon`
79++ zuse: the standard library, in `/sys/zuse/hoon`
80++ vanes: arvo kernel modules, including clay itself, in folder `/sys/vane`
81++ userspace: apps, marks, ancillary source code like libraries, and user data
82+
83+An update to one layer necessitates a reload of all layers above it; e.g. a change to Zuse should trigger updates to the vanes and userspace. Conversely, an update to a higher layer should not cause a spurious reload of lower layers, which should not be affected by the change; for example, an update to just userspace should not cause any reloads of system code.
84+
85+Clay is responsible for enforcing the layering of updates. An update to a module is triggered when an attempt is made to commit a change to Clay that affects one or more files needed to build the module. For example, if the 'foo' agent's source, defined in `/app/foo/hoon`, imports the 'bar' library from `/lib/bar/hoon`, then a modification to `/lib/bar/hoon` triggers an update to the 'foo' agent. All vanes and userspace files depend on Zuse, which depends on the Arvo and Hoon sources, so a change to the Hoon, Arvo, or Zuse sources will trigger updates to all vanes and userspace files.
86+
87+When asked to perform a commit, Clay determines which layers need to be updated based on which files have changed and which modules depend on those files. For now, all running programs load their source from the `%home` desk, so only changes to `%home` trigger stateful updates. Files in other desks can be built, but not installed into the system. This might be relaxed in the future.
88+
89+The process of updating varies by layer. The Hoon and Zuse layers are stateless, so their newly rebuilt cores (Nock executables) must be stored (somewhere in the system’s Nock tree, in memory; remember, Urbit is a single-level store), but they have no state that would need to be migrated. The Arvo kernel, vanes, and userspace agents are all live, stateful programs, so in order to update one of those, the system must extract the state from the old program, pass that data into the newly built program, then discard the old program and store the new one. Arvo and agent state injection routines can emit effects, but vane updates cannot.
90+
91+To work around this limitation, Gall has a two-phase update process. First it enters a dormant “pupal” phase that stores not running agent cores, but only the agent states that the old Gall had extracted from its agents. When Clay notifies Gall that its agents have been rebuilt, Gall “molts” back into normal functionality by loading the agent cores from Clay and then running their `+on-load` routines to inject the old state.
92+
93+If there's a change to files in `/sys` on the `%home` desk, Clay asks Arvo to update kernelspace. Clay sends a sequence of moves (effects) to Arvo to ask Arvo to perform any necessary updates to hoon, the kernel, Zuse, and vanes. This sequence is terminated by an extra move back to Clay itself, which will be received by the updated version of Clay after migrating its state. The rebuilt Clay can then use the newly rebuilt version of Zuse to rebuild userspace and notify clients of the update. One client is Gall, which molts when Clay notifies it.
94+
95+Clay triggers updates, but the Arvo kernel is responsible for performing updates to all kernelspace layers, and Gall is responsible for updating userspace agents. Agents are stored in Gall's state, but all other layers are stored directly in the Arvo core's state, so the Arvo kernel contains the routines that reload Hoon, the kernel itself, Zuse, and the vanes.
96+
97+The Arvo kernel reloads itself by receiving its new source code as a `%lyra` move from Clay, compiling this source into a core with empty state, then calling the new core's `+load` routine with the relevant parts of the old state. The state passed to the new Arvo now includes not just the vane cores and their states, but also the Arvo "duct" call `stack`, which maintains a stack of queues of moves to be passed from one vane to another, and a list of effects to emit to Unix at the end of the current Arvo event. If needed, Arvo could migrate the outstanding moves themselves -- if, say, the duct datatype changes.
98+
99+Passing the Arvo call stack state to new Arvo allows a kernel update to happen in the middle of a more complex event without disturbing other sequences of processing steps happening concurrently in the vanes.
100+
101+This entire update process happens in one Arvo event and doesn’t break event-dispatching semantics. This not only provides atomic rollback, but allows the update to be combined with other actions into a larger transaction -- for example, to stage complex changes, user code could trigger two kernel updates in a row, both in the same event.
102+
103+Note that this is the opposite situation from the entropically leaking asynchronicity described earlier. Now the guarantees don’t deteriorate; they can be composed into stronger guarantees.
104+
105+## How Clay Validates a Desk
106+
107+A desk is Urbit's answer to a git branch. It's almost identical, except all files are typed and validated, and whenever a commit becomes the equivalent of git’s ‘HEAD’, it’s assigned a semantically meaningful revision number, and all files are typed and validated.
108+
109+If Clay has been asked to perform a commit, it needs to validate all the files in this desk and notify all subscribers to live queries of this desk's data. Gall, for example, maintains live queries on builds of its live agents. Validation uses the Ford build system, which as of this update is no longer a standalone vane but a core within Clay.
110+
111+A Clay commit, like a git commit, is specified as the current value of all its changed files (and, separately, references its parent commits by hash), not as the diff from a parent commit. Unlike git, Clay is typed, and every file must be validated according to its "mark". A mark is named like a file extension, e.g. `%txt`, `%png`, or `%noun`, and Clay maintains a mapping from that name to behaviors of values of that type under various operations. The last segment of any Clay path specifies the mark to use for operations on that file, including validation.
112+
113+Mark operations include conversion to and from other marks (such as converting `%json` to `%txt`), revision control operations (diff, patch, and merge), and validating an untyped noun. Operations for mark `%foo-bar` are defined by a core built using the source code at `/mar/foo-bar/hoon`, or if that doesn't exist, at `/mar/foo/bar/hoon`.
114+
115+Consider a file at `/web/foo/json`. In order to validate this file, Clay must load the mark definition core and use its validation routine to ensure the untyped value of `/web/foo/json` is in fact valid JSON. To obtain this core, Clay must build the file at `/mar/json/hoon` from source and then process the resulting raw mark core using some mild metaprogramming to get a standard interface core for dealing with marks, called a `$dais`, whose type is defined in Zuse.
116+
117+Since building a source file only makes sense if the file has been validated as a `%hoon` file, but mark definitions themselves must be built from source, there's a logical dependency cycle -- who validates the validators? To break this cycle, Clay hard-codes the validation of `%hoon` files. This allows mark definitions to be built from source, and in fact any file can depend on any other file of any mark as long as there are no cycles. As of Ford Fusion, Ford performs a cycle check to ensure acyclicity.
118+
119+Since building a file is a pure function, Clay memoizes the results of all builds, including builds of marks, mark conversions, and hoon source files. These memoization results are stored along with the desk and are used by later revisions of that desk. Future work should allow merge commits to pull memoized builds from all parents, but for now only the previous revision of the current desk is used. This is a major simplification of previous Ford architectures, which maintained much more complex caches with less clear eviction semantics. Now on every commit, we just throw away any unused memoized builds from the previous revision's Ford cache.
120+
121+Once Clay has validated every file in this new revision of a desk, it constructs and sends updates to any subscriptions that other vanes or agents have requested. More Ford builds may be run to fulfill these requests, including builds for any running agents whose dependencies changed in this commit.
122+
123+When Gall receives a newly rebuilt agent from Clay, it calls the gate produced by the `+on-load` arm of the new agent with the state extracted from the old agent. If there is a crash in any `+on-load` calls or in the handling of any effects they emit (which can include more agent activations), then the whole event crashes, canceling the commit. This effectively gives any agent the ability to abort a commit by crashing.
124+
125+It is a bit counterintuitive that an app reload failure could prevent a kernel update. The reason is that we don't want the system to update itself into a broken state. An Urbit can be rendered practically unusable by the presence of broken agents, even if the kernel hasn't lost integrity,
126+so it's kinder to the user not to break their agents by installing an incompatible kernel update. This also puts virtuous pressure on kernel developers not to "break userspace", the importance of which has been insisted on for decades by Linus Torvalds, among others.
127+
128+If an agent does crash a commit event that included a kernel update, the attempted commit is now trivially rolled back, and the system can deliver an error message to the user. This does not leave the system in an inconsistent or stuck state, so the user could modify the failing agent and try the kernel update again later. Supporting better workflows for keeping third-party agents up-to-date will be an important aspect of Urbit’s upcoming software distribution work.
129+
130+## Ford Build Semantics
131+
132+### The Three Types of Ford Builds: Files, Marks, and Casts
133+
134+The Ford build semantics have been simplified. There are now three kinds of builds that Ford can perform: files, marks, and casts, all of which happen synchronously as function calls inside Clay and are available (without memoization) as scry interfaces.
135+
136+#### File Builds
137+
138+A file build takes in a filepath containing Ford runes and Hoon source, runs the Ford runes to perform imports, and then compiles the source, producing a `$vase`, a noun tagged with its Hoon type.
139+
140+Clay exposes file builds into the scry namespace with `%ca`: as an example, `.^(vase %ca /~zod/home/3/lib/sole/hoon)` will build the `sole` library.
141+
142+#### Mark Builds
143+
144+A mark build produces a `$dais` mark-interface core. It first performs a file build on the Hoon file in `/mar` that defines the mark core, then it does some metaprogramming to make the operations more convenient to use. If the raw mark core delegated revision control operations to another mark core, the mark build will also load the delegate mark core and resolve the result into the `$dais`.
145+
146+Clay exposes mark builds into the scry namespace with `%cb`: as an example, `.^(dais:clay %cb /~zod/home/3/mar/foo/hoon)` builds a `$dais` for the `%foo` mark.
147+
148+#### Cast Builds
149+
150+A cast build produces a `$tube`: a gate that takes a value of one mark as input and converts it to a valid value of another mark or crashes. To convert from mark `%foo` to mark `%bar`, Clay tries the following operations, in order:
151+
152++ direct grow from `%foo`
153++ direct grab from `%bar`
154++ indirect jump from `%foo` through `%qux`
155++ indirect grab from `%bar` through `%qux`
156+
157+The `%foo` mark can “grow to” `%bar` by providing an arm in its `+grow` core named `+bar`. `%bar` can convert from `%foo` using a `+foo` arm in its `+grab` core. `%foo` can also chain a conversion through an intermediary using an arm in its `+jump` core, and `%bar` can specify an “indirect grab” by having a `+grab` arm produce a delegate mark instead of directly defining a conversion gate.
158+
159+Clay exposes cast builds into the scry namespace with `%cc`: as an example, `.^(tube:clay %cc
160+/~zod/home/3/foo/bar)` builds a `$tube` conversion gate from `%foo` to `%bar`.
161+
162+### Ford Runes
163+
164+There are now only four Ford runes. A file can contain zero, one, or many of each, but each Ford expression can only be one line, and they must be in the standard order of `/-`s, `/+`s, `/=`s, and then `/*`s.
165+
166+```
167+/- foo, *bar, baz=qux
168+```
169+
170+The `/-` rune imports a structures file from `/sur`. You can import it as just `foo`, in which case the build result of that file (usually a core with mold definitions) will be pinned into the compilation subject with the face `foo`. If you prefix it with a `*` as in `*bar`, the result will be pinned into the subject with no face; if the structures file compiled to a core, this exposes all the arms into the namespace of the compilation subject. Finally, if you import it as `baz=qux`, the `baz` face will be applied instead of `qux`. This is similar to "import as" in other languages.
171+
172+```
173+/+ foo, *bar, baz=qux
174+```
175+
176+The `/+` rune imports a library file from `/lib`. Aside from the different source folder, the syntax and semantics are the same as for `/-`.
177+
178+```
179+/= clay-raw /sys/vane/clay
180+```
181+
182+The `/=` rune imports the result of building a hoon file from a user-specified path (the second argument), wrapping it in a face specified by the first argument. The final `/hoon` at the end of the path must be omitted. This is mostly useful for importing a file for testing. The file at the specified path will be built as a normal userspace hoon file; i.e. its compilation subject will be Zuse augmented with the results of any Ford runes it has at the top of the file.
183+
184+```
185+/* hello-gen %hoon /gen/hello/hoon
186+```
187+
188+The `/*` rune imports the contents of a file in the desk, specified as the third argument with the full path including the trailing mark, converted to the mark specified by the second argument, and pinned into the compilation subject wrapped in the face specified by the first argument. This can be used to import static data at build-time, such as a data file, a media file, or, in the case of this example, a hoon file as source text rather than already built.
189+
190+A valid userspace hoon file must contain a nonempty list of hoons (hoon source expressions) below the Ford runes, separated by gap (more than one space, or at least one newline). The system wraps this list of hoons in a `=~` expression so that the result of the previous hoon is used as the subject of the next hoon. The result of the Ford runes is used as the compilation subject for this `=~` hoon; informally, the shape of the compilation subject can be thought of as:
191+
192+```
193+:* fastar-2 fastar-1
194+ fastis-2 fastis-1
195+ faslus-2 faslus-1
196+ fashep-2 fashep-1
197+ <zuse>
198+==
199+```
200+
201+## Future Work
202+
203+Urbit still needs to make better use of desks other than `%home` and the development process should be adjusted given the tighter coupling between source code and kernel and tighter criteria for accepting an update.
204+
205+This work also hopefully provides a good foundation of a package management and software distribution system for Urbit. As `~wicdev-wisryt` has said, a user should be able to run `|install
206+~norsyr-torryn/canvas` to load and build remote source. No one should experience dependency hell on Urbit, but we're not there yet.
207+
208+At least now, building a desk has no dependencies, other than a Ford with a compatible Hoon compiler. No decisions have been made on this yet, but
209+Ford might get moved to inside the desk, possibly by making Zuse callable. This could allow a desk to expose a Nock interface in addition to a typed Hoon interface, which could even let a desk be used as a "pill" bootloader.
210+
211+## Conclusion
212+
213+`~littel-ponnys` and I spent most of 2018 rewriting Ford with the intent of improving its performance. Compared to its predecessor, its result was better in some ways but worse in others. The caching system was labyrinthine and poorly factored, making the system difficult to debug or prove correct, even informally. Some things were faster, but the caching and dependency tracking were actually complex enough that a number of common operations, like mark conversion, were too slow.
214+
215+In early 2020, `~master-morzod` suggested moving Ford into Clay to reduce asynchronicity. It seemed absurd at first, but at some point I realized I could combine that idea with a simpler build-caching scheme and self-contained desk builds, and `~wicdev-wisryt` realized he could use that to further simplify Clay’s commit and merge code, which he did as part of this project.
216+
217+The first time I rewrote Ford, it took me six months, with help from `~littel-ponnys`, and it weighed in at 6,000 lines of code. The second time, in late 2018, took a few weeks. The third time, in January 2020, took a week. I wrote `+ford` in Ford Fusion in one long day, and it’s about 500 lines of synchronous, functional code.
218+
219+It has taken me two or three years to understand this problem as well as I do, and I expect there are parts of it I still don’t understand. The code itself isn’t the issue; it’s finding the right answer to ontological and teleological questions. What *is* Ford? What will it be in a hundred years? I’m confident Ford Fusion is more similar than its predecessor to the Ford of 2120, because it’s smaller, more functional, and easier to understand and administer.
220+
221+As an engineering discipline and organizational practice, working on a system intended to be frozen yields surprising simplifications like this every so often. Urbit is now reaching the point where we’re starting to see more of the obsidian edges of the frozen future system emerge from the lava.
10222
11223
arvo/gall/tutorial.mdnew file+14
@@ -0,0 +1,14 @@
1++++
2+title = "Tutorial"
3+weight = 5
4+template = "doc.html"
5++++
6+
7+[**The Complete Guide to Gall and Userspace Apps on
8+Urbit**](https://github.com/timlucmiptev/gall-guide), or more colloquially
9+referred to as just "the Gall Guide," was contributed by a member of our
10+community named `~timluc-miptev`.
11+
12+Our plan is ultimately to make this part of the official documentation found
13+here, but for now, know that it has our official seal of approval and is
14+actively maintained.
arvo/io.mddeleted−471
@@ -1,471 +0,0 @@
1−+++
2−title = "Input and Output"
3−weight = 37
4−template = "doc.html"
5−+++
6−
7−Let's talk about IO in Urbit. I won't say much about how events and effects are
8−processed by the runtime; it suffices to note that the runtime is a normal Unix
9−program which (1) listens for various events, (2) passes them to Arvo (Urbit
10−OS), and (3) processes the effects produced by Arvo. Instead, I’ll focus on how
11−IO works from the perspective of Hoon programs, like Arvo or apps running on
12−Arvo. But first, let's review IO paradigms in other languages.
13−
14−All examples are in a made-up language, since it's useful to understand this
15−information even before you're comfortable in Hoon. If you're learning Hoon and
16−want a challenge, try translating them!
17−
18−## The three styles of IO
19−
20−I will call these styles imperative IO, monadic IO, and state machines (note
21−that this classification refers only to the experience of using them and the
22−program structure they dictate). An imperative programming language can use any
23−of these and a functional programming language can use any of them.
24−
25−### Imperative IO
26−
27−Imperative languages (such as C and Python) perform IO by calling a function in
28−the middle of whatever they were doing. Anywhere, in any statement, you could
29−have IO.
30−
31−In this example and others to follow, the task will be to read a filename from
32−the command line, read a URL out of that file, and fetch the contents at that
33−URL.
34−
35− output = fetchUrl(stripWhitespace(readFile(cliInput())))
36−
37−For readability, intermediate variables would be a good idea, but nothing stops
38−you from nesting IO this way.
39−
40−### Monadic IO
41−
42−Languages that use explicit monads for IO (such as Haskell) perform IO by
43−running IO behind a bind operation, which I'll notate with `<-`. Thus, while you
44−can't put IO *anywhere*, the general structure is a sequence of IO operations.
45−
46− fileName <- cliInput()
47− url <- readFile(fileName)
48− output <- fetchUrl(stripWhitespace(url))
49−
50−[Tackling the Awkward
51−Squad](https://www.microsoft.com/en-us/research/wp-content/uploads/2016/07/mark.pdf)
52−is the canonical description of monadic IO, and does a great job of explaining
53−how the Haskell community decided to use this as their primary IO style.
54−
55−### State machines
56−
57−Languages that use explicit state machines for IO (such as Elm) perform IO by
58−accepting events and producing a list of effects.
59−
60− event :: Initialize
61− | CLIInput text
62− | FileInput text
63− | HTTPResponse body
64− effect :: CLIInput
65− | ReadFile fileName
66− | FetchUrl url
67− | Print text
68− main(event) {
69− switch event {
70− Initialize -> [CLIInput ~]
71− CLIinput fileName -> [ReadFile fileName]
72− FileInput url -> [FetchUrl stripWhitespace(url)]
73− HTTPResponse body -> [Print body]
74− }
75− }
76−
77−The effects produced are not functions but data.
78−
79−It's important to note that this example is chosen to highlight a particular
80−kind of IO — sequences of events. Further, this example has no persistent state
81−— each IO operation is a pure function of the output of the previous one.
82−
83−## A stateful, loopy example
84−
85−Let's look at another type of program: a simple HTTP server that you can give
86−text at the CLI, which will respond to all HTTP requests with that text.
87−
88−Imperative:
89−
90− text = "no text entered yet"
91− while (true)
92− cli = readCli()
93− if (cli != Null)
94− text = cli
95− request = readHttp()
96− if (request != Null)
97− respond(request,text)
98−
99−Monadic:
100−
101− loop("no text entered yet")
102−
103− where:
104−
105− loop :: text -> IO Null
106− loop =
107− input <- readInput()
108− switch input
109− CLIInput newText -> loop(newText)
110− HTTPRequest request ->
111− _ <- respond(request,text)
112− loop(text)
113−
114−State machine:
115−
116− text = "no text entered yet"
117− main(text,event) {
118− switch event {
119− CLIInput newText -> [newText, Null]
120− HTTPRequest request -> [text, HTTPResponse text]
121− }
122− }
123−
124−Again, note the response in the state machine is data, not a function.
125−
126−I'm not trying to make a point about which type is better in general. There's a
127−pretty strong argument that in the first example, imperative was the best
128−option, followed by monadic, followed by state machine. There's an equally
129−strong argument that the second example is most naturally represented by the
130−state machine.
131−
132−Look at how state is handled in the monadic example. Formally, bind composes
133−functions, so that every time you see a `<-` there's actually a new function
134−(closure/delimited continuation) being created and stored for when we receive a
135−response. All variables in scope are stored in that closure, so we can
136−conveniently access them later without explicitly storing them. However, the
137−state we preserve over time varies a lot. In this example, it varies between
138−storing `loop`, `[loop input]`, `[loop input newText]`, and `[loop input
139−request]`.
140−
141−By comparison, the state machine does not store intermediate values, it only
142−stores its explicit state. While this is somewhat less flexible, it puts the
143−permanent state front-and-center.
144−
145−I'll reiterate that all of these are possible to implement in purely functional
146−languages, and further they can all be implemented in terms of each other. State
147−machines are trivially implementable -- it's just a function [state event] ->
148−[new-state (list effect)]. Monadic IO can be implemented directly (as in
149−Haskell) or on top of state machines by storing continuations in your state.
150−Imperative IO is somewhat more difficult but should be possible through
151−algebraic effects.
152−
153−When inventing a new system, you should consider which of these you intend to
154−support based on the sort of code you expect to see. For example, a scripting
155−language will almost always benefit from imperative (or at least monadic) style.
156−
157−## In Urbit
158−
159−So much for exploring the space of IO solutions. In terms of deployed code on
160−Earth, the split is about 90% imperative, 5% monadic, and 5% state machine. In
161−Urbit, the split is about 90% state machine and 10% monadic. This is what I
162−intend to explain and defend.
163−
164−Urbit's OS is called Arvo; it has several "kernel modules" called vanes, and it
165−has userspace applications. Colloquially these are called "apps," but when
166−speaking about them abstractly, it's helpful to use their more specific name:
167−["agents"](https://urbit.org/docs/tutorials/arvo/gall/#agents). Arvo, the vanes,
168−and agents are all structured as explicit state machines.
169−
170−In addition, there are
171−["threads"](https://urbit.org/docs/tutorials/arvo/gall/#threads), which are
172−structured as monadic IO. Note there's only a superficial resemblance to Unix
173−threads: they are not executed in parallel and they don't share memory, or at
174−least not any more than agents do. They're simply a computation that takes an
175−argument and produces a result, possibly after doing some IO, structured
176−monadically.
177−
178−As you can see, all the lowest levels of Arvo are explicit state machines, and
179−only the highest layer supports monadic IO. To see why this is the case, let's
180−list advantages and disadvantages to each type. Note that, while I'm speaking
181−specifically of agents and threads in the context of Urbit, these are
182−fundamental properties of monadic and state machine IO.
183−
184−Agents are:
185−
186−- Upgradable. Since the state is explicit, you can upgrade an agent in-place by
187− supplying a new state machine and a function from the old state type to the
188− new state type. This is very similar to a database migration.
189−
190−- Robust. A state machine must accept any input at any time. If it receives
191− unexpected input, it must have had explicit error handling for that input,
192− since it's one of the types in the switch statement. Thus, it's relatively
193− easy to stay in a consistent state.
194−
195−- Permanent. Since it's upgradable and robust, there's no reason to stop its
196− running.
197−
198−- Hard to write long sequences of IO. Long sequences of IO create many possible
199− states, and you must handle any input in any state. This can result in
200− complex, hard-to-follow code with code paths that are rarely if ever taken.
201−
202−Threads are:
203−
204−- Not upgradable in-place. Since the state is implicit, you can only cleanly
205− upgrade by (1) killing the thread and restarting it or (2) letting it resolve
206− to a defined "upgradable state" periodically, usually at the top of a "main
207− loop". If you do (2), then you are in fact structuring it as a state machine,
208− so the other advantages of threads are compromised.
209−
210−- Fragile. If we don't receive expected input, the default behavior is to be
211− stuck waiting for input. You must remember to add any error-handling features
212− you want, and it's easy to end up in an inconsistent state.
213−
214−- Impermanent. Since a thread can't be upgraded and may get stuck in case of
215− unexpected input, a thread can't be expected to last forever. It must be
216− "rebooted" from time to time.
217−
218−- Easy to write long sequences of IO. Just...write the IO one line at a time.
219−
220−Arvo proper and the vanes are permanent pieces of software and, for this reason,
221−state machines are more natural.
222−
223−I'll note that other kernels, like the Unix kernel, use imperative IO. The
224−difference is that Unix isn't permanent in itself — it only lasts until you
225−reboot. Since your permanent state is stored externally, you don't need to be
226−upgradable or permanent. With sufficient discipline you can write robust C code,
227−so it makes sense to use imperative style. Even so, a lot of C code is written
228−in a state machine style; even if it doesn't need to be upgradable, it's worth
229−it for the robustness and concurrency advantages.
230−
231−However, Arvo is a single-level store — all of its state is permanent. This is
232−very convenient and eliminates many long-tail bugs, but it also means we need to
233−code for permanence, and that's much easier when you structure your code with
234−explicit state.
235−
236−Further, Arvo and the vanes rarely perform long sequences of IO. Generally, they
237−do one thing and emit some effects, similar to the HTTP server example above.
238−Sometimes they "pass through" a request. For example, the Eyre vane passes HTTP
239−requests to userspace agents or threads. In this case, there is a sequence of
240−IO, which in monadic code would be:
241−
242− loop()
243−
244− where:
245−
246− loop =
247− request <- receiveRequest()
248− agent = lookupAgent(request)
249− response <- callAgent(agent, request)
250− _ <- sendResponse(request, response)
251− loop()
252−
253−This is clear code to read, but it leaves open the question of how to respond
254−during the callAgent() function. If another request comes in, can we handle it
255−in parallel? If we need to upgrade ourselves before the agent responds, can we
256−make sure to properly handle the response?
257−
258−The naive solution in monadic code is to say that you can only handle one
259−request at a time, and if an upgrade happens you just drop outstanding requests.
260−You can resolve both of these by introducing a sort of main loop, which is just
261−a way of saying "turn it into a state machine".
262−
263−In a state machine, the naive solution is:
264−
265− state :: (map request agent)
266− main(state, event) {
267− switch event {
268− HTTPRequest request ->
269− agent = lookupAgent(request)
270− [put(state, request, agent), CallAgent agent request]
271− AgentResponse request response ->
272− [del(state, request), HTTPRespond request response]
273− }
274− }
275−
276−Upgrading this is trivial, since the state (map of requests to outstanding calls
277−to agents) is explicit. It also trivially handles concurrent requests.
278−
279−I won't claim this is easier or harder to write than the monadic version, but it
280−has the properties we need at this level of the system.
281−
282−Userspace agents similarly are permanent entities that need to not lose data or
283−get stuck. For this reason they’re structured as state machines.
284−
285−A helpful comparison is that explicit state machines are basically Mealy
286−machines, the kind you might have learned about in an introductory digital
287−design class. This shouldn't be surprising; a digital circuit must always be
288−consistent because it can't be manually "rebooted", and their input and output
289−is highly formalized. By contrast, a Rube Goldberg machine doesn't have the same
290−constraints; which is why they're a lot more fun!
291−
292−It's notable also that explicit state machines are considerably more declarative
293−than imperative or monadic IO. Not everyone thinks that's a good thing, but
294−anyone who defends functional programming should see some advantages to that.
295−
296−However, userspace sometimes needs to perform long sequences of IO. Let's look
297−at an example where we want to fetch the front page of a site and the first
298−couple comments on each story. HTTP is unreliable, so on failure we retry five
299−times.
300−
301−Monadic:
302−
303− topStories <- fetch(topStoriesUrl)
304− loop(topStories)
305−
306− where:
307−
308− loop :: topStories -> IO Null
309− if topStories is Null
310− return Null
311− comments <- retryLoop(5,head(topStories))
312− otherComments <- loop(tail(topStories))
313− append(comments,otherComments)
314−
315− retryLoop :: [n story] -> IO Comments
316− comments <- fetchComments(story)
317− if comments is HTTPError:
318− if n == 0:
319− bail
320− else:
321− retryLoop(n-1, story)
322−
323−State machine:
324−
325− state :: Initial
326− | FetchingTop
327− | FetchingStory comments stories retries
328− | Done comments
329−
330− main(state, event) {
331− switch event {
332− Initialize ->
333− assert state == Initial
334− [FetchingTop, Fetch topStoriesUrl]
335− HttpResponse response ->
336− switch state {
337− FetchingTop ->
338− [FetchingStory Null stories 5, FetchComments head(stories)]
339− FetchingStory comments stories retries ->
340− if response is HTTPError:
341− if retries == 0:
342− [Initial, Null]
343− else:
344− [FetchingStory comments stories retries-1,
345− FetchComments head(stories)]
346− else:
347− comments = append(response,comments)
348− if tail(stories) is Null:
349− [Done comments, Null]
350− else:
351− [FetchingStory append(comments,response) tail(stories) 5,
352− FetchComments head(tail(stories))]
353− }
354− }
355− }
356−
357−With practice, the state machine version of this can be written correctly.
358−However, (1) it's verbose, (2) the control flow jumps all over the place, and
359−(3) in practice it's challenging to get exactly right. This is still a small
360−example, and it gets much worse as the length and complexity of the IO sequence
361−grows.
362−
363−The monadic version, on the other hand, flows cleanly down the page. We can
364−factor out generic functionality like "retry this request n times" to make the
365−essence of the computation clear.
366−
367−Suppose you have to upgrade this. In the state machine, you can see exactly
368−which stage of the computation you're in and write specific code to upgrade
369−cleanly.
370−
371−Threads, as we've discussed, can't be upgraded in-place. Let's be real though:
372−we're downloading comment sections, not regulating a nuclear reactor. If we get
373−a better version of this script, just kill the old one and start the new one
374−from scratch. What's a couple extra HTTP requests?
375−
376−This suggests a general division of workloads: code which needs to be permanent,
377−upgradable, and concurrent should generally be a state machine. Code with long
378−or complex sequences of IO and definite termination should generally be a
379−thread.
380−
381−These aren't completely mutually exclusive, but it's surprising how often they
382−are.
383−
384−### Jael: a case study
385−
386−When you need to do something permanent and upgradable, but you also need to do
387−long sequences of IO, the main trick is to factor your problem into both an
388−agent and a thread (or several).
389−
390−As a case study, consider Jael, one of our vanes. This maintains our PKI state,
391−which it downloads over HTTP from an Ethereum node. Downloading from an Ethereum
392−node is a complex sequence that starts with fetching its most recent block
393−number, then fetching all the blocks we haven't seen and scanning for
394−transactions we care about. We also maintain a map of block hashes to block
395−number, and if we see that a block's parent doesn't have the hash we expect,
396−that means a reorganization has occurred, so we must "rewind" one block at a
397−time until we find where the fork happened, then restart going forward.
398−
399−You don't have to understand this sequence of IO; it's sufficient to see that
400−it's complex and must be exactly right. We used to do this in a state machine
401−directly in Jael. This data is, of course, permanent and needs to be accessible
402−to the rest of the system, so Jael must be a state machine.
403−
404−However, we had many small mistakes in this sequence of IO, some of which only
405−appeared during unusual events, such as when an HTTP request failed at the same
406−time as a reorganization happened.
407−
408−We're in a bit of a bind, though: Jael has to be a state machine. The solution
409−is to factor out the act of getting updates into a thread while the main PKI
410−state is stored in the state machine in Jael.
411−
412−This thread has a definite purpose: given the most recent block number we
413−already know about, fetch all the PKI transactions since then. The function
414−signature is:
415−
416− syncEthereum oldBlockNumber -> IO [newBlockNumber, newTxs]
417−
418−Jael runs this thread every five minutes and, if it succeeds, then we update our
419−block number and PKI state. If the thread fails, gets stuck, or we need to
420−upgrade it, we just kill the old thread and start a new one. Again, a few extra
421−HTTP requests don’t matter.
422−
423−From Jael's perspective, it looks something like:
424−
425− state :: State block txs outstandingThread
426− main(state,event) {
427− switch event {
428− Initialize -> [State 0 Null Null, StartTimer (now + five minutes)]
429− TimerFired ->
430− effects = If outstandingThread is Null
431− then Null
432− else [Kill outstandingThread]
433− newId = newThreadId()
434− [State txs newId,
435− append(effects,
436− StartThread newId syncEthereum(block),
437− StartTimer (now + five minutes))]
438− ThreadFinished Failure -> [State block txs Null, Null]
439− ThreadFinished Success newBlockNumber newTxs ->
440− [State newBlockNumber append(txs,newTxs) Null, Null]
441− }
442− }
443−
444−In other words, from Jael's perspective, it's just a single IO event that
445−encapsulates arbitrarily complex IO in the thread. A single IO event is easy
446−enough, and we can maintain all our permanency and robustness guarantees,
447−because we know the thread will have one of three results: success, failure, or
448−it hangs. If we set a timeout, hang becomes failure, so there's only two
449−possible results: success or failure. If we handle both of those correctly,
450−we've handled all the possible IO errors that could have occurred.
451−
452−What about upgrading? We've already said we can handle the thread dying for
453−arbitrary reasons, so if an upgrade comes in, we just kill it. We can upgrade
454−Jael's state machine easily since its state is very simple.
455−
456−## Recap
457−
458−Let's recap what we've covered:
459−
460−- There are three styles of IO: imperative, monadic, and explicit state
461− machines.
462−- Urbit supports explicit state machines (agents) and monadic IO (threads).
463−- Explicit state machines are preferred for permanent, robust, concurrent code.
464−- Monadic IO is preferred for short-lived code with complex IO.
465−- If a state machine needs to perform complex IO, it should encapsulate it in a
466− thread so that, from the perspective of the state machine, it's simple IO.
467−
468−Hopefully it's fairly clear why Urbit uses explicit state machines in most
469−situations. More than anything else, our goal is to build software that can last
470−forever. Explicit state machines are a crucial tool for that.
471−
arvo/jael/jael-api.md+1−1
@@ -14,7 +14,7 @@ each `task` that Jael can be `%pass`ed, and which `gift`(s) Jael can `%give` in
1414
1515This `task` is called once per ship during the vane initialization
1616phase immediately following the beginning of the [adult
17−stage](@/docs/arvo/arvo.md#structural-interface-core). This `task` is `%pass`ed to Jael by Dill, as Dill is the first vane to be loaded for
17+stage](@/docs/arvo/overview.md#structural-interface-core). This `task` is `%pass`ed to Jael by Dill, as Dill is the first vane to be loaded for
1818technical reasons, though we consider Jael to be the true "first" vane. This
1919`task` is only used for ships that will join the Ames network - fake ships (i.e.
2020made with `./urbit -F zod`) use the `%fake` `task` instead.
arvo/arvo.md → arvo/overview.mdrenamed+2−4
@@ -9,8 +9,6 @@ Arvo, also called Urbit OS, is our operating system.
99
1010# Introduction
1111
12−## Overview
13−
1412This article is intended to provide a thorough summary of all of the most
1513important aspects of the Arvo kernel and how this functionality gives life to
1614the ambitions of the Urbit platform. We work on two levels: a conceptual level
@@ -253,7 +251,7 @@ The Arvo kernel, stored in `sys/arvo.hoon`, is about 1k lines of Hoon whose prim
253251This section requires an understanding of Hoon of at least the level of Chapter One of the [Hoon tutorial](@/docs/hoon/hoon-school/_index.md).
254252
255253After concluding this section, the reader is encouraged to follow along with the
256−[move trace tutorial](@/docs/arvo/move-trace.md),
254+[move trace tutorial](@/docs/arvo/tutorials/move-trace.md),
257255which applies many of the concepts covered below.
258256
259257## Overall structure
@@ -576,4 +574,4 @@ As of this writing, we have nine vanes, which each provide the following service
576574
577575Now that you've learned about the nuts and bolts of the Arvo kernel, why not
578576check it out in action? An in-depth "move trace" tutorial for running a timer app
579−is available [here](@/docs/arvo/move-trace.md).
577+is available [here](@/docs/arvo/tutorials/move-trace.md).
arvo/tutorials/_index.mdnew file+8
@@ -0,0 +1,8 @@
1++++
2+title = "Tutorials"
3+weight = 200
4+sort_by = "weight"
5+template = "sections/docs/chapters.html"
6++++
7+
8+Tutorials aimed at broadening understanding of Arvo.
arvo/move-trace.md → arvo/tutorials/move-trace.mdrenamed+6−6
@@ -1,5 +1,5 @@
11+++
2−title = "Tutorial: Move Trace"
2+title = "Move Trace"
33weight = 12
44template = "doc.html"
55+++
@@ -7,7 +7,7 @@ template = "doc.html"
77In this tutorial we will run a simple "move trace" and use the output to get a
88picture of what the Arvo kernel proper does during the routine task of setting a
99timer. Some level of familiarity with the kernel is required for this section,
10−which can be obtained in our [Arvo kernel tutorial](@/docs/arvo/arvo.md#the-kernel).
10+which can be obtained in our [Arvo kernel tutorial](@/docs/arvo/overview.md#the-kernel).
1111
1212## Running a move trace
1313
@@ -20,7 +20,7 @@ has elapsed.
2020To follow along yourself, boot up a fake `~zod` and enter `|verb` into the dojo
2121and press Enter to enable verbose mode (this is tracked by the laconic bit
2222introduced in the section on [the
23−state](@/docs/arvo/arvo.md#the-state)) in the kernel documentation, followed by `-time ~s1`
23+state](@/docs/arvo/overview.md#the-state)) in the kernel documentation, followed by `-time ~s1`
2424followed by Enter. Your terminal should pretty print a series of `move`s that looks something like this:
2525
2626```
@@ -105,7 +105,7 @@ arrow to Vane B, this represents either a `%pass` `note/task` sequence or a
105105`%give` `gift/sign` sequence that actually has the Arvo kernel in the middle.
106106That is to say, Vane A `%pass`es a `note` to the Arvo kernel addressed to Vane
107107B, and the Arvo kernel then `%pass`es a `task` to Vane B. For more information,
108−see the [Arvo kernel tutorial](@/docs/arvo/arvo.md#the-kernel).
108+see the [Arvo kernel tutorial](@/docs/arvo/overview.md#the-kernel).
109109
110110This simple action ends up involving four vanes - Dill, Gall, Behn, and Ford -
111111as well as four applications - hood, spider, dojo, and time.
@@ -118,7 +118,7 @@ This tells us that Unix has sent a `%belt` `card`, which corresponds to
118118terminal input (the Enter keystroke) at time `~2020.1.14..19.01.25..7556`
119119
120120Here is the line of code in `arvo.hoon`, found in the [section
121−3bE core](@/docs/arvo/arvo.md#section-3be-core), that generated the output:
121+3bE core](@/docs/arvo/overview.md#section-3be-core), that generated the output:
122122
123123```hoon
124124 ~? !lac ["" %unix -.q.ovo p.ovo now]
@@ -170,7 +170,7 @@ Here, Dill `%pass`es a `task` `card` saying to `%poke` Gall's hood app (with the
170170Enter keystroke).
171171
172172Let's glance at part of the `+jack` arm in `arvo.hoon`, located in the [section 3bE
173−core](@/docs/arvo/arvo.md#section-3be-core). This arm is what the Arvo kernel uses to send `card`s,
173+core](@/docs/arvo/overview.md#section-3be-core). This arm is what the Arvo kernel uses to send `card`s,
174174and here we look at the segment that includes `%pass` `move`s.
175175
176176```hoon
azimuth/azimuth.md+1−1
@@ -6,7 +6,7 @@ aliases = ["/docs/learn/azimuth"]
66+++
77Azimuth is a general-purpose public-key infrastructure (PKI) on the Ethereum blockchain, used as a platform for _Urbit identities_. You need such an identity to use the Arvo network.
88
9−The primary way to interact with Azimuth is through our [Bridge](https://github.com/urbit/bridge) application and the node libraries that it depends on, [azimuth-js](https://github.com/urbit/azimuth-js) and [urbit-key-generation](https://github.com/urbit/urbit-key-generation). Take a look at the source and play around, or see [Getting Started](@/using/install.md).
9+The primary way to interact with Azimuth is through our [Bridge](https://github.com/urbit/bridge) application and the node libraries that it depends on, [azimuth-js](https://github.com/urbit/azimuth-js) and [urbit-key-generation](https://github.com/urbit/urbit-key-generation). Take a look at the source and play around, or see [Getting Started](@/getting-started.md).
1010
1111## Arvo vs. Azimuth
1212
development/_index.md+12−11
@@ -1,28 +1,29 @@
11+++
22title = "Development"
3−weight = 200
3+weight = 100
44sort_by = "weight"
55template = "sections/docs/chapters.html"
66+++
77
8+This section covers the development process in general.
89
10+## [Getting Started](@/docs/development/develop.md)
911
10−## [Developer's Guide](@/docs/development/develop.md)
12+An orientation to the various development paths within the Urbit ecosystem
1113
12−How to get started developing on Urbit.
14+## [Environment Setup](@/docs/development/environment.md)
1315
14−## [Using the HTTP API](@/docs/development/integrating-api.md)
16+How to get your development environment ready for Urbit development.
1517
16−How to use Urbit's HTTP API. See also [Eyre](@/docs/arvo/eyre/eyre.md),
17−[Arvo's](@/docs/arvo/arvo.md)'s HTTP server vane.
18+## [Grants Program](@/docs/development/grants.md)
1819
19−## [Airlock](@/docs/development/airlock.md)
20+An introduction to our grants program, where you can earn address space for
21+contributing to the project.
2022
21−The set of APIs for interacting with a running Urbit ship from outside the Urbit network.
23+## [Project Repositories](@/docs/development/project-repositories.md)
2224
23−## [Community Projects](@/docs/development/community-projects.md)
24−
25−Projects created by the community.
25+A directory of official code repositories, and unofficial community-maintained
26+ones.
2627
2728## [Precepts](@/docs/development/precepts.md)
2829
development/airlock.mddeleted−135
@@ -1,135 +0,0 @@
1−+++
2−title = "Airlock"
3−weight = 30
4−template = "doc.html"
5−+++
6−
7−Airlock is the term to describe the set of APIs for interacting with a running Urbit ship from outside of the Urbit network.
8−
9−## Urlock-py
10−
11−Urlock-py is a python library for using Airlock.
12−
13−It consists of a single class `Urlock`. Methods are below.
14−
15−`__init__(url, code)`
16−
17− Constructor
18−
19− `url` - url to the http interface of the running ship
20−
21− `code` - the `+code` of the ship, should never be published
22−
23−
24−`connect()`
25−
26− Connect to the running ship
27−
28−
29−`poke(ship, app, mark, j)`
30−
31− `ship` - ship to send the poke
32−
33− `app` - gall application to send the poke to
34−
35− `mark` - mark of data sent to the gall application
36−
37− `j` - json poke data
38−
39−
40−`ack(eventId)`
41−
42− Send an acknowledgment of receipt of a message so it's cleared from the ship's queue
43−
44− `eventId` - id of the event to acknowledge
45−
46−
47−`sse_pipe()`
48−
49− returns the sseclient object
50−
51−
52−`subscribe(ship, app, path)`
53−
54− `ship` - ship on which the gall application lives
55−
56− `app` - gall application to subscribe to
57−
58− `path` - path to subscribe on
59−
60−
61−Below is a simple script to send a message and subscribe to a chat channel. The specifics require an understanding of the `chat-store` and `chat-hook` interfaces.
62−
63−Even without experience with python this should be pretty readable.
64−
65−```
66−#!/usr/bin/python3
67−
68−import urlock
69−import baseconvert
70−import time
71−import random
72−import dumper
73−
74−zod = urlock.Urlock("http://localhost:8080", "lidlut-tabwed-pillex-ridrup")
75−r = zod.connect()
76−s = zod.subscribe("zod", "chat-store", "/mailbox/~/~zod/mc")
77−
78−pipe = zod.sse_pipe()
79−
80−s = baseconvert.base(random.getrandbits(128), 10, 32, string=True).lower()
81−uid = '0v' + '.'.join(s[i:i+5] for i in range(0, len(s), 5))[::-1]
82−
83−p = zod.poke("zod", "chat-hook", "json", {"message": {"path": "/~/~zod/mc",
84− "envelope": {"uid": uid,
85− "number": 1,
86− "author": "~zod",
87− "when": int(time.time() * 1000),
88− "letter": {"text": "hello world!"}}}})
89−
90−
91−for m in pipe.events():
92− dumper.dump(m)
93− dumper.dump(zod.ack(int(m.id)))
94−```
95−
96−After the imports, instantiating the Urlock class with the address of the running ship and the `+code` from the ship. This code should not be shared. The one used here is for fakezods.
97−
98−```
99−zod = urlock.Urlock("http://localhost:8080", "lidlut-tabwed-pillex-ridrup")
100−```
101−
102−Next we connect to the ship and set up a subscription to chat-store
103−
104−```
105−r = zod.connect()
106−s = zod.subscribe("zod", "chat-store", "/mailbox/~/~zod/mc")
107−```
108−
109−After this we get the SSE pipe that all responses will arrive on.
110−
111−```
112−pipe = zod.sse_pipe()
113−```
114−
115−Next comes some setup for specific implementation details of `chat-hook` and a `poke` is sent to create a new chat message.
116−
117−```
118−s = baseconvert.base(random.getrandbits(128), 10, 32, string=True).lower()
119−uid = '0v' + '.'.join(s[i:i+5] for i in range(0, len(s), 5))[::-1]
120−
121−p = zod.poke("zod", "chat-hook", "json", {"message": {"path": "/~/~zod/mc",
122− "envelope": {"uid": uid,
123− "number": 1,
124− "author": "~zod",
125− "when": int(time.time() * 1000),
126− "letter": {"text": "hello world!"}}}})
127−```
128−
129−Finally, the loop here is used to read messages from the sse pipe and send back an acknowledgment. This is important to clear the queue on the ship.
130−
131−```
132−for m in pipe.events():
133− dumper.dump(m)
134− dumper.dump(zod.ack(int(m.id)))
135−```
development/community-projects.mddeleted−20
@@ -1,20 +0,0 @@
1−+++
2−title = "Community Projects"
3−weight = 50
4−template = "doc.html"
5−+++
6−
7−## Tutorials
8−
9−Here are some tutorials written by members of the Urbit community.
10−
11−- [A Nock Interpreter](https://jtobin.io/nock) by `~nidsut-tomdun`
12−- [Basic Hoonery](https://jtobin.io/basic-hoonery) by `~nidsut-tomdun`
13−- [The Complete Guide to
14− Gall](https://github.com/timlucmiptev/gall-guide/blob/master/overview.md) by
15− `~timluc-miptev`
16−- [Nock for Everyday Coders](https://blog.timlucmiptev.space/part1.html) by `~timluc-miptev`
17−- [Rote - An Annotated Flashcard App](https://github.com/lukechampine/rote)
18−
19−If you want to add something to the list, [shoot us an email](mailto:support@urbit.org) or make a pull request in the [docs repository](https://github.com/urbit/docs).
20−
development/develop.md+107−96
@@ -6,99 +6,110 @@ template = "doc.html"
66aliases = ["/docs/using/creating-a-development-ship/", "/docs/getting-started/contributing"]
77+++
88
9−You can develop on Urbit in three ways:
10−
11−- [Applications using Urbit](#api), which use Urbit as the back-end to store data and communicate with others
12−- [Urbit Applications](#application), which are written in [Hoon](/docs/hoon/), and run as part of Urbit
13−- [Urbit Core](#core), which involves contributing to Urbit's operating system ([Arvo](https://github.com/urbit/urbit/tree/master/pkg/arvo)) or runtime ([Vere](https://github.com/urbit/urbit/tree/master/pkg/urbit))
14−
15−This guide will start by getting you set up to run an Urbit ship, and then tell you everything you need to know to do either.
16−
17−### Setting up your environment
18−
19−We assume you’ve gotten a basic introduction to Urbit. If you haven’t, read the [Understanding Urbit](@/understanding-urbit/_index.md) series.
20−
21−Once you’re ready, you can get started on the network right away and take some first steps, without acquiring an identity, by [creating a comet](@/using/install.md#comet).
22−
23−When developing, however, we recommend [booting a development ship](#creating-a-development-ship) and working locally -- you may need to make changes that could, in the wrong hands, destroy the ship’s environment, and it’s best to do so in a safe, separate place.
24−
25−## Applications using Urbit {#api}
26−
27−Urbit ships with its own set of apps written in its own language, Hoon. However it is also meant to integrate with applications written in other languages via an API. The clearest example of an application using Urbit is Landscape, the default client. Although it does currently ship with Urbit, its front-end is a separate piece of software that uses Urbit's HTTP APIs to interact with an Urbit ship. You can create your own application that uses Urbit to store data and interact with other Urbit ships without writing any Hoon code thanks to Urbit's HTTP APIs. This could be a chat client, a writing app, a game, or anything else that can communicate over HTTP.
28−
29−To get started quickly with the language of your choice, see the following libraries that provide HTTP interfaces to Urbit:
30−
31− - [Python](https://github.com/baudtack/urlock-py) (Stable)
32− - [Swift](https://github.com/dclelland/UrsusAirlock) (Under development)
33− - [Haskell](https://github.com/bsima/urbit-airlock) (Under active development)
34− - [JavaScript](https://www.npmjs.com/package/urbit) (Under active development)
35− - Go (Pending release)
36−
37−[View details about using the API or creating your own implementation here.](@/docs/development/integrating-api.md)
38−
39−## Urbit Applications {#application}
40−
41−Urbit applications are still young, but can be fun to experiment with.
42−
43−When creating user applications on Urbit, you aren’t tied to any particular user interface. They can work without providing a response to the user, or by printing to the Dojo, or with an interface in Landscape, which uses [Eyre](@/docs/arvo/eyre/eyre.md) (the Arvo vane that serves HTTP to serve a React-based interface to the application through a web browser).
44−
45−When writing applications, you will often make use of [Gall](@/docs/hoon/hoon-school/gall.md), the Arvo vane that manages user applications.
46−
47−If you want to see examples of Urbit applications with common functionality requirements, you can see our [examples](https://github.com/urbit/examples) repository. If you want to get started building applications with a Landscape interface, check out our [create-landscape-app](https://github.com/urbit/create-landscape-app) repository.
48−
49−## Urbit Core {#core}
50−
51−Working on the core means improving the Urbit project itself, working with the existing community of Urbit developers. The kernel is much more stable, but generally more challenging from an engineering standpoint.
52−
53−Just arrived and unsure what to work on? An ideal way to get started is by experimenting with the system, talking to other developers, and reading (or [contributing to](https://github.com/urbit/docs)) the [documentation](/docs/).
54−
55−Prefer learning with an instructor? Our community runs an online course that covers the basics of Urbit development called [Hooniversity](https://hooniversity.org/). If course-based learning works well for you, we recommend you sign up.
56−
57−The Urbit developer community congregates around [the urbit-dev mailing list](https://groups.google.com/a/urbit.org/forum/#!forum/dev), the `~bitbet-bolbel/urbit-community` group on Landscape, and [Urbit’s GitHub repository](https://github.com/urbit/urbit). It’s a good idea to sign up, see what people are talking about, and introduce yourself.
58−
59−Once you’re comfortable working with Urbit, check out the [project’s issues on GitHub](https://github.com/urbit/urbit/issues) or some of our [contribution bounties](https://grants.urbit.org/).
60−
61−If you’re looking for some guidance, need help, or would prefer direct communication for your ideas, you can also always reach out to us directly at [support@urbit.org](mailto:support@urbit.org).
62−
63−## Creating a development ship {#creating-a-development-ship}
64−
65−To do work with Hoon and with the system, we recommended using a "fake" ship -- one not connected to the network.
66−
67−Because such a ship has no presence on the network, you don't need an Azimuth identity for its purposes. You just need to have [installed our software](/using/install).
68−
69−To create a fake ship named `~zod`, run the command below. You can replace `zod` with any valid Urbit ship-name.
70−
71−```
72−./urbit -F zod
73−```
74−
75−Now you should see a block of boot messages, starting with the Urbit version number. Welcome!
76−
77−
78−## How else can I contribute? {#how}
79−
80−The Urbit project is a global community of developers, users, and fans. If you’re interested in getting involved, there’s space for you; you don’t have to be a developer to be a part of the project.
81−
82−### Running stars and galaxies
83−
84−There are two ways to participate in the Arvo network: as a user running a planet and as an infrastructure provider running a galaxy or a star.
85−
86−For planets, Urbit is a peer-to-peer network where users can interact with each other via Landscape, or using custom applications that anyone can write.
87−
88−Running a planet helps build Urbit’s community, surfaces bugs, and helps core developers improve Urbit under realistic conditions.
89−
90−Stars and galaxies, however, have additional responsibilities and play a role in peer discovery as well as star and planet distribution. You can think of stars and galaxies as similar to the DNS system in the modern Internet. Most users don’t know it exists, but without it, the web wouldn’t work at all.
91−
92−Running a reliable galaxy or star, and spawning stars and planets from them, are excellent ways to help bootstrap the Urbit network.
93−
94−If you’re interested in running a galaxy or star, you’ll be reliably providing peer discovery for your children just by running your node – and we’re doing our best to make this both easy and profitable. If you’re interested in this, see [Star and Galaxy Operations](@/using/os/stars-and-galaxies.md).
95−
96−If you’re interested in distributing planets, read on.
97−
98−### Distribute points
99−
100−Want to get your friends and family into Urbit? Distribute planets using Bridge with a feature called **delegated sending**.
101−
102−Here’s how it works: any star can grant a number of invites to any of its child planets. Those planets can then send one-time-use invite codes via email to anyone of their choosing.
103−
104−For instructions on how to grant and send invites, check out [Using Bridge](@/using/id/using-bridge.md).
9+There are many ways to get involved as a developer. This guide serves to give
10+you a "lay of the land" for developing on Urbit. Let's start with what you can
11+contribute to. At a high level, you can:
12+
13+- [Build clients](#clients), which use Urbit as their back-end to store data and
14+ interact with the network
15+- [Develop agents](#agents), or more precisely [*gall*
16+ agents](@/docs/arvo/gall/gall.md), which are written in [Hoon](/docs/hoon/)
17+ and can best be thought of as microservices
18+- [Contribute to Urbit's core](#core), which involves contributing to Urbit
19+ itself &mdash; either the operating system
20+ ([Arvo](https://github.com/urbit/urbit/tree/master/pkg/arvo)), runtime
21+ ([Vere](https://github.com/urbit/urbit/tree/master/pkg/urbit)), or public key
22+ infrastructure ([Azimuth](https://github.com/urbit/azimuth))
23+
24+Below we'll go into more detail about each of these options and do our best to
25+point you towards a number of additional helpful resources that can be found
26+throughout the docs.
27+
28+### Build Clients {#clients}
29+
30+Urbit ships with [Landscape](@/docs/landscape/overview.md), which can be thought
31+of as its flagship client. Landscape can be broken into two different technical
32+components: there's the collection of [agents](#agents) that utilize the
33+Urbit for networking and data persistence, and the JavaScript client, which is
34+an [interface](https://github.com/urbit/urbit/tree/master/pkg/interface) built
35+with [React](https://reactjs.org).
36+
37+Additionally, you can [contribute to
38+Landscape](https://github.com/urbit/urbit/blob/master/pkg/interface/CONTRIBUTING.md)
39+by tackling issues in its [issue
40+tracker](https://github.com/urbit/landscape/issues) and/or running the the
41+[development stream](https://groups.google.com/a/urbit.org/g/dev/c/r2hv4ajCLwk).
42+
43+You can create your own clients that uses Urbit to store data and interact with
44+other Urbit ships without writing any Hoon code thanks to Urbit's HTTP APIs.
45+This could be a chat client, a writing app, a game, or anything else that can
46+communicate over HTTP.
47+
48+To get started quickly with the language of your choice, see the list
49+libraries that provide HTTP interfaces to Urbit [here](https://github.com/urbit/awesome-urbit#http-apis-airlock).
50+
51+To learn more about how to work with Urbit's HTTP interface, follow [this
52+guide](@/docs/arvo/eyre/using-eyre.md).
53+
54+Alternatively, command-line interface (CLI) applications can be built using a
55+library called `shoe`, which you can learn more about
56+[here](@/docs/hoon/guides/cli-tutorial.md). This does require Hoon knowledge.
57+
58+### Develop Agents {#agents}
59+
60+Gall agents can be best thought of as individual services with a
61+statically-typed interface and built-in database. They're written in
62+[Hoon](@/docs/hoon/overview.md) and all conform to a specific
63+[interface](@/docs/arvo/gall/gall-api.md) that's defined by the kernel vane
64+called [Gall](@/docs/arvo/gall/gall.md).
65+
66+Applications built on Urbit utilize a collection of different agents, each of
67+which handle specific functionality. The [Landscape
68+architecture](@/docs/landscape/overview.md) is a good reference implementation
69+to see how this pattern works in practice.
70+
71+If you want to learn how to build gall agents, your best bet is to first [learn
72+the Hoon programming language](@/docs/hoon/hoon-school/_index.md), and then follow that
73+up with the [Gall guide](@/docs/arvo/gall/tutorial.md).
74+
75+### Contribute to Urbit Core {#core}
76+
77+Working on the core means improving the Urbit project itself, working with the
78+existing community of Urbit developers. The kernel is much more stable, but
79+generally more challenging from an engineering standpoint.
80+
81+Just arrived and unsure what to work on? An ideal way to get started is by
82+experimenting with the system, talking to other developers, and reading (or
83+[contributing to](https://github.com/urbit/docs)) the [documentation](/docs/).
84+
85+Prefer learning with an instructor? Our community runs an online course that
86+covers the basics of Urbit development called
87+[Hooniversity](https://hooniversity.org/). If course-based learning works well
88+for you, we recommend you sign up.
89+
90+The Urbit developer community congregates around [the urbit-dev mailing
91+list](https://groups.google.com/a/urbit.org/forum/#!forum/dev), the
92+`~bitbet-bolbel/urbit-community` group on Landscape, and [Urbit’s GitHub
93+repository](https://github.com/urbit/urbit). It’s a good idea to sign up, see
94+what people are talking about, and introduce yourself.
95+
96+Once you’re comfortable working with Urbit, check out the [project’s issues on
97+GitHub](https://github.com/urbit/urbit/issues) or some of our [contribution
98+bounties](https://grants.urbit.org/).
99+
100+If you’re looking for some guidance, need help, or would prefer direct
101+communication for your ideas, you can also always reach out to us directly at
102+[support@urbit.org](mailto:support@urbit.org).
103+
104+## Next Steps
105+
106+From here, you'll probably want to learn more about:
107+
108+- How to set up a [development environment](@/docs/development/environment.md)
109+- Our [grants program](@/docs/development/grants.md), where you can earn address
110+ space for helping the project grow
111+- The different [project
112+ repositories](@/docs/development/project-repositories.md), both official and
113+ community-maintained
114+- Our development [Precepts](@/docs/development/precepts.md), which outline the
115+ philosophies that drive Urbit development
development/environment.mdnew file+62
@@ -0,0 +1,62 @@
1++++
2+title = "Environment Setup"
3+description = "How to set up an environment for Urbit development."
4+weight = 10
5+template = "doc.html"
6++++
7+
8+This guide covers best practices for preparing your environment to develop
9+within the Urbit ecosystem.
10+
11+## Creating a development ship
12+
13+To do work with Hoon, we recommended using a "fake" ship -- one that's not
14+connected to the network.
15+
16+Because such a ship has no presence on the network, you don't need an Azimuth
17+identity. You just need to have [installed the Urbit binary](/getting-started).
18+
19+To create a fake ship named `~zod`, run the command below. You can replace `zod`
20+with any valid Urbit ship-name.
21+
22+```
23+./urbit -F zod
24+```
25+
26+This should take a couple of minutes, during which you should see a block of boot
27+messages, starting with the Urbit version number.
28+
29+
30+## Hoon support in text editors
31+
32+A variety of plugins have been built to provide support for the Hoon language in
33+different text editors:
34+
35+#### Atom
36+Atom is free and open-source and runs on all major operating systems. It is
37+available [here](https://atom.io/). A package for Hoon support is maintained by
38+Tlon and may be obtained using the package manager within the editor by
39+searching for `Hoon`.
40+
41+#### Sublime Text
42+Sublime Text is closed-source, but may be downloaded for free and there is no
43+enforced time limit for evaluation. It runs on all major operating systems. It
44+is available [here](https://www.sublimetext.com/).
45+
46+#### Visual Studio Code
47+Visual Studio Code is free and open-source and runs on all major operating
48+systems. It is available [here](https://code.visualstudio.com/). Hoon support
49+may be acquired in the Extensions menu within the editor by searching for
50+`Hoon`.
51+
52+#### Emacs
53+
54+Emacs is free and open-source and runs on all major operating systems. It is
55+available [here](https://www.gnu.org/software/emacs/). Hoon support is available
56+with [hoon-mode.el](https://github.com/urbit/hoon-mode.el).
57+
58+#### Vim
59+
60+Vim is free and open-source and runs on all major operating systems. It is
61+available [here](https://www.vim.org/). Hoon support is available with
62+[hoon.vim](https://github.com/urbit/hoon.vim) and is maintained by Tlon.
development/grants.mdnew file+85
@@ -0,0 +1,85 @@
1++++
2+title = "Grants Program"
3+weight = 20
4+template = "doc.html"
5+aliases = ["/docs/using/creating-a-development-ship/", "/docs/getting-started/contributing"]
6++++
7+
8+The [Urbit Foundation](https://urbit.org/blog/first-steps-towards-urbit-org/)
9+runs a [Grants program](https://grants.urbit.org), where you can earn address
10+space ([stars](@/docs/glossary/star.md)) in exchange for contributing to the
11+project.
12+
13+Grants come in four different flavors at present: [bounties](#bounties),
14+[proposals](#proposals), [scholarships](#scholarships) and [gifts](#gifts).
15+
16+If you're curious about grants, join the conversation in Landscape at
17+`~wolref-podlex/foundation` or book some time to [talk with
18+us](https://calendly.com/wolref/30min).
19+
20+### Bounties {#bounties}
21+
22+[Bounties](https://grants.urbit.org/bounties) are specific, tightly-scoped
23+pieces of work that we at the Urbit Foundation think are of high value to the
24+ecosystem at large. They're frequently development-focused, but also often
25+relate to marketing, community-building or technical writing.
26+
27+Bounties are usually competitive&mdash;worker requests should provide plenty of
28+information about why the requester is right candidate for the job.
29+
30+### Proposals {#proposals}
31+
32+Where Bounties are put forward by the Foundation,
33+[Proposals](https://grants.urbit.org/proposals) come from the community. These
34+are things that our community thinks Urbit needs, and span a wide range of
35+topics: we've got [books being
36+written](https://grants.urbit.org/proposals/1590647060-a-book-about-urbit),
37+[videos being
38+produced](https://grants.urbit.org/proposals/1350087489-urbit-explainer-video),
39+help with [production of
40+events](https://grants.urbit.org/proposals/1751024973-urbit-event-series),
41+[marketing](https://grants.urbit.org/proposals/1395578140-smol-future-sustained-knowledge-sharing-and-marketing)
42+and
43+[documentation](https://grants.urbit.org/proposals/1888977136-graph-store-documenation-guide),
44+and
45+[ambitious](https://grants.urbit.org/proposals/21131866-webrtc-gall-agent-and-external-app)
46+[development](https://grants.urbit.org/proposals/1760204192-urbit-lfs)
47+[projects](https://grants.urbit.org/proposals/337545546-urbian-a-customized-linux-distribution-for-urbit-appliances)
48+all happening. If you've got skills and time to put into Urbit, we'll put you to
49+work.
50+
51+Proposals are more likely to be approved if their relevance to the project is
52+made clear, their scope is clearly defined, the proposer is qualified, and it's
53+obvious that a lot of thought has gone into the idea.
54+
55+If you've got an idea and want some help turning it into a proposal, book some
56+time with us [here](https://calendly.com/wolref/30min).
57+
58+### Scholarships {#scholarships}
59+
60+Scholarships are the newest addition to the grants program that pairs
61+contributors with core Urbit developers to tackle infrastructure projects. These
62+generally take the form of contributions to
63+[Arvo](@/docs/system-overview/arvo.md) or
64+[Vere](@/docs/system-overview/vere.md).
65+
66+Tackling a scholarship requires an advanced understanding of Urbit. It's
67+expected that you've got a demonstrated command of the Hoon language or other
68+part of Urbit through existing contributions on our repositories or successfully
69+completed grants.
70+
71+New scholarships are posted within the Foundation group in Landscape
72+(`~wolref-podlex/foundation`), and you can sign up for the waitlist using [this
73+form](https://airtable.com/shr6Xmo55h8dZ0O46).
74+
75+### Gifts {#gifts}
76+
77+Not every contribution is made with a plan or according to a specification.
78+Sometimes people just fix issues, help newcomers, or promote the project because
79+they want to.
80+
81+Roughly every six months we [give
82+out](https://urbit.org/blog/urbit-grants-and-mid-2019-gifts/) a [bunch of
83+address space](https://urbit.org/blog/gifts-q3-2020/) to those that have helped
84+the project without asking for anything in return, just because we want to. It
85+just feels good, man.
development/precepts.md+5−1
@@ -1,9 +1,13 @@
11+++
22title = "Precepts"
3−weight = 60
3+weight = 40
44template = "doc.html"
55+++
66
7+<br>
8+
9+<img class="ba" src="https://media.urbit.org/site/posts/essays/pre-01.jpg">
10+
711Urbit is a principled approach to system design and programming, but it's often not obvious what those principles are. We have many specific terms for the different parts of the project: Arvo is the OS, Hoon is the language, Tlon is the company, Azimuth is the identity system, Ames is the network. But the word most associated with the project is "Urbit", and it's not clear what technically it refers to. It's only a small stretch to say that "Urbit" *is* this set of principles, and that if anybody follows these principles strictly they will create a system that is isomorphic to the Urbit.
812
913Some of these are commonly held among many software projects, and some are not. Some are only debatably better than the alternatives, but Urbit exclusively chooses them.
development/project-repositories.mdnew file+49
@@ -0,0 +1,49 @@
1++++
2+title = "Project Repositories"
3+weight = 30
4+template = "doc.html"
5++++
6+
7+Here's a breakdown of the various repositories that comprise the project. All of
8+our code is hosted on GitHub, so you can of course peruse it there at
9+[https://github.com/urbit](https://github.com/urbit).
10+
11+### Urbit
12+
13+Urbit OS, the Landscape interface and Vere are all contained in one monolithic
14+repository that can be found [here](https://github.com/urbit/urbit). The repo is
15+large, so here's some links to its various high-level components
16+
17+- [Arvo](https://github.com/urbit/urbit/tree/master/pkg/arvo): the part of the urbit pepo that comprises Arvo, the Urbit OS.
18+- [Vere](https://github.com/urbit/urbit/tree/master/pkg/urbit): the part of the
19+ urbit repo that comprises the C and Haskell interpreters.
20+- [Landscape
21+ interface](https://github.com/urbit/urbit/tree/master/pkg/interface): the part
22+ of the urbit repo that contains the interface code for Landscape.
23+ - [Issue Tracker](https://github.com/urbit/landscape/issues): the Landscape issue
24+ tracker is a separate repository.
25+
26+### Urbit ID
27+
28+- [azimuth](https://github.com/urbit/azimuth): the public-key infrastructure
29+ (PKI) that comprises Urbit ID, live on the Etheereum blockchain.
30+- [bridge](https://github.com/urbit/bridge): an application for interacting with
31+ Azimuth that can be accessed at [bridge.urbit.org](https://bridge.urbit.org).
32+- [urbit-key-generation](https://github.com/urbit/urbit-key-generation): a javascript library for key derivation and HD
33+ wallet generation functions.
34+- [sigil-js](https://github.com/urbit/sigil-js): a javascript library for
35+ generating sigils.
36+
37+### Content
38+
39+- [urbit.org](https://github.com/urbit/urbit.org): the source for the urbit.org
40+ website.
41+- [docs](https://github.com/urbit/docs): the source for the documentation that
42+ you're currently reading.
43+ - *Note:* the documentation is loaded into the
44+ [urbit.org](https://github.com/urbit/urbit.org) repo as a submodule.
45+
46+### Community
47+
48+The best way to keep track of the various community projects is via our
49+[**awesome-urbit**](https://github.com/urbit/awesome-urbit) repository.
glossary/arvo.md+1−1
@@ -34,7 +34,7 @@ A ship creates its own copy of Arvo via a bootstrap sequence known as a
3434
3535### Further Reading
3636
37−- [The Arvo tutorial](@/docs/arvo/arvo.md): An in-depth technical
37+- [The Arvo tutorial](@/docs/arvo/overview.md): An in-depth technical
3838 guide to Arvo and its vanes.
3939- [The Technical Overview](@/docs/system-overview/_index.md): An
4040 overview of all of Urbit.
glossary/azimuth.md+1−1
@@ -14,5 +14,5 @@ It should be noted that Azimuth isn't built just for Arvo. It can be used as an
1414### Further Reading
1515
1616- [The Azimuth concepts page](@/docs/azimuth/advanced-azimuth-tools.md): A more in-depth explanation of Azimuth, including information the storage of Urbit identities.
17−- [Install instructions](@/using/install.md): Guide to installing Urbit, which includes instructions on booting with your Urbit identity.
17+- [Install instructions](@/getting-started.md): Guide to installing Urbit, which includes instructions on booting with your Urbit identity.
1818- [Understanding Urbit ID](@/understanding-urbit/urbit-id.md)
glossary/comet.md+1−1
@@ -12,4 +12,4 @@ Comets have no presence on [Azimuth](../azimuth) and thus have no associated Urb
1212
1313### Further reading
1414
15−- [Creating a Comet](@/using/install.md#comet): A guide to spinning up a comet of your own.
15+- [Creating a Comet](@/getting-started.md#comet): A guide to spinning up a comet of your own.
glossary/dojo.md−1
@@ -11,5 +11,4 @@ The other default command-line app is [Chat](../chat). To switch between Dojo
1111and [Chat](../chat) press Ctrl-X. The Dojo is the first thing you encounter after successfully booting your [ship](../ship).
1212
1313### Further Reading
14−- [Using Your Ship](@/using/os/using-your-ship.md): The "Shell" section contains instructions on using the Dojo.
1514- [Hoon Tutorial Lesson 1.1: Setup](@/docs/hoon/hoon-school/setup.md): A great way to get started with using Hoon in the Dojo.
glossary/keyfile.md+1−1
@@ -12,4 +12,4 @@ The keyfile is used as an argument in the command line when booting a ship. Duri
1212
1313### Further Reading
1414
15−- [Installation Guide](@/using/install.md): Instructions on using a keyfile to boot a ship.
15+- [Installation Guide](@/getting-started.md): Instructions on using a keyfile to boot a ship.
glossary/moon.md+2−1
@@ -12,4 +12,5 @@ Unlike planets, moons have no presence on [Azimuth](../azimuth) and have no asso
1212
1313### Further Reading
1414
15−- [Using Your Ship](@/using/os/using-your-ship.md#moons): The "Moons" section contains instructions for creating and managing moons.
15+- [Using Your Ship](@/using/os/getting-started.md#moons): The "Moons" section contains instructions for creating and managing moons.
16+
glossary/ship.md+1−1
@@ -20,7 +20,7 @@ To be able to use the Arvo network, planets, stars, and galaxies must be combine
2020
2121### Further Reading
2222
23−- [Using Bridge](@/using/install.md): A guide to installing Urbit and booting a ship.
23+- [Using Bridge](@/getting-started.md): A guide to installing Urbit and booting a ship.
2424- [Ship Troubleshooting](@/using/os/ship-troubleshooting.md): General instructions on getting your ship to work, which includes network connectivity issues.
2525- [Understanding Urbit ID](@/understanding-urbit/urbit-id.md)
2626- [Pier](../pier): The directory containing a ship's state.
glossary/vane.md+1−1
@@ -21,4 +21,4 @@ A **vane** is an [Arvo](../arvo) kernel module that performs essential system op
2121
2222### Further Reading
2323
24−- [The Arvo tutorial](@/docs/arvo/arvo.md): An in-depth technical guide to Arvo and its vanes.
24+- [The Arvo tutorial](@/docs/arvo/overview.md): An in-depth technical guide to Arvo and its vanes.
hoon/_index.md+4−2
@@ -5,9 +5,11 @@ sort_by = "weight"
55template = "sections/docs/chapters.html"
66+++
77
8−## [Why Hoon?](@/docs/hoon/whyhoon.md)
8+Hoon is Urbit's high-level general-purpose programming language.
99
10−An overview of why [Arvo](@/docs/arvo/arvo.md) was written using Hoon.
10+### [Overview](@/docs/hoon/overview.md)
11+
12+An overview of why [Arvo](@/docs/arvo/overview.md) was written using Hoon.
1113
1214### [Hoon School](@/docs/hoon/hoon-school/_index.md)
1315
hoon/hoon-school/_index.md+28−7
@@ -6,15 +6,36 @@ template = "sections/docs/hoon.html"
66aliases = ["/docs/byte/0/", "/docs/byte", "/docs/learn/hoon/hoon-tutorial/"]
77+++
88
9−This series is designed to teach you Hoon without assuming you have an extensive programming background. In fact, you should be able to follow much of it even if you have no programming experience at all, though of course experience helps. We strongly encourage you to try out all the examples of each lesson. These lessons are meant for the beginner but they aren't meant to be skimmed. Each lesson falls into one of two categories: **readings**, which are prose-heavy explanations of Hoon fundamentals, and **walkthroughs**, which are line-by-line explanations of example programs. Walkthroughs are found between readings, offering a practical implementation of the concepts taught in the reading before.
9+This series is designed to teach you Hoon without assuming you have an extensive
10+programming background. In fact, you should be able to follow much of it even if
11+you have no programming experience at all, though of course experience helps. We
12+strongly encourage you to try out all the examples of each lesson. These lessons
13+are meant for the beginner, but they aren't meant to be skimmed. Each lesson
14+falls into one of two categories: **readings**, which are prose-heavy
15+explanations of Hoon fundamentals, and **walkthroughs**, which are line-by-line
16+explanations of example programs. Walkthroughs are found between readings,
17+offering a practical implementation of the concepts taught in the reading
18+before.
1019
11−Before you start, we recommend reading [Why Hoon?](https://urbit.org/blog/why-hoon/), a blog post by a Tlon engineer that justifies the existence and use of this peculiar language. This explainer gives useful context to all types of learners, but those new to programming will need to use Google frequently for the jargon.
20+If you're curious about why Urbit is written in this new language, we recommend
21+reading the [Hoon overview](@/docs/hoon/overview.md) that covers the high-level
22+design decisions behind the language.
1223
13−Chapter 1 introduces and explains the fundamental concepts you need in order to understand Hoon's semantics.
24+Chapter 1 introduces and explains the fundamental concepts you need in order to
25+understand Hoon's semantics.
1426
15−Hoon is a "subject-oriented" programming language -- every expression of Hoon is evaluated relative to a **subject**. The subject is a piece of data that represents the environment, or the context, of an expression. After reading Chapter 1 you should understand what the subject is and how to refer to its various parts. In this chapter you'll also learn about **[cores](/docs/glossary/core/)**, which are an important data structure in Hoon. Once you get the hang of [cores](/docs/glossary/core/) you'll be able to write your own functions in Hoon.
27+Hoon is a "subject-oriented" programming language &mdash; every expression of
28+Hoon is evaluated relative to a **subject**. The subject is a piece of data that
29+represents the environment, or the context, of an expression. After reading
30+Chapter 1 you should understand what the subject is and how to refer to its
31+various parts. In this chapter you'll also learn about
32+**[cores](/docs/glossary/core/)**, which are an important data structure in
33+Hoon. Once you get the hang of [cores](/docs/glossary/core/) you'll be able to
34+write your own functions in Hoon.
1635
17−Chapter 2 covers the type system, and writing apps, and the workings of the Arvo kernel.
36+Chapter 2 covers the type system, writing basic apps, and the workings of the
37+Arvo kernel.
1838
19−You should also consider enrolling in Hooniversity, a regularly held community-run
20−course which follows along the Hoon School curriculum and may be found at [Hooniversity](https://hooniversity.org/).
39+You should also consider enrolling in Hooniversity, a regularly held
40+community-run course which follows along the Hoon School curriculum and may be
41+found at [Hooniversity](https://hooniversity.org/).
hoon/hoon-school/behn.md+1−1
@@ -16,7 +16,7 @@ Kernel code is generally kept to be as minimal as possible, and so almost anythi
1616
1717Vanes communicate with one another by exchanging chunks of data known as
1818`move`s. We will get into more detail above what a `move` is in our example of
19−Behn below, (and also see [move traces](@/docs/arvo/move-trace.md)) but at a high level one should think of a `move` as either a request from one vane to another or a response to a request. In our egg timer app, Gall and Behn will be exchanging `move`s.
19+Behn below, (and also see [move traces](@/docs/arvo/tutorials/move-trace.md)) but at a high level one should think of a `move` as either a request from one vane to another or a response to a request. In our egg timer app, Gall and Behn will be exchanging `move`s.
2020
2121Notably, vanes are _not_ something that a user ever interacts with directly. They live in an area of the memory called "kernel space", while all user processes live in [user space](https://en.wikipedia.org/wiki/User_space). Applications in user space make _system calls_ to the kernel, which the kernel may or may not obey (for security and stability purposes). These requests could be things such as asking for the time, getting the input of a hardware device, making an http request, or moving a file. In our egg timer app, we will be making system calls to ask Behn to handle the timer aspect.
2222
hoon/hoon-school/setup.md+3−3
@@ -15,9 +15,9 @@ These may not look like numbers, but they are. Each urbit name is written in a b
1515
1616## Installing Urbit
1717
18−You can install Urbit on any Mac or Unix machine; if you're just trying out Urbit or creating a development ship, you can follow the steps for creating a development ship [here](@/using/develop.md#creating-a-development-ship). On Windows, make a virtual Linux machine using VirtualBox or a similar tool.
18+You can install Urbit on any Mac or Unix machine; if you're just trying out Urbit or creating a development ship, you can follow the steps for creating a development ship [here](@/docs/development/environment.md). On Windows, make a virtual Linux machine using VirtualBox or a similar tool.
1919
20−Once you're finished, you can [boot your very own ship](@/using/install.md#comet). While you can develop in Hoon on your own ship on the live network, we strongly suggest developing on a development ship first.
20+Once you're finished, you can [boot your very own ship](@/getting-started.md#comet). While you can develop in Hoon on your own ship on the live network, we strongly suggest developing on a development ship first.
2121
2222## Getting started
2323
@@ -67,7 +67,7 @@ You asked Dojo to evaluate `17` and it echoed the number back at you. This value
6767
6868Generators are the most straightforward way to write Hoon programs. They are a concept in Arvo, and involve saving Hoon code in a `.hoon` text file. While they aren't strictly part of the Hoon language, we'll be dealing with generators throughout this tutorial.
6969
70−The simplest type of generator is the **naked generator**. All naked generators are `gates`: functions that take an argument and produce an output. Before creating a generator you need to [mount](@/using/install.md#the-dojo) your `desk` to Unix. To create a generator, all you need to do is write a `gate` and put it into a file in the `/home/gen/` directory of your ship as a `.hoon` file. (Assuming you've already mounted with `|mount /=home=`.) After this, you need to run `|commit %home` in Dojo and the new file will be recognized by your ship. To run a generator named `mygen.hoon`, you would type `+mygen <argument>` in your ship's Dojo.
70+The simplest type of generator is the **naked generator**. All naked generators are `gates`: functions that take an argument and produce an output. Before creating a generator you need to [mount](@/getting-started.md#the-dojo) your `desk` to Unix. To create a generator, all you need to do is write a `gate` and put it into a file in the `/home/gen/` directory of your ship as a `.hoon` file. (Assuming you've already mounted with `|mount /=home=`.) After this, you need to run `|commit %home` in Dojo and the new file will be recognized by your ship. To run a generator named `mygen.hoon`, you would type `+mygen <argument>` in your ship's Dojo.
7171
7272If this doesn't make sense yet, that's okay. In the [next lesson](@/docs/hoon/hoon-school/list-of-numbers.md), we will walk you through an example `gate` that is run as a generator.
7373
hoon/hoon-school/workbook/_index.mddeleted−17
@@ -1,17 +0,0 @@
1−+++
2−title = "Hoon Workbook"
3−weight = 150
4−sort_by = "weight"
5−template = "sections/docs/chapters.html"
6−aliase = ["docs/learn/hoon/workbook/"]
7−+++
8−The Workbook is the place to sharpen your Hoon skills. Each entry in the
9−Workbook is a code walkthrough followed by exercises.
10−
11−- The [Digits](@/docs/hoon/hoon-school/workbook/digits.md) example demonstrates how to decompose a number into a list of its digits.
12−
13−- The [Magic 8-Ball](@/docs/hoon/hoon-school/workbook/eightball.md) example emulates everyone's favorite decision-making machine.
14−
15−- The [Traffic-light](@/docs/hoon/hoon-school/workbook/traffic-light.md) example demonstrates how to creates a state machine in Hoon.
16−
17−- The [Bomb-defusing](@/docs/hoon/hoon-school/workbook/bomb.md) exercise shows how to program, well, a bomb-defusing scenario.
hoon/hoon-school/workbook/bomb.mddeleted−140
@@ -1,140 +0,0 @@
1−+++
2−title = "Bomb Defusing"
3−weight = 7
4−template = "doc.html"
5−aliases = ["docs/learn/hoon/workbook/bomb"]
6−+++
7−In this exercise, we will build a generator that takes a list of wires to be cut
8−in order to defuse a bomb. The bomb is defused according to the following rules.
9−
10−There are 6 possible colors of wire: white, black, purple, red, green, and
11−orange.
12−
13−If you cut a white cable, you cannot cut white or black cable.
14−
15−If you cut a red cable, you must cut a green cable.
16−
17−If you cut a black cable, you cannot cut a white, green, or orange cable.
18−
19−If you cut an orange cable, you must cut a red or cable.
20−
21−If you cut a green cable, you must cut an orange or white cable.
22−
23−If you cut a purple cable, you cannot cut a purple, green, orange, or white
24−cable.
25−
26−If the list of cuts does not result in the bomb exploding, the output should be
27−a tape `bomb defused`. If any of the rules were broken, it should output the
28−tape `boom`.
29−
30−
31−```hoon
32−!:
33−:- %say
34−|= [* [cuts=(list tape) ~] ~]
35−:- %noun
36−=<
37−(defuse cuts)
38−|%
39−++ defuse
40− |= cuts=(list tape)
41− =| bad=(list tape)
42− |-
43− ?~ cuts
44− "bomb defused"
45− =/ cut i.cuts
46− ?~ bad
47− $(bad (~(got by rules) cut), cuts t.cuts)
48− ?~ (find [cut ~] bad)
49− $(bad (~(got by rules) cut), cuts t.cuts)
50− "boom"
51−++ rules
52− %- ~(gas by *(map tape (list tape)))
53− :~ :- "white"
54− :~ "white"
55− "black"
56− ==
57− :- "red"
58− :~ "white"
59− "red"
60− "black"
61− "orange"
62− "purple"
63− ==
64− :- "black"
65− :~ "white"
66− "green"
67− "orange"
68− ==
69− :- "orange"
70− :~ "white"
71− "orange"
72− "green"
73− "purple"
74− ==
75− :- "green"
76− :~ "red"
77− "black"
78− "green"
79− "purple"
80− ==
81− :- "purple"
82− :~ "purple"
83− "green"
84− "orange"
85− "white"
86− ==
87− ==
88−--
89−```
90−
91−The start of our generator is simple enough. The `!:` in the first line enables
92−a full stack trace in the event of an error. The following three lines create a
93−`%say` generator that takes a list of tape as an argument.
94−
95−We next use the `=<` rune to compose two hoons, inverted. Remember that it's
96−good Hoon style is to have the heaviest parts to the bottom -- that's what we're
97−doing here.
98−
99−We call `defuse` and pass it `cuts`, the list of tapes we were provided with
100−when the generator started.
101−
102−Next is the [core](/docs/glossary/core/) that has two [arms](/docs/glossary/arm/), `defuse` and `rules`. Let's look at `rules`
103−quickly.
104−
105−We can see that it is a `map` of `tape` to `list` of `tape`. For each of the
106−rules above we have specified when you cut a wire, which of the other wires you
107−cannot cut. This required some reformulating of the rules given to use at the
108−start, but it is much simpler to work with.
109−
110−```hoon
111−++ defuse
112− |= cuts=(list tape)
113− =| bad=(list tape)
114− |-
115− ?~ cuts
116− "bomb defused"
117− =/ cut i.cuts
118− ?~ bad
119− $(bad (~(got by rules) cut), cuts t.cuts)
120− ?~ (find [cut ~] bad)
121− $(bad (~(got by rules) cut), cuts t.cuts)
122− "boom"
123−```
124−
125−The `defuse` arm is the meat of our program. It is a `gate` that takes a `list`
126−of `tape`. We combine a defaulted `list` of `tape` with the face `bad` with the
127−subject.
128−
129−If `cuts` is empty, the bomb has been successfully defused.
130−
131−Otherwise, we give `i.cuts`, the first item in the list, a face called `cut`.
132−
133−If `bad` is empty, we recurse. This recursion sets `bad` to be the list of
134−wires we can not cut from the `rules` map and make `cuts` `t.cuts` or the tail
135−of `cuts`, removing the first element of the list.
136−
137−If `bad` is not empty, we want to search inside of it for the current `cut`. If
138−it's not listed, then we are safe to continue and recurse to process the rest of
139−the cuts. However, if it is found in the bad list, the user has failed and the
140−bomb explodes.
hoon/hoon-school/workbook/digits.mddeleted−113
@@ -1,113 +0,0 @@
1−+++
2−title = "Digits"
3−weight = 4
4−template = "doc.html"
5−aliases = ["docs/learn/hoon/workbook/digits/"]
6−+++
7−Let's write a generator that takes a `@ud` (unsigned decimal) and returns a list
8−of its digits.
9−
10−```hoon
11−!:
12−:- %say
13−|= [* [n=@ud ~] ~]
14−:- %noun
15−=| lis=(list @ud)
16−|- ^+ lis
17−?: (lte n 0)
18− lis
19−%= $
20− n (div n 10)
21− lis (mod n 10)^lis
22−==
23−```
24−
25−We're creating a [`%say` generator](@/docs/hoon/hoon-school/generators.md). That means we
26−need some "boilerplate" code in the format of `[%say [%noun "data"]]`:
27−
28−```hoon
29−:- %say
30−|= [* [n=@ud ~] ~]
31−:- %noun
32−```
33−
34−The head of this cell is the literal `%say`.
35−
36−In the tail is the [gate](/docs/glossary/gate/) and its sample: `|= [* [n=@ud ~] ~]`. This is
37−where we describe any arguments we are expecting to be passed in when the
38−generator is called. We are expecting data of type `@ud`. We give the data the
39−face `n` so that we can easily reference it later.
40−
41−Also in the tail is another `cell`, its head indicating to the `dojo` how to
42−print the value we are creating. In this case, we use the generic `%noun`.
43−
44−The tail of our second cell is the product of the rest of the program.
45−
46−```hoon
47−=| lis=(list @ud)
48−```
49−
50−We use the above code to construct a `list` of `@ud` by cutting up the `@ud` we
51−got passed and so we add a face onto that type. This list is empty until we
52−manipulate it further.
53−
54−```hoon
55−|- ^+ lis
56−?: (lte n 0)
57− lis
58−```
59−
60−`|-` creates a gate that functions as a recursion point.
61−
62−We are actually able to reuse `lis` for the type of output that we are going
63−to produce. A sibling of the `^-` rune, `^+` is distinct because it is for
64−casting _by example_. It takes type information from an _instance_ of that type.
65−It's useful when using a complicated type.
66−
67−```hoon
68−?: (lte n 0)
69− lis
70−```
71−
72−`?:` checks if the statement that follows is true or false. In our case, if it's
73−true that `n` is less than or equal to `0`, we simply return `lis`. Otherwise,
74−we branch to the following operations:
75−
76−```hoon
77−%= $
78− n (div n 10)
79− lis (mod n 10)^lis
80−==
81−```
82−
83−`%=` is the rune that takes a wing with any number changes, in the
84−form of a list. Our list has two elements that represent such changes, contained
85−in a `$` expression to perform recursion. This is the tall form of an equivalent
86−syntax that you may be more familiar with:
87−`$(n (div n 10), lis (mod n 10)^lis)`.
88−
89−The first change divides `n` by `10`, rounding down without a remainder, and
90−assigning that product as the new value for `n`.
91−
92−The second change prepends the remainder of `n` divided `10` to `lis` (`x^y` is
93−an alternative syntax for `[x y]`). `mod` performs the modulo operation.
94−
95−Together, these operations will pull each digit out of `n` and put it into a
96−`list`. That's because dividing `n` by 10 will knock off one decimal place from
97−the value, and `mod` will store the actual discarded digit. To visualize this
98−complementarity, let's run some operations in the dojo:
99−
100−```hoon
101−> (div 146 10)
102−14
103−
104−> (mod 146 10)
105−6
106−```
107−
108−* TODO What if we do this with vases? Can we accept a vase, map it to whatever
109−the correct value would be to extract each digit of the number in whatever base
110−we are interpreting it in?
111−
112−* TODO from Rob: we need a few exercises here. Maybe asking the reader to
113−make one that accepts a vase could be one?
hoon/hoon-school/workbook/eightball.mddeleted−158
@@ -1,158 +0,0 @@
1−+++
2−title = "Magic 8-Ball"
3−weight = 5
4−template = "doc.html"
5−aliases = ["docs/learn/hoon/workbook/eightball"]
6−+++
7−In this lesson we'll write a generator that mimics the functionality of a
8−Magic 8-Ball, producing a randomized response with each run.
9−
10−Save the code below as `eightball.hoon` in your `/gen` directory.
11−
12−```hoon
13−!:
14−:- %say
15−|= [[* eny=@uv *] *]
16−:- %noun
17−^- tape
18−=/ answers=(list tape)
19− :~ "It is certain."
20− "It is decidedly so."
21− "Without a doubt."
22− "Yes - definitely."
23− "You may rely on it."
24− "As I see it, yes."
25− "Most likely."
26− "Outlook good."
27− "Yes."
28− "Signs point to yes."
29− "Reply hazy, try again"
30− "Ask again later."
31− "Better not tell you now."
32− "Cannot predict now."
33− "Concentrate and ask again."
34− "Don't count on it."
35− "My reply is no."
36− "My sources say no."
37− "Outlook not so good."
38− "Very doubtful."
39− ==
40−=/ rng ~(. og eny)
41−=/ val (rad:rng (lent answers))
42−(snag val answers)
43−```
44−
45−Let's go through our code in chunks so that we might more easily understand it.
46−
47−```hoon
48−!:
49−```
50−
51−We start with the `!:` rune to enable a full stack trace for any errors. This
52−is good practice whenever developing something in Hoon.
53−
54−
55−```hoon
56−:- %say
57−|= [[* eny=@uv *] *]
58−:- %noun
59−```
60−
61−To make our program produce a random result, we need entropy. To get entropy,
62−we need data from Arvo. To get data from Arvo, we use a generator of the
63−[`%say`](@/docs/hoon/hoon-school/generators.md) variety. The above code chunk is
64−the template that is followed for all `%say` generators.
65−
66−`:- %say` creates a cell with `%say` as that cell's head to define
67−the generator's format.
68−
69−`|= [[* eny=@uv *] *]` is the tail of the cell, a [gate](/docs/glossary/gate/), and that gate's first
70−child, a sample. Because the only external data our program is interested in
71−using is entropy to seed our random-number generator, that's the only one we
72−will assign a face (`eny`). The `*` elements that you see represent any [noun](/docs/glossary/noun/). We
73−use these as fillers: because we don't wish to use the data that's passed to
74−those parts of the sample, we don't assign them faces.
75−
76−`:- %noun` creates another cell, itself residing in the tail of our first cell
77−via our gate expression. In all `%say` generators, the head of this second cell
78−is a `mark` that's used to tell Arvo what kind of data the generator is
79−producing. In this case, we are using the `%noun` `mark` to tell the system how
80−to print the generator's outputted value. The tail of this cell is that value
81−itself, produced by the rest of our program.
82−
83−```hoon
84−^- tape
85−```
86−
87−Above is a cast statement that requires the non-`mark` component of our cell to
88−be of the `tape` type. If it's not, the program doesn't compile.
89−
90−```hoon
91−=/ answers=(list tape)
92− :~ "It is certain."
93− "It is decidedly so."
94− "Without a doubt."
95− "Yes - definitely."
96− "You may rely on it."
97− "As I see it, yes."
98− "Most likely."
99− "Outlook good."
100− "Yes."
101− "Signs point to yes."
102− "Reply hazy, try again"
103− "Ask again later."
104− "Better not tell you now."
105− "Cannot predict now."
106− "Concentrate and ask again."
107− "Don't count on it."
108− "My reply is no."
109− "My sources say no."
110− "Outlook not so good."
111− "Very doubtful."
112− ==
113−```
114−
115−The code in the chunk above constructs the list of possible responses.
116−
117−`=/ answers=(list tape)` is used to put add data to the subject with a face,
118−so that we can easily use it later. The face is `answers`, and we designate that
119−its accompanying value will be a `list` of `tape`. The value itself is given
120−as a `list` in the lines that follow.
121−
122−`:~` is a rune that constructs a null-terminated list. Here we have used the
123−tall form for readability, as an alternative to the wide form of `~[1 2 3]` that
124−you may be more familiar with.
125−
126−Contained within the `:~` rune are the elements of the list. In our case, those
127−elements are the `tape`s that are selected as the 8-Ball's responses.
128−
129−`==` terminates our list. `:~` expressions are always closed in this way.
130−
131−```hoon
132−=/ rng ~(. og eny)
133−=/ val (rad:rng (lent answers))
134−```
135−
136−The code above is our random-number engine.
137−
138−`og` is the [core](/docs/glossary/core/) in the standard library that contains [arms](/docs/glossary/arm/) that perform
139−randomness-related operations. `=/ rng ~(. og eny)` passes `eny` to the
140−subject of `og`, and then stores the resulting core in a face called `rng`.
141−
142−`=/ val (rad:rng (lent answers))` uses `rad` arm. `rad` produces a random
143−number from `0` to `n-1`, where `n` the entropy-seeded `rng` core and pulls.
144−Is the upper bound that we give it. In this case, the upper bound is the number
145−of elements in `answers`, obtained by using the `lent` standard-library arm. We
146−store the random result in `val`.
147−
148−```hoon
149−(snag val answers)
150−```
151−
152−`snag` is a standard-library arm that that takes two arguments: an [atom](/docs/glossary/atom/) and
153−a `list`. It fetches the element in position `n` of the list, where `n` is the
154−value of the atom it was passed. By using the randomized `val` as that position
155−argument, we can pull a different response from `answers` every time the
156−generator is run.
157−
158−TODO (rob): Exercises here.
hoon/hoon-school/workbook/traffic-light.mddeleted−155
@@ -1,155 +0,0 @@
1−+++
2−title = "Traffic Light"
3−weight = 6
4−template = "doc.html"
5−aliases = ["docs/learn/hoon/workbook/traffic-light/"]
6−+++
7−Let's create a state machine in Hoon that models the functionality of a traffic
8−light. Save the code below as `traffic.hoon` in your `/gen` directory.
9−
10−```hoon
11−:- %say
12−|= *
13−:- %noun
14−=+ |%
15− ++ state ?(%red %yellow %green)
16− --
17−=/ current-state=state %red
18−=+ ^= traffic-light
19− |%
20− ++ look current-state
21− ++ set
22− |= s=state
23− +>.$(current-state s)
24− --
25−=+ a=traffic-light
26−=+ b=traffic-light
27−=. a (set.a %yellow)
28−[current-state.a current-state.b]
29−```
30−
31−Let's look at the code piece-by-piece.
32−
33−```hoon
34−:- %say
35−|= *
36−:- %noun
37−```
38−
39−Here's the boilerplate code to designate our generator as being a
40−[`%say` generator](@/docs/hoon/hoon-school/generators.md). We're using this variant because
41−it allows us to run the generator without any arguments. It's otherwise not
42−relevant to the functionality of our program.
43−
44−```hoon
45−=+ |%
46− ++ state ?(%red %yellow %green)
47− --
48−```
49−
50−`=+` adds a [noun](/docs/glossary/noun/) to the subject. In our case, the [noun](/docs/glossary/noun/) in question is the [core](/docs/glossary/core/)
51−that is opened with `|%` and closed with `--`. This core is used to store types,
52−and does that with the [arm](/docs/glossary/arm/) that it contains.
53−
54−`++ state` creates an arm called `state`, which will be used as the name of the
55−new type that is created in the code that follows, `?(%red %yellow %green)`.
56−That following code creates a new type from the union of its elements. In this
57−case, the state can be one of three values: `%red`, `%yellow`, or `%green`
58−corresponding to the three colors of a standard traffic light.
59−
60−Having new types in a separate core is a common idiom in Hoon programs that allows
61−the compiler to do [constant folding](https://en.wikipedia.org/wiki/Constant_folding),
62−which improves performance.
63−
64−```hoon
65−=/ current-state=state %red
66−```
67−
68−The line above creates a noun of type `state` - the type that we created with
69−the arm in previous code chunk - and gives it a default value. Because we are
70−putting this noun into the subject, it will be available for use in the
71−`traffic-light` core we are about to create.
72−
73−```hoon
74−=+ ^= traffic-light
75− |%
76− ++ look current-state
77− ++ set
78− |= s=state
79− +>.$(current-state s)
80− --
81−```
82−
83−`=+ ^= traffic-light` does two things. The `^=` rune assigns a face to that
84−noun so it's easier to reference. The `=+` rune adds a noun to the subject, in
85−this case the core that we just assigned a name and start to build on the next
86−line and assigned the name.
87−
88−With `|%`, we are finally at the meat of the program. This core that we just
89−named has two arms: `look`, which gives us the current state, defined later; and
90−`set`, which gives us a simple way to modify the value of `current-state`.
91−
92−The [gate](/docs/glossary/gate/) we are producing with `|=` may look a bit strange, so let's break it
93−down.
94−
95−`s=state` allows for an argument of type `state` and gives it a face `s`.
96−
97−We first produce a core with one arm named `$`. That `$` arm will produce a new
98−core with `current-state` changed to match the `s` provided when it was called.
99−How does this work?
100−
101−Remember that `.` is [wing syntax](@/docs/hoon/reference/limbs/wing.md) that
102−applies the wing expression on the left of it to the noun to the right of it.
103−`$` is the arm of the core. Then by using the wing expression `+>`, which means
104−"return the tail of the tail", we traverse the subject to the core to latch onto
105−its parent core. where we defined the arms `look` and `set`. The `( )` then
106−lists changes to the core we would like to make as we produce a new one. You
107−will often see `+>.$` used in this way.
108−
109−```hoon
110−=+ a=traffic-light
111−=+ b=traffic-light
112−```
113−
114−Now we have the last parts of our program. Remember that `=+` allows us to add a
115−noun to the head of the subject. In this case, we are adding two nouns, one with
116−the face `a` and a second with the face `b`. These two nouns will be copies of
117−the `traffic-light` core, with all the bits we previously created.
118−
119−```hoon
120−=. a (set.a %yellow)
121−```
122−
123−`=.` changes a leg in the subject. We use the `set` arm on `a` to produce a gate
124−and give that the argument of `%yellow`. Remember that we are actually producing
125−a new core in the gate, so we have to then assign that back to the face `a`.
126−
127−```hoon
128−[current-state.a current-state.b]
129−```
130−
131−Here we simply are creating a new cell that has the `current-state` from `a` as
132−its head and the `current-state` from `b` as its tail.
133−
134−Let's run it in the Dojo to get our product:
135−
136−```
137−> +traffic
138−[%yellow %red]
139−```
140−
141−### Exercises
142−
143−1. Modify the generator to include a way to cycle the light without
144−explicitly having to select the next color. That is, if the light is currently
145−`%green` then the next color would be `%yellow`. If `%yellow` then the next
146−color should be `%red`.
147−
148−2. Using what you have learned about creating state machines in Hoon,
149−produce a state machine that can act as a vending-machine emulator. It should
150−keep track of the amount of items it has, as well as the amount of money that an
151−item costs. To keep it simple, assume this vending machine only has one item for
152−sale.
153−
154−3. Modify your vending machine from exercise 2 to support holding multiple items
155−with different prices.
hoon/whyhoon.md → hoon/overview.mdrenamed+7
@@ -4,6 +4,13 @@ weight = 2
44template = "doc.html"
55+++
66
7+We are often asked why Urbit was written in a new language, rather than some
8+existing language like Haskell or C. This document provides the high-level
9+rationale for that decision, and also covers some of the features of the
10+language that set it apart from others. If you're looking to learn Hoon, check
11+out our tutorial series called [Hoon School](@/docs/hoon/hoon-school/_index.md)
12+below.
13+
714### What can Hoon do that other languages can't?
815
916The short answer is: implement a purely functional operating system.
hoon/reference/advanced.md+23−20
@@ -18,27 +18,29 @@ large functions. Don't worry about them for a little while.
1818 $@ $? %noun
1919 %void
2020 ==
21− $% [$atom p=term q=(unit @)]
22− [$cell p=type q=type]
23− [$core p=type q=coil]
24− [$face p=$@(term tune) q=type]
25− [$fork p=(set type)]
26− [$hint p=(pair type note) q=type]
27− [$hold p=type q=hoon]
21+ $% [%atom p=term q=(unit @)]
22+ [%cell p=type q=type]
23+ [%core p=type q=coil]
24+ [%face p=$@(term tune) q=type]
25+ [%fork p=(set type)]
26+ [%hint p=(pair type note) q=type]
27+ [%hold p=type q=hoon]
2828 ==
2929::
30−+$ coil $: p=[p=(unit term) q=poly r=vair]
31− q=type
32− r=[p=seminoun q=(map term tome)]
30++$ coil $: p=garb :: name, wet=dry, vary
31+ q=type :: context
32+ r=(pair seminoun (map term tome)) :: chapters
33+ == ::
3334::
35++$ garb (trel (unit term) poly vair) :: core
3436+$ poly ?(%wet %dry)
35−+$ vair ?($gold $iron $lead $zinc)
37++$ vair ?(%gold %iron %lead %zinc)
3638+$ tome (pair what (map term hoon))
37−+$ tune
38− $~ [~ ~]
39− $: p=(map term (unit hoon))
40− q=(list hoon)
41− ==
39++$ tune :: complex
40+ $~ [~ ~] ::
41+ $: p=(map term (unit hoon)) :: aliases
42+ q=(list hoon) :: bridges
43+ == ::
4244```
4345
4446If you compare this to the basic `type`, you'll see that we've
@@ -66,8 +68,9 @@ the payload the core was compiled with is `q.q`.
6668
6769In the Bertrand Meyer tradition of type theory, there are two
6870forms of polymorphism: variance and genericity. In Hoon this
69−choice is per core, hence the `poly` label in `coil`: it can be either `%wet` or `%dry`. Dry polymorphism relies on variance; wet
70−polymorphism relies on genericity.
71+choice is per core, hence the `poly` label in `p.q`: it can be either `%wet`
72+or `%dry`. Dry polymorphism relies on variance; wet polymorphism relies on
73+genericity.
7174
7275### Dry arms
7376
@@ -188,13 +191,13 @@ of secret superpowers for hacking the namespace. Remember that
188191Hoon doesn't have anything like a symbol table; to resolve a
189192limb, we just search the type depth-first.
190193
191−If a name is in the `p.p` map, it's an alias. (An alias is defined using the
194+If a name is in the `p.p` `map`, it's an alias. (An alias is defined using the
192195`=*` rune.) The map contains a `(unit hoon)`; if the unit is full, the name
193196resolves to that hoon (compiled against the `q` type). If the unit is empty,
194197the name is blocked / skipped (see [limb](@/docs/hoon/reference/limbs/limb.md) for what
195198this means).
196199
197−If a name is in the `q.p` map, it's a bridge. (A bridge is defined using the
200+If a name is the `q.p` `term`, it's a bridge. (A bridge is defined using the
198201`=,` rune.) When we search for a name, we also compile the bridge, and check
199202if the name resolves against the bridge product. If so, we use it.
200203
hoon/reference/auras.md+1−1
@@ -8,7 +8,7 @@ Auras are system of nested "soft types" on [atoms](@/docs/glossary/atom.md) that
88are used to track metadata about how a particular atom is to be interpreted.
99This is used for type checking as well as pretty printing.
1010
11−You can learn more about auras in [Hoon school](@/docs/hoon/hoon-school/atoms-auras-and-simple-types.md).
11+You can learn more about auras in [Hoon school](@/docs/hoon/hoon-school/atoms-auras-and-simple-cell-types.md).
1212
1313### Table of Auras
1414
hoon/reference/rune/sig.md+4−1
@@ -3,7 +3,10 @@ title = "Hints ~ ('sig')"
33weight = 14
44template = "doc.html"
55+++
6−Runes that use Nock `11` to pass non-semantic info to the interpreter.
6+Runes that use Nock `11` to pass non-semantic info to the interpreter. A
7+mnemonic to remember what sig runes are for is "we're *sig*naling some
8+information to the interpreter".
9+
710
811## Runes
912
landscape/_index.md+6−2
@@ -5,9 +5,13 @@ sort_by = "weight"
55template = "sections/docs/chapters.html"
66+++
77
8+While not technically part of Urbit, Landscape serves as a reference
9+implementation for how to build applications in user space.
810
9−## [Landscape Architecture](@/docs/landscape/arch.md)
11+## [Landscape Architecture](@/docs/landscape/overview.md)
1012
1113An overview of how Landscape, our flagship client, is structured.
1214
13−## [API Reference](@/docs/landscape/apiref/_index.md)
15+## [API Reference](@/docs/landscape/reference/_index.md)
16+
17+API documentation about specific agents that comprise Landscape.
landscape/arch.mddeleted−19
@@ -1,19 +0,0 @@
1−+++
2−title = "Overview"
3−weight = 4
4−template = "doc.html"
5−+++
6−
7−Landscape is designed using a particular userspace architecture mode consisting of stores, hooks, and threads.
8−
9−## Stores
10−
11−Stores are the first of the two gall models to form this architecture. A store is intended to maintain all the state required for an application or set of applications. Stores are intended to be only accessible by the ship it's running on. A store may not send pokes, peeks, or watches. A store should be treated and thought of as a database. While this is not enforced, it is the convention. The primary example of a store is `graph-store` which can be found at `app/graph-store`
12−
13−## Hooks
14−
15−Hooks are the second gall application used in this architecture and are not always present. Hooks are used for inter-app communication. This allows a separation of access control concerns and a division between those things which are able to be done by a store itself and those done by another gall application. `graph-store` in particular has two hooks `graph-pull-hook` for outgoing requests, and `graph-push-hook` for incoming requests.
16−
17−## Threads
18−
19−Threads are used when you want to have a series of transactions on a store where the order of those transactions matters. No guarantees are made about the order in which individual requests to a gall applications are processed; threads were introduced to address this. Threads do not maintain their own state while inactive and are instead run only upon request. A good example is `ted/graph/create`
landscape/overview.mdnew file+195
@@ -0,0 +1,195 @@
1++++
2+title = "Overview"
3+weight = 1
4+template = "doc.html"
5++++
6+
7+![landscape](https://storage.googleapis.com/media.urbit.org/tlon/landscapes.png)
8+
9+The architecture of Landscape’s userspace application suite has gone through a
10+number of overhauls in the past few years, and each iteration has gotten closer
11+to a point where Urbit’s userspace can truly perform as a next-generation social
12+suite built entirely on distributed networking and individual-owned personal
13+servers.
14+
15+As of this year, this application suite has arrived at a point where we’re
16+confident both in how all the parts fit together, and confident in the
17+individual parts.
18+
19+
20+## What is Landscape Intended to Be?
21+
22+Landscape is a single suite of userspace applications built to run on top of
23+Urbit. Landscape is maintained by [Tlon](https://tlon.io), a for-profit corporation that helps
24+research Urbit. Landscape is one of many possible application suites for Urbit,
25+and we hope many others emerge that build on top of the Arvo kernel. We plan on
26+making Landscape itself more extensible for user-developers in late 2021.
27+
28+Landscape is specifically a social suite of applications, meant to enable
29+communication and socializing in many forms.
30+
31+
32+## What is Landscape technically composed of?
33+
34+Landscape is composed of two primary parts: its backend, which runs as a suite of userspace applications (also known as Gall agents), and its frontend interface, which runs as a single-page web application. Both the backend and the frontend may be decomposed into their constituent parts for further understanding.
35+
36+
37+### Backend
38+
39+The Landscape backend is implemented as a collection of long-running
40+microservices known as [Gall agents](@/docs/arvo/gall/gall.md). They can be divided into the following,
41+though this is a simplification:
42+
43+- **Graph**: handles storing messages / posts in a non-relational database
44+- **Groups**: organizes people into groups and roles and handles permissioning
45+- **Metadata**: a database join between graphs and groups, it also provides
46+ titles and descriptions for graphs and groups
47+- **Contacts**: handles nicknames, profile pictures, and ship-related metadata
48+- **Invites**: a generic inviting subsystem that is used for joining graphs or groups
49+- **Hark**: a notification subsystem for keeping track of read state and
50+ notifying users
51+
52+Each of these components are built out using a few microservices that handle
53+more specific responsibilities. These responsibilities can be subdivided into
54+two main categories: [stores](#stores) and [hooks](#hooks). To simply describe
55+the separation of responsibilities, stores are dumb databases (models in MVC)
56+and hooks are for processing data (controllers in MVC).
57+
58+
59+### Stores {#stores}
60+
61+Concisely defined, a store is a dumb database. It does not send outgoing pokes,
62+watches, or peeks, except in an `+on-load` to migrate its state. It does store
63+permanent and/or temporary state, allows incoming peeks/watches to read that
64+data, and allows pokes to modify that data. A store may only accept local reads
65+and writes, not remote ones. It may or may not interact with various kernel
66+modules. Examples include:
67+[graph-store](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/app/graph-store.hoon),
68+[group-store](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/app/group-store.hoon),
69+[metadata-store](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/app/metadata-store.hoon),
70+[contact-store](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/app/contact-store.hoon),
71+and
72+[invite-store](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/app/invite-store.hoon).
73+
74+
75+### Hooks {#hooks}
76+
77+A hook is a more loosely-defined agent that performs business logic. It should
78+only keep track of a minimal amount of state (*e.g.* active subscriptions). Hooks
79+are used for a variety of purposes in the system, but there are a few important
80+hook patterns to be aware of:
81+
82+#### Pull Hooks
83+
84+A pull-hook syncs data from a remote resource down to a local resource. There is
85+a
86+[pull-hook](https://github.com/urbit/urbit/blob/master/pkg/arvo/lib/pull-hook.hoon)
87+library that drastically simplifies the implementation of such a hook, and is
88+the defacto standard for how to sync down remote data to your ship.
89+
90+#### Push Hooks
91+
92+A push-hook allows remote ships to subscribe to and sync down the information
93+from a local resource. There is a [push-hook
94+library](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/lib/push-hook.hoon)
95+that drastically simplifies the implementation of such a hook, and is the
96+defacto standard for how to make local data available to remote ships.
97+
98+#### Observe Hook
99+
100+The observe-hook subscribes to data coming in from another agent, and starts up
101+a thread of computation every time a subscription update from that agent is
102+received.
103+
104+#### Poke-Proxy Hook
105+
106+The poke-proxy-hook conditionally forwards a poke from a foreign ship to a store
107+on the local ship if the foreign ship has permission to do so.
108+
109+
110+### Major Components
111+
112+#### Groups
113+
114+Groups are the core building block of data permissioning within Landscape. A
115+group is made up of the following fields:
116+
117+```
118++$ group
119+ $: members=(set ship)
120+ =tags
121+ =policy
122+ hidden=?
123+ ==
124+```
125+
126+- `members` is a set of ships that are at present in the group
127+- `tags` are strings that may define additional permissions or roles within the
128+ group
129+- The `policy` defines whether a group is open to new members, is invite-only, or
130+ has some other scheme
131+- `hidden` is a boolean flag that determines whether the group’s lifecycle is
132+ attached to a single external resource (such as a chat DM, which when the DM
133+ is deleted, the group is deleted too), or whether it has an independent life
134+ of its own. This flag also determines whether the group should show up in
135+ interfaces as something that may be managed and edited.
136+
137+The `%group-store` holds a map of these groups and allows subscriptions to their
138+data. The group-store may be accessed from foreign ships through the use of the
139+`%group-pull-hook` and `%group-push-hook`. Groups may be joined either by
140+manually discovering and pasting in a group name into the “join group” dialogue
141+in the interface for an open group, or by accepting an invite to an invite-only
142+group. When a group is deleted, all data related to it is deleted or archived as
143+well.
144+
145+#### Graphs
146+
147+Graphs are the core place where we store social user-generated content: chat
148+messages, social network posts, blog posts, links, and eventually multimedia.
149+Graph store is built to be flexible enough to support many different types of
150+“apps” built on top of it, whether you want to have a forum with some friends, a
151+Pinterest equivalent, a more private version of Facebook, a decentralized
152+Reddit, or an even more distributed version of Mastodon. You can read more about
153+graph-store by [viewing the
154+source](https://github.com/urbit/urbit/blob/ac096d85ae847fcfe8786b51039c92c69abc006e/pkg/arvo/app/graph-store.hoon)
155+or reading our [API Reference](@/docs/landscape/reference/graph-store.md) documentation.
156+
157+The `%graph-store` may be accessed from foreign ships through the use of the
158+`%graph-pull-hook` and `%graph-push-hook`.
159+
160+#### Metadata
161+
162+Metadata is stored in the `%metadata-store`, and is where we store metadata
163+about resources (ex: graphs or groups). We store their display name,
164+description, a color, and the date they were added. We also store what group the
165+resource is associated with, what app the resource is associated with, and what
166+module (display mode) the resource should be used with.
167+
168+Metadata within the broader context of the userspace application suite can best
169+be thought of as a database join between the `%group-store` and the
170+`%graph-store`, as it provides bidirectional indices for querying all of the
171+graphs that a group has, or which group a particular graph is associated with.
172+
173+
174+#### Contacts
175+
176+Contacts are your address book. Individual ships (people) you talk to may have a
177+ nickname, a profile picture, or a colored sigil background that helps you
178+ identify them in groups, chatrooms, blogs, and collections.
179+
180+
181+#### Invites
182+
183+Invites is a simple subsystem that allows you to send all the details of a given
184+resource (*e.g.* graph or group) to some other ship so that they may join it if
185+they desire to. Invite acceptance is handled with threads that listen to the
186+`%invite-store` using the `%observe-hook` and invite sending is handled with the
187+`%invite-hook`, which allows any ship to send you an invite without any
188+permissions involved.
189+
190+
191+#### Hark
192+
193+Hark is a generic notification and unread-tracking subsystem that currently
194+keeps track of all unread functionality for the system. The `%hark-graph-hook`
195+sends data about `%graph-store` events to `%hark-store`.
landscape/apiref/_index.md → landscape/reference/_index.mdrenamed+1−1
@@ -5,6 +5,6 @@ sort_by = "weight"
55template = "sections/docs/chapters.html"
66+++
77
8−## [Graph Store](@/docs/landscape/apiref/graph.md)
8+## [Graph Store](@/docs/landscape/reference/graph-store.md)
99
1010The primary data backend utilized by Landscape.
landscape/apiref/graph.md → landscape/reference/graph-store.mdrenamed+6−4
@@ -4,9 +4,11 @@ weight = 3
44template = "doc.html"
55+++
66
7−# What is Graph Store?
8−
9−Graph Store is a gall implementation of a tree with additional virtual edges by allowing nodes to reference other nodes. It is most comparable to modern NoSQL databases in structure, though it allows for schemas to be written in the form of marks. It is used as the backend for an increasing number of Landscape applications, and is considered to be best used for social data.
7+`graph-store` is a gall agent that implements of a tree with additional virtual
8+edges by allowing nodes to reference other nodes. It is most comparable to
9+modern NoSQL databases in structure, though it allows for schemas to be written
10+in the form of marks. It is used as the backend for an increasing number of
11+Landscape applications, and is considered to be best used for social data.
1012
1113## Data types
1214
@@ -155,4 +157,4 @@ What follows is a summary of the scrys available in graph-store
155157
156158## Marks
157159
158−There are marks in `mar/graph/validator` that are worth reviewing. They are each short enough to read quickly. They are used to validate the shapes of various nouns to be stored in the graph-store.
160+There are marks in `mar/graph/validator` that are worth reviewing. They are each short enough to read quickly. They are used to validate the shapes of various nouns to be stored in the graph-store.
system-overview/_index.md+12−9
@@ -1,6 +1,6 @@
11+++
22title = "System Overview"
3−weight = 100
3+weight = 200
44sort_by = "weight"
55template = "sections/docs/chapters.html"
66+++
@@ -10,15 +10,18 @@ network of general-purpose personal servers. Each server on this network is a
1010deterministic computer called an 'urbit' that runs on a Unix-based virtual
1111machine.
1212
13−The current Urbit stack includes (among other things):
13+The Urbit stack is primarily comprised of:
1414
15−- Arvo: the functional operating system of each urbit, written in Hoon.
16−- Azimuth: the Urbit identity layer, built on the Ethereum blockchain.
17−- Hoon: a strictly typed functional programming language whose standard library
18− includes a Hoon-to-Nock compiler.
19−- Nock: a low-level combinator language whose formal specification fits readably on a t-shirt.
20−- Vere: a Nock interpreter and Unix-based virtual machine that mediates between
21− each urbit and the Unix software layer.
15+- [Arvo](@/docs/system-overview/arvo.md): the functional operating system of
16+ each urbit, written in Hoon.
17+- [Hoon](@/docs/system-overview/hoon.md): a strictly typed functional
18+ programming language whose standard library includes a Hoon-to-Nock compiler.
19+- [Nock](@/docs/system-overview/nock.md): a low-level combinator language whose
20+ formal specification fits readably on a t-shirt.
21+- [Vere](@/docs/system-overview/vere.md): a Nock interpreter and Unix-based
22+ virtual machine that mediates between each urbit and the Unix software layer.
23+- [Azimuth](@/docs/system-overview/azimuth.md): the Urbit identity layer, built
24+ on the Ethereum blockchain.
2225
2326## Anatomy of a personal server
2427
system-overview/arvo.md+13−13
@@ -4,19 +4,19 @@ weight = 10
44template = "doc.html"
55+++
66
7−Arvo is a purely functional, [non-preemptive](https://en.wikipedia.org/wiki/Cooperative_multitasking)
8−OS, written in Hoon, that serves as the event manager of your urbit.
9−It can upgrade itself from over the network without downtime. The Arvo kernel
10−proper is quite simple -- it's only about 600 lines of code, excluding its
11−various modules.
7+Arvo is a purely functional,
8+[non-preemptive](https://en.wikipedia.org/wiki/Cooperative_multitasking) OS,
9+written in Hoon, that serves as the event manager of your urbit. It can upgrade
10+itself from over the network without downtime. The Arvo kernel proper is quite
11+simple -- it's only about 600 lines of code, excluding its various modules.
1212
13−The Urbit transition function is implemented in Arvo. Upon being 'poked' by
14−Vere with the pair of `<input event, state>`, Arvo directs the event to the
15−appropriate OS module. The result of each Vere 'poke' is a pair of
16−`<output events, new state>`. Events are typed, and each has an explicit
17−call-stack structure indicating the event's source module in Arvo.
13+The Urbit transition function is implemented in Arvo. Upon being 'poked' by Vere
14+with the pair of `<input event, state>`, Arvo directs the event to the
15+appropriate OS module. The result of each Vere 'poke' is a pair of `<output
16+events, new state>`. Events are typed, and each has an explicit call-stack
17+structure indicating the event's source module in Arvo.
1818
19−For a more in-depth technical introduction, see [Arvo Overview](@/docs/arvo/arvo.md).
19+For a more in-depth technical introduction, see [Arvo Overview](@/docs/arvo/overview.md).
2020
2121Arvo modules are also called 'vanes'. Arvo's vanes are:
2222
@@ -28,6 +28,6 @@ Arvo modules are also called 'vanes'. Arvo's vanes are:
2828- [Dill](@/docs/arvo/dill/dill.md): terminal driver.
2929- [Eyre](@/docs/arvo/eyre/eyre.md): HTTP server.
3030- [Gall](@/docs/arvo/gall/gall.md): application sandbox and manager.
31−- [Iris](@/docs/glossary/iris.md): HTTP client.
32−- [Jael](@/docs/glossary/jael.md): Public and private key storage.
31+- [Iris](@/docs/arvo/iris/iris-api.md): HTTP client.
32+- [Jael](@/docs/arvo/jael/jael-api.md): Public and private key storage.
3333
system-overview/azimuth.md+5−8
@@ -25,13 +25,10 @@ is the neighborhood that you live in.
2525
2626## Further Reading
2727
28−### [Azimuth](@/docs/azimuth/azimuth.md)
29−
30−An overview of the Ethereum-based public key infrastructure utilized by Urbit.
31−
32−### [Advanced Azimuth Tools](@/docs/azimuth/advanced-azimuth-tools.md)
33−
34−Expert-level tooling for generating, signing, and sending Azimuth-related
35−transactions from within Urbit itself.
28+* [Azimuth](@/docs/azimuth/azimuth.md): An overview of the Ethereum-based public
29+ key infrastructure utilized by Urbit.
30+* [Advanced Azimuth Tools](@/docs/azimuth/advanced-azimuth-tools.md):
31+ Expert-level tooling for generating, signing, and sending Azimuth-related
32+ transactions from within Urbit itself.
3633
3734
system-overview/hoon.md+8−16
@@ -17,20 +17,12 @@ about 3000 lines of Hoon.
1717
1818## Further Reading
1919
20−### [Hoon Overview](@/docs/hoon/whyhoon.md)
21−
22−Learn why we created a new language to build Urbit in.
23−
24−### [Hoon School](@/docs/hoon/hoon-school/_index.md)
25−
26−A collection of tutorials designed to teach you the Hoon language.
27−
28−### [Guides](@/docs/hoon/guides/_index.md)
29−
30−Guides to specific Hoon tasks, including testing, command-line interface apps,
31−and parsing.
32−
33−### [Reference](@/docs/hoon/reference/_index.md)
34−
35−Reference material primarily intended for Hoon developers with some experience.
20+* [Hoon Overview](@/docs/hoon/overview.md): Learn why we created a new language
21+ to build Urbit in.
22+* [Hoon School](@/docs/hoon/hoon-school/_index.md): A collection of tutorials
23+ designed to teach you the Hoon language.
24+* [Guides](@/docs/hoon/guides/_index.md): Guides to specific Hoon tasks,
25+including testing, command-line interface apps, and parsing.
26+* [Reference](@/docs/hoon/reference/_index.md): Reference material primarily
27+ intended for Hoon developers with some experience.
3628
system-overview/nock.md+8−19
@@ -22,24 +22,13 @@ pair of nouns. Nouns are acyclic and expose no pointer equality test.
2222
2323## Further Reading
2424
25−### [Nock Definition](@/docs/nock/definition.md)
26−
27−The Nock specification.
28−
29−### [An explanation of Nock](@/docs/nock/explanation.md)
30−
31−A comprehensive walkthrough of the Nock spec.
32−
33−### [Nock by hand](@/docs/nock/example.md)
34−
35−Learn Nock by example.
36−
37−### [Nock Implementations](@/docs/nock/implementations.md)
38−
39−The many ways that Nock has been implemented.
40−
41−### [Nock for Everyday Coders](https://blog.timlucmiptev.space/part1.html)
42−
43−A comprehensive guide to Nock by community member `~timluc-miptev`.
25+* [Nock Definition](@/docs/nock/definition.md): The Nock specification.
26+* [An explanation of Nock](@/docs/nock/explanation.md): A comprehensive
27+ walkthrough of the Nock spec.
28+* [Nock by hand](@/docs/nock/example.md): Learn Nock by example.
29+* [Nock Implementations](@/docs/nock/implementations.md): The many ways that
30+ Nock has been implemented.
31+* [Nock for Everyday Coders](https://blog.timlucmiptev.space/part1.html): A
32+ comprehensive guide to Nock by community member `~timluc-miptev`.
4433
4534
system-overview/vere.md+12−23
@@ -31,26 +31,15 @@ licensed.
3131
3232## Further Reading
3333
34−### [C runtime system](@/docs/vere/runtime.md)
35−
36−The Urbit interpreter is built on a Nock runtime system written
37−in C, `u3`. This section is a relatively complete description.
38−
39−### [c3: C in Urbit](@/docs/vere/c.md)
40−
41−Under `u3` is the simple `c3` layer, which is just how we write C
42−in Urbit.
43−
44−### [u3: Land of nouns](@/docs/vere/nouns.md)
45−
46−The division between `c3` and `u3` is that you could theoretically
47−imagine using `c3` as just a generic C environment. Anything to do
48−with nouns is in `u3`.
49−
50−### [u3: API overview by prefix](@/docs/vere/api.md)
51−
52−A walkthrough of each of the `u3` modules.
53−
54−### [How to write a jet](@/docs/vere/jetting.md)
55−
56−A jetting guide by for new Urbit developers.
34+* [C runtime system](@/docs/vere/runtime.md): The Urbit interpreter is built on
35+a Nock runtime system written in C, `u3`. This section is a relatively complete
36+description.
37+* [c3: C in Urbit](@/docs/vere/c.md): Under `u3` is the simple `c3` layer, which
38+is just how we write C in Urbit.
39+* [u3: Land of nouns](@/docs/vere/nouns.md): The division between `c3` and `u3`
40+is that you could theoretically imagine using `c3` as just a generic C
41+environment. Anything to do with nouns is in `u3`.
42+* [u3: API overview by prefix](@/docs/vere/api.md): A walkthrough of each of the
43+ `u3` modules.
44+* [How to write a jet](@/docs/vere/jetting.md): A jetting guide for new Urbit
45+ developers.
tutorials/azure-container-instances.mdnew file+120
@@ -0,0 +1,120 @@
1++++
2+title = "Deploying to an Azure Container Instance"
3+weight = 8
4+template = "doc.html"
5+aliases = ["docs/using/azure-container-instance"]
6++++
7+
8+Urbit can be deployed as a [Docker Image](https://hub.docker.com/r/tloncorp/urbit). Microsoft's [Azure](https://azure.com) hosting service allows docker containers to be deployed without necessitating the management of underlying VM instances.
9+
10+## Initialize your ship
11+
12+When deploying a ship in a container, it is best to boot your ship locally and then copy your pier to the cloud storage which will be volume-mounted. Container-hosting services generally do not provide console access to individual containers.
13+
14+In particular, you will want to run `+code` from your dojo locally before copying your pier to the cloud. Save the provided code, you will use it when signing into your ship's Landscape frontend or running API calls against it.
15+
16+## Warnings
17+
18+- We recommend deploying only moons or comets via this method, unless you are absolutely sure you know what you are doing. Mistakes in the deployment procedure can lead to data loss and/or require a breach.
19+- Landscape will be exposed via *insecure HTTP over the public internet*. Thus, this guide should only be used for experimentation or as a basis for creating more secure deployments, e.g. by deploying nginx with LetsEncrypt as a reverse proxy.
20+
21+## Install `azure-cli` and log in
22+
23+This guide assumes that you are running a recent version of a major Linux distribution.
24+Ensure that the [`azure-cli` package is installed](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) on your machine.
25+
26+Log in to your Azure subscription:
27+
28+```shell
29+az login
30+```
31+
32+This should open a browser window for you to log in to your Azure account and select your subscription.
33+If not, it will print a URL to visit in your browser and a code for you to enter at that URL.
34+Once you have successfully logged in in the browser, the `az login` command should complete in the terminal.
35+
36+## Create a resource group
37+
38+All Azure resources must be part of a resource group. By creating a resource group just for your ship deployment,
39+it will be easy to remove all resources when you are done experimenting or if you decide to migrate
40+your ship elsewhere.
41+
42+```shell
43+URBIT_AZ_RESOURCE_GROUP_NAME=sapmel-palnet-ritpub-sipsyl
44+URBIT_AZ_REGION=eastus # change to whichever Azure region seems best to you
45+az group create -n $URBIT_AZ_RESOURCE_GROUP_NAME -l $URBIT_AZ_REGION
46+```
47+
48+## Create a storage account and file share
49+
50+Azure storage resources share authentication credentials as part of storage accounts. Create a storage account
51+in the resource group we set up in the previous step:
52+
53+```shell
54+URBIT_AZ_STORAGE_ACCOUNT_NAME=sapmelpalnetritpubsipsyl
55+az storage account create \
56+ --resource-group $URBIT_AZ_RESOURCE_GROUP_NAME \
57+ --name $URBIT_AZ_STORAGE_ACCOUNT_NAME \
58+ --location $URBIT_AZ_REGION
59+```
60+
61+Create an Azure file share which will hold your ship's pier and be mounted to the container:
62+
63+```shell
64+URBIT_AZ_SHARE_NAME=sapmel-palnet-ritpub-sipysl
65+az storage share create \
66+ --name $URBIT_AZ_SHARE_NAME \
67+ --account-name $URBIT_AZ_STORAGE_ACCOUNT_NAME
68+```
69+
70+Get the storage key for the storage account and store it in a variable:
71+
72+```shell
73+URBIT_AZ_STORAGE_KEY=$(az storage account keys list --resource-group $URBIT_AZ_RESOURCE_GROUP_NAME --account-name $URBIT_AZ_STORAGE_ACCOUNT_NAME --query "[0].value" --output tsv)
74+```
75+
76+## Copy the urbit ship to the file share
77+
78+The Azure CLI has a convenient command for copying files to a file share:
79+
80+Assuming your pier (the directory containing the data for your ship) is in e.g. `sapmel-palnet-ritpub-sipsyl`:
81+
82+```shell
83+az storage file upload-batch \
84+ --source sapmel-palnet-ritpub-sipsyl \
85+ --destination $URBIT_AZ_SHARE_NAME \
86+ --account-name $URBIT_AZ_STORAGE_ACCOUNT_NAME \
87+ --destination-path sapmel-palnet-ritpub-sipsyl
88+```
89+
90+## Start an ACI container
91+Download the [`urbit-azure.jq`](urbit-azure.jq) JQ filter.
92+We will use this JQ filter to create the YAML description for our ACI deployment.
93+(Recall that YAML is a superset of JSON, so we can use JSON tooling to create valid YAML.)
94+
95+Pass the environment variables from before as arguments to the filter.
96+
97+```shell
98+jq -n -f urbit-azure.jq \
99+ --arg SHIPNAME sapmel-palnet-ritpub-sipsyl \
100+ --arg SHARENAME $URBIT_AZ_SHARE_NAME \
101+ --arg STORAGEACCOUNTNAME $URBIT_AZ_STORAGE_ACCOUNT_NAME \
102+ --arg STORAGEACCOUNTKEY $URBIT_AZ_STORAGE_KEY \
103+ > urbit-azure.yaml
104+```
105+
106+Create an azure container in your resource group using the spec:
107+
108+```shell
109+az container create -g $URBIT_AZ_RESOURCE_GROUP_NAME --file urbit-azure.yaml
110+```
111+
112+## Access your ship
113+
114+Once the `az container create` command finishes, the output will include a public DNS name.
115+Since the container maps your ship's HTTP interface on port 80, you can simply browse to this DNS name in a web browser and authenticate using the code you obtained earlier.
116+
117+**Remember, this is an *insecure* HTTP connection.**
118+
119+## Parting thoughts
120+Setting up an HTTPS proxy for Urbit is beyond the scope of this tutorial, but an easy and standard way to approach the problem would be to configure an [Azure Application Gateway](https://docs.microsoft.com/en-us/azure/application-gateway/) instance in front of your Azure Container Instance runing your Urbit ship, and configure the application gateway for SSL.
tutorials/urbit-azure.jqnew file+64
@@ -0,0 +1,64 @@
1+{
2+ "apiVersion": "2019-12-01",
3+ "location": "eastus",
4+ "name": $SHIPNAME,
5+ "properties": {
6+ "containers": [
7+ {
8+ "name": $SHIPNAME,
9+ "properties": {
10+ "environmentVariables": [],
11+ "image": "tloncorp/urbit:latest",
12+ "ports": [
13+ {
14+ "port": 80
15+ },
16+ {
17+ "port": 34343,
18+ "protocol": "UDP"
19+ }
20+ ],
21+ "resources": {
22+ "requests": {
23+ "cpu": 1,
24+ "memoryInGB": 1.5
25+ }
26+ },
27+ "volumeMounts": [
28+ {
29+ "mountPath": "/urbit",
30+ "name": "piervolume"
31+ }
32+ ]
33+ }
34+ }
35+ ],
36+ "osType": "Linux",
37+ "restartPolicy": "Always",
38+ "ipAddress": {
39+ "type": "Public",
40+ "ports": [
41+ {
42+ "port": 80
43+ },
44+ {
45+ "port": 34343,
46+ "protocol": "UDP"
47+ }
48+ ],
49+ "dnsNameLabel": $SHIPNAME
50+ },
51+ "volumes": [
52+ {
53+ "name": "piervolume",
54+ "azureFile": {
55+ "sharename": $SHARENAME,
56+ "storageAccountName": $STORAGEACCOUNTNAME,
57+ "storageAccountKey": $STORAGEACCOUNTKEY
58+ }
59+ }
60+ ]
61+ },
62+ "tags": {},
63+ "type": "Microsoft.ContainerInstance/containerGroups"
64+}