You are reading a protocol definition for the first time. Read it, then answer each question at the end in one to three sentences, naming the section that decides it. Use only what the text says.

## 2. Protocol version 2

An OCX message is a JSON object in a fenced block of a forum post or a
ticket change, found as version 1 finds one ([Fossil, senders and nodes,
section 2](https://ollama.openbeagle.org/ollama/doc/tip/docs/protocol-v1-fossil.md#finding)).
Every message carries `"ocx": 2`. A reader that knows only version 2 ignores
a block with `"ocx": 1`. When this section says OCX does something, it means
OCX on the run's clone.

Three rules first. A run names two different Fossil users: `clone.user`,
whom OCX on the run's clone acts as, such as `lab-1`, and `process.user`,
whom the process acts as, such as `builder`; they are never the same user.
Only the clone's user writes reports: a `started` or `ended` from any other
user never counts, not even from a user holding admin or setup. A
repository acts on a run only when the run's `clone` is its own, both its
server-code and its user; every other repository ignores the run.

### 2.1 The kinds

| Kind | Sent by | Written where | Keys | Answered by |
| --- | --- | --- | --- | --- |
| `run` | a user holding admin or setup; or a user holding `R`, within what the clone's owner allows (2.9, row 1) | anywhere: a new thread, a reply, a ticket change | `ocx`, `kind`, `clone`, `objective`, then `workspace`, `sandbox`, `limits`, `process`, read in that order | `started` then `ended`, or `ended` alone |
| `stop` | a user holding admin or setup; or the user holding `R` that sent the run | where its run is | `ocx`, `kind`, `run` | its run's `ended` |
| `started` | OCX, as the clone's user; from any other user, even one holding admin or setup, it does not count | where its run is | `ocx`, `kind`, `run`, `clone`, `values`, `limits` | none |
| `ended` | OCX, as the clone's user; from any other user, even one holding admin or setup, it does not count | where its run is | `ocx`, `kind`, `run`, `clone`, `outcome`, `exit`, `note` | none |

Two clones appear in a run. The run's clone, named by the key `clone`,
already exists and acts on the run. The process's clone does not exist until
the workspace step `clone` makes it, new, from the server's repository; its
path is `$$process_clone$$`, and the process works in it.

| Key | In | Holds |
| --- | --- | --- |
| `ocx` | every kind | `2` |
| `kind` | every kind | `run`, `stop`, `started` or `ended` |
| `clone` | `run` | `{"server_code", "user"}`, both required. `server_code`: the 40 lower-case hex digits of the server-code of the repository that is to act on the run, the run's clone, as `fossil info` prints it as server-id there. `user`: the login of the Fossil user OCX acts as on that clone, the clone's user. Every other repository ignores the run |
| `clone` | `started`, `ended` | `{"server_code", "user"}`: the server-code of the repository that wrote it, and the user it wrote as |
| `objective` | `run` | text, required: what the run is for, and what counts as passing |
| `run` | `stop`, `started`, `ended` | the run's hash in full: the hash of the forum post or ticket change holding it |

Who sent a message is the user the server's repository received it from, by
its receipt, never a name written in the message. A post's edit is a new
artifact: an edit holding a run is a new run.

| A message that | Is |
| --- | --- |
| is a `run` naming this repository's server-code, from anyone section 2.1 does not name | refused: OCX writes `ended`, `refused`, as the clone's user (2.9, row 1) |
| is a `run` whose `clone` is not this repository's own: another server-code, or this server-code with a `clone.user` other than the user OCX acts as here | ignored by this repository: it writes nothing, and says so in its log |
| is a `stop` from anyone section 2.1 does not name | ignored |
| is a `started` or `ended` not received from the run's `clone.user`, or whose `clone` is not the run's | does not count |
| is a second `started` or `ended` for one run that counts | ignored: the first, in the server's order, counts |
| has a `kind`, or an `ocx`, the reader does not know | ignored |

### 2.2 The clone's user, and the process's user

| Who | Is | Holds |
| --- | --- | --- |
| the clone's user, `clone.user` | the Fossil user OCX acts as on the run's clone; on a clone that `poll` made, the clone's default user, which its owner chose with `poll --login`; on the server's repository, the user its hook was installed with, `hook --login` | never admin or setup (`hook` and `poll` refuse one); on the server's host, no capability: OCX writes into the repository directly; elsewhere what its owner asked: by default `g`, `o`, `i`, and `y` to share unversioned files. Its capabilities on the server's repository are the most OCX on that clone can do, as for any Fossil command line |
| the process's user, `process.user` | the Fossil user the run's process acts as, in the process's clone | never admin or setup; never a clone's user (one named as the `clone.user` of a run a user holding admin or setup sent); it works for one clone's user: the `clone.user` of the first run, in the server's order, that a user holding admin or setup sent naming it |

The clone's user and the process's user are never the same user. Once an
admin's run has named `builder` as its `process.user` with `clone.user`
`lab-1`, `builder` works for `lab-1`: every clone whose user is not `lab-1`
refuses a run whose `process.user` is `builder` (2.9, row 5).

One user may be the user of several clones: each run names its clone by
server-code, so no run is taken by two. Several clones on one host each have
their own release root.

### 2.3 Values

A string names something OCX knows as `$$name$$`; every other character is
itself. Read in every string of `workspace`, `sandbox` and `process`, but
`process.user`, `process.deliveries`, `process.hears` and
`process.branches`, never in keys. A run naming a value nothing sets before
it is refused on arrival (2.9, row 3). `started` lists every value set.

| Name | Set by | Value |
| --- | --- | --- |
| `root` | OCX | the directory under which OCX makes workspaces |
| `repository_name` | OCX | the server's repository's name: the last part of its URL |
| `server_url` | OCX | the URL of the server's repository, from which the process's clone is made |
| `run` | OCX | the run's hash, in full |
| `clone_user` | OCX | the run's `clone.user` |
| `process_user` | OCX | the run's `process.user` |
| `release` | OCX | the directory of the OCX release OCX runs |
| `secret:NAME` | OCX, on the server's repository only | the server's repository's secret NAME; in `process.env` alone; written in `started` and kept logs as `$$secret:NAME$$` |
| `workspace` | step `directory` | the workspace's directory |
| `process_clone` | step `clone` | the path of the process's clone |
| `checkout` | step `checkout` or `files` | the directory holding the check-in's files |
| `checkin` | step `checkout` or `files` | the check-in's hash, in full, resolved once |

### 2.4 `workspace`: a list of steps

Each step is `{"step": KIND, ...}`, run in order; a step that fails ends the
run `refused`, its note naming the step.

| Step | Keys | Needs | Does | Sets |
| --- | --- | --- | --- | --- |
| `directory` | `at`, within `$$root$$` | none | makes the directory, removing what was there, readable by OCX's host account alone | `workspace` |
| `password` | none | none | takes the process's user's password: on the server's repository, OCX sets a fresh one (one run at a time for each process's user); on another host, it reads it from the file of passwords | none |
| `clone` | `into`, within `$$workspace$$` | `password` | `fossil clone` of `$$server_url$$` as the process's user into `into`, remembering the password | `process_clone` |
| `checkout` | `of`, `into` within `$$workspace$$` | `clone` | opens a check-out of the check-in `of` names, from the process's clone | `checkout`, `checkin` |
| `files` | `of`, `into` within `$$workspace$$` | none | writes the files of the check-in `of` names, from the run's clone, and nothing else: no repository, no password | `checkout`, `checkin` |

```json
"workspace": [
  {"step": "directory", "at": "$$root$$/$$process_user$$/projects/$$repository_name$$/$$run$$"},
  {"step": "password"},
  {"step": "clone", "into": "$$workspace$$/clone.fossil"},
  {"step": "checkout", "of": "trunk", "into": "$$workspace$$/checkout"}
]
```

### 2.5 `sandbox`

Every key required, applied in this order; on Linux, as bubblewrap's
arguments.

| Key | Type | Meaning |
| --- | --- | --- |
| `uid`, `gid` | whole numbers | the Linux user and group ids the process runs as inside |
| `linux_capabilities` | list of names | the Linux capabilities it keeps; empty keeps none |
| `network` | true or false | whether it shares the host's network |
| `isolate_terminal` | true or false | whether it is kept from any terminal outside (a session of its own, in Linux's sense) |
| `ends_with_parent` | true or false | whether it ends when the OCX process that started it ends |
| `proc`, `dev`, `tmp` | paths | where it sees its own `/proc`, `/dev`, and an empty directory |
| `read_only` | list of paths | host paths it sees read-only |
| `read_write` | list of paths | host paths it sees read-write; a path in both is read-write |
| `homes` | list of paths | host paths it sees read-write inside the workspace, by base name |
| `created_files` | list of `{"at", "text"}` | files made for it alone |

No path may reach OCX's own files: the run's clone, `ROOT/runs/`,
`ROOT/owner/`, the release root (but `$$workspace$$` anywhere and
`$$release$$` in `read_only`), and the file of passwords (2.9, row 8).

### 2.6 `limits`

| Key | Type | Past it |
| --- | --- | --- |
| `wall_time` | a whole number and `s`, `m`, `h` or `d`, from the launch | `ended`, `budget` |
| `cpu_seconds` | whole seconds, for each process | `ended`, `budget` |
| `processes` | a whole number, at any moment | no new process starts |
| `file_size` | a size, for each file written | `ended`, `budget` |
| `memory` | a size, at any moment | refused: not yet provided |

A size is a whole number of bytes, or a whole number and `K`, `M` or `G`.

### 2.7 `process`

| Key | Type | Default | Meaning |
| --- | --- | --- | --- |
| `user` | a login | required | the process's user (2.2) |
| `command` | list of text | required | the program, then its arguments |
| `env` | object of text | empty | the process's whole environment; OCX adds nothing |
| `cwd` | text | `$$workspace$$`, or `/` with no workspace | where it starts |
| `manual` | true or false | false | true: it waits until a user holding admin or setup starts it with OCX's `start` |
| `session` | true or false | false | true: it is given what it subscribes to |
| `hears` | list of logins, or `["*"]` | empty | whose posts and ticket changes a session is given |
| `branches` | list of branch names | empty | the branches whose check-ins a session is given |
| `deliveries` | `feed` or `start` | `feed` | each delivery to the running process, or each to a process of its own |
| `terminal` | true or false | false | runs on a terminal a person may join with `attach` |
| `keep` | `{"stderr", "stdout", "stdout_when"}` | `64K`, `64K`, `failure` | how much of the end of each stream OCX keeps and posts |
| `verdict` | true or false | false | writes a `ci` verdict on `$$checkin$$`, as the clone's user |
| `unversioned_files` | list of `{"at", "as"}` | none | after the process, shares each file `at` (within `$$workspace$$`) as the unversioned file `as`, as the clone's user |

Streams, kept logs, subscriptions and deliveries are as version 1 says
(sections 8.1, 8.2, 9), with "the node" read as OCX on the run's clone and
`checkins` as `branches`. A session is never given an OCX message, nor what
the process's user or any clone's user sent.

### 2.8 Reports and a run's life

A `started` or `ended` counts only if the server's repository received it
from the run's `clone.user` and its `clone.server_code` is the run's; OCX on
a clone also counts its own report before the server has it. The state
table is version 1's section 10, with "the node whose `started` counts"
read as the run's clone. OCX answers `lost` only a run whose counted
`started` it wrote.

`ended`'s `outcome` is `refused`, `stopped`, `exited` (with `exit`), `budget`
or `lost`, each with a `note` as version 1's section 12 says.

### 2.9 Refusals

Checked in order on arrival, and again when a person starts a manual run.

| # | Holds when | Note names |
| --- | --- | --- |
| 1 | no user holding admin or setup sent it; or a user holding `R` sent it and it asks more than the clone's owner allows in `ROOT/owner/r-senders.json` (as version 1's row 1) | which |
| 2 | a required key is missing, a key has the wrong type or form, or it has a key version 2 does not define, such as `node` | the key |
| 3 | an unknown step kind, a step whose needs are unmet, or a value not set by then | which |
| 4 | its `process.user` is the clone's user, any clone's user, or holds admin or setup | which |
| 5 | its `process.user` works for a user other than this clone's user (2.2) | the user it works for |
| 6 | it has a `password` step, and OCX, on another host, holds no password for the process's user | the user |
| 7 | it has no `sandbox`, and the clone's owner has not allowed unconfined runs (`ROOT/owner/unconfined`) | that |
| 8 | it asks a sandbox key or limit OCX cannot provide, or a path reaches OCX's own files | which |
| 9 | a workspace step fails | the step, and why |

Every refusal is written as the clone's user, so it counts. A run whose
`clone` is wrong is never refused, since no refusal written by another user
would count; `create` and `status` show a clone's server-code and user, so a
sender copies both.


## Questions

S1 stands for the 40-digit server-code 1a2b3c4d5e6f708192a3b4c5d6e7f80910a1b2c3, and S2 for 9f8e7d6c5b4a39281706f5e4d3c2b1a098765432.

1. A run holds `"clone": {"server_code": S1, "user": "lab-1"}`. One host has two clones whose OCX both act as the user lab-1: one with server-code S1, one with S2. Which acts on the run, and what does the other do with it?
2. The server's repository received a `started` for that run from the user `stone`, who holds setup; its `clone` is `{"server_code": S1, "user": "lab-1"}`. Does it count? Why?
3. The server's repository received a `started` for that run from lab-1, its `clone` being `{"server_code": S2, "user": "lab-1"}`. Does it count? Why?
4. In a run, what is `clone.user` and what is `process.user`? Who acts as each? May they be the same user?
5. A user holding only the capability `i` (check-in) posts a run naming clone S1, user lab-1. What does OCX on S1 write, and as which user?
6. A run names `{"server_code": S1, "user": "lab-2"}`, but OCX on the clone S1 acts as lab-1. What does OCX on S1 do with the run?
7. A run's workspace is: directory at `$$root$$/$$process_user$$/projects/$$repository_name$$/$$run$$`; password; clone into `$$workspace$$/clone.fossil`; checkout of `trunk` into `$$workspace$$/checkout`. What do `$$process_clone$$`, `$$checkout$$` and `$$checkin$$` hold?
8. (a) A post holds a block with `"ocx": 1, "kind": "run", "node": "lab-1"`. What does a reader that knows version 2 do with it? (b) A block with `"ocx": 2, "kind": "run"` that also has a key `node`: what happens?
9. What keys does a `stop` hold, and who may send one that is acted on?
10. A user holding `R` (and not admin or setup) sends a run whose sandbox has `"network": true`; the clone's `ROOT/owner/r-senders.json` allows no network. What happens?
11. The word "clone" appears in a run as the key `clone`, as the workspace step `clone`, and inside the value name `$$process_clone$$`. Which repository does each refer to?
12. An admin earlier sent a run whose `process.user` was `builder`, naming `{"server_code": S1, "user": "lab-1"}`. Now an admin sends a run naming `{"server_code": S2, "user": "lab-2"}`, with `process.user` `builder`. What does OCX on S2 do?
