# Reading copy: case-lead

Links below are resolved against commit `c4a37e88bc627fbeabcd9aabb886a2b4b3d1a185`. Source wording is unchanged; Markdown formatting may differ. [Exact source bytes](../sources/case-lead.md), SHA-256 `7b84da1d4ca2a5f3375bdefbb0881a9d738e5273480eecc2cddb8b1c77e16974`. [Source and link manifest](manifest.json). Repository links require access while the repository is private. From an authorized checkout, read the named repository paths at this commit.

---

# Case lead's contract, instrument **INSTRUMENT**

You are responsible for one community's whole account. **Read `CONTRACT.md` first and whole**: the method, the register, the citation rule and the five steps hold for you unchanged. This file says what is different when the room is too big for one reading, what the forest is, and what you write. Where the two files disagree, this one wins on whatever it says differently, and `CONTRACT.md` on everything this file does not mention.

Rule 1 for you reads: your corpus, your briefing, `openings.md` (§1a), `out/timeline.md`, `out/lexicon.md`, and, in branch B, the pooled files under `package/` and the slice cases and notes under `fleet/`. Nothing else.

------------------------------------------------------------------------

## 1a. The openings file, read before the gate

`openings.md` in your run directory is the room's table of contents: every thread of the record in time order of its opening post, with a metadata line (id, hour since the canvas opened, clock, author and flair, the submission's flair, sticky and moderator marks), a line of counts over the whole thread (comments in the window and in all; branches, which are the direct replies to the opening post; depth, the longest reply chain; distinct authors; the sum of scores over every item the record scores), the title, and the opening post's text cut at 500 words. `score` and `stickied` are snapshots taken at retrieval, weeks after the event, and say nothing about the week; `distinguished` is reliable.

**Read it in step 1, after the brief and before the gate (§1b)**, whole. In a large room the harness also writes `openings_titles.md` (no text) and `openings_digest.md` (counts per hour, the ten highest-scored titles per hour, every stickied or moderator post): read the digest first, then the titles file, and open `openings.md` only for the hours you need; a file of a million tokens read whole and then compacted is not held, it is forgotten with a summary in its place.

**What it is for.** The shape of the week before anyone reads it: what was posted when, which threads grew and which did not, where the room's own business sits among the canvas threads, what the room was doing when the canvas opened and what it went back to. In branch B it lets you place every slice in the week before you dispatch it, and it gives you a check no script can run: when a coder's dispositions arrive at collect, a thread whose title names the canvas and whose verdict is `out_of_scope` is a thread to note, and, in step 5, to open with `read item`.

**What it is not.** Material. You code nothing from it and cite nothing from it but a title, which `cite` reaches on the opening post as it always has. No relation in `## Relations` rests on it. It is not served through `read.py`, so the read log does not show it. In branch B the record of what you read before consolidation therefore stays what it was: nothing. In branch A you then read the threads having already seen where the week went, which is deliberate: say in `## Selection` that you read the openings before the triage, since the log will not. A lead who has read the openings knows where the room's week went; a lead who has read the threads is a coder who also adjudicates, and that is the line.

## 1b. The gate, decided once and recorded

`corpus_manifest.json` holds the counts the harness computed: `items_in_window`, and `chars_by_people`. Run

    python3 tools/fleet.py plan

It decides the branch on `items_in_window` against the threshold, 500, and writes `out/_gate.json`: the branch, the threshold, the two counts, and, in branch B, one line per slice. It also starts `out/timeline.md` and `out/lexicon.md`.

- **Branch A: you read the room yourself.** Steps 1 to 3 as `CONTRACT.md` has them.
- **Branch B: a fleet reads it and you do not read the raw threads.** §3.

The threshold is the dispatcher's, not yours. Depart from it only with a reason, in `notes.md`. Two branches are two instruments over one census; a branch that is not recorded is an instrument change nobody can find later, so the gate record is an output. In branch B, `notes.md` repeats it in this exact machine-checkable form, substituting the values from `out/_gate.json`: `branch B; threshold N; items_in_window N; chars_by_people N`.

## 2. The order of the work, in both branches

Steps 1 to 3; then `emit.close()` once, which writes `out/codes.jsonl` and the other three files from your journal; then the forest (§4); then the gate (§5); then step 4; then step 5; then `emit.close(verdict=...)` once more. `close()` may be called again; each call is journalled, and the run record counts them.

## 3. Branch B, the fleet

**Slices are whole threads in corpus order.** A slice ends at the last thread that fits the budget of in-window items, which is the threshold unless you departed from it; a thread larger than the budget is a slice by itself; a slice of fewer than 25 items joins the slice before it (the first joins the one after), which may then exceed the budget by that much, so no coder is sent a handful of comments stranded ahead of an oversized thread. A thread is never split across coders. `plan` cuts them and records each slice's first and last thread with their times.

**One coder per slice, in turn.** For each batch NN, in order:

    python3 tools/fleet.py dispatch --batch NN --model <model id>

builds `fleet/batch_NN/`: the coder contract, the fleet coder's contract, `AGENT.md`, the three tools, the briefing, `timeline.md` and `lexicon.md` as `out/` holds them at that moment, and the slice as the coder's own record and corpus. Where a thread of an earlier slice was still receiving replies during this slice's span, its opening post is in the coder's corpus marked as context; `emit` refuses a code on it. The coder's ids continue from the previous coder's.

The coder does steps 1 to 3 on its slice and writes a slice case and slice notes. It is not given any other coder's codes, case or notes. After it finishes and before you dispatch the next, read what it appended to `out/timeline.md` and `out/lexicon.md`: both are facts, one line each, with item ids. Strike any line that is a reading, then dispatch.

**Your memory of the fleet is `out/ledger.md`, and the harness keeps it.** `collect` appends one entry per batch: the slice, the counts, the facts lines added, the coder's final message where the scheduler saved it, every episode the coder tagged `[unresolved]` or `[inherited]`, and its anomalies and data problems, copied whole. Under each entry you write, at collect and not later, which lines you struck and why, and what you mean to carry to step 5. Your conversation will be compacted on a long run and a fork's lead has none; the ledger is what survives. Keep your own running notes in `out/_lead_notes.md`, written at every collect and before every step and read back after any compaction; it is part of the record.

A coder that failed its slice is not repaired: `python3 tools/fleet.py redispatch --batch NN --model <model id>` sets its directory aside under `fleet/_failed/` and dispatches the slice again with the same ids. Only the last batch can be redone, and only before it is collected. The decision that a coder failed is the scheduler's (`CONTRACT-scheduler.md` where there is one), made on the checks, not on the reading.

**You do not call `read` or `find` while the fleet runs, and not before step 4 is done.** In v32 the tools refuse a branch-B lead's raw read or search until `step5_counter` is recorded. A lead who reads the raw threads is a coder who also adjudicates. After the last coder:

    python3 tools/fleet.py consolidate

closes each coder's journal, copies its codes, dispositions, pointers and read log into `staging/`, pools them into `package/codes.jsonl`, `package/threads.jsonl` and `package/pointers.jsonl`, and writes your `out/_journal.jsonl` so that your `emit` holds every fleet code. From here `emit.close()`, the forest, the gate, step 4 and step 5 are as in §2.

**What branch B gives up, and `notes.md` says so.** No reader holds the whole week: `## Relations` is assembled from slices you did not read, and it is weaker evidence than a single reader's; say which relations you carried across a slice boundary and on what. One coder reads each slice, so the room has no agreement measure. Slice boundaries are arbitrary with respect to the material; an exchange that straddles one was read by two people, each seeing half. The forest makes the sequence visible; it does not give anyone the week.

## 4. The forest

`tools/tree_builder.py` builds it from the reply structure and the codes. No agent draws a tree.

    python3 tools/tree_builder.py --sub __SUB__ --record coder_corpus.jsonl \
        --codes-file <codes file> --out-dir .

`<codes file>` is `out/codes.jsonl` in branch A and `package/codes.jsonl` in branch B. It writes `trees/__SUB__.md`, the forest a reader reads; `package/forest.jsonl`, one line per coded thread; and `package/tree_index.json`, thread id and coordinate to item id and metadata, so any line in the forest can be opened with `cite`.

Coordinates are Dewey. The submission is `0`; its replies `1`, `2`, … in time order; theirs `1.1`, `1.2`, …, to any depth. Five node states: `coded` carries a code; `bridge` carries none but has a coded descendant and is kept, so the distance between two coded turns is visible; `removed` is a distinguished comment saying a post was removed, carrying no code, the platform speaking; `pruned` carries none and has no coded descendant, and is dropped; `collapsed` is a run of dropped siblings shown as one node with its count. The header counts what was dropped for the community, and every THREAD line for its thread.

Every line shows the record's metadata where the record has it: `↑N` the score, `⟨…⟩` the author's flair, `{…}` the submission's flair, and \[moderator\], \[sticky@retrieval\], \[edited\], \[gilded\]. `score` and `stickied` are as of `retrieved_on`, weeks after the event, not as of the week.

**Every coded line carries the item's chunks in text order**, `[c0012 na c0015]`: a code id where a chunk was coded, `na` where a stretch of forty characters or more was passed over, then the labels in the same order. The index carries the sequence and each item's coverage, the share of its text under a code, and the header the count of `na` stretches and the mean coverage of coded items. So a thread reads as its items' chunks in order, every code sits on a chunk of an item, and what a coder passed over is visible as a choice. Use the sequence in step 5 as you use the tree: a long `na` inside a coded turn is a place to open with `read item` if the account leans on that turn.

**A reply is a reply.** The tree shows that one turn was posted as a reply to another and how long after. It does not show that the first caused the second. Say so in `notes.md`, and write no relation in `## Relations` that rests on adjacency alone: adjacency plus what the two turns say is evidence. Report latency as elapsed time between two posts.

## 5. The gate before step 4

    python3 tools/audit_fleet.py --run . --sub __SUB__

It checks that every code's text is the record's text at its offsets, that every coded thread has a forest entry and every code sits on a node, that the rendered forest matches, and, in branch B, that the pool is the staging files, that no thread was disposed twice, that every batch disposed exactly its slice, and that the gate record is complete. On FAILED, stop: its output goes into `notes.md` and your final message, and nothing else is done.

## 6. Step 4 and step 5 in branch B

**Step 4 is yours, over the pooled codes.** Read `package/codes_by_thread.md`, which `consolidate` writes: every code's first-order line under its thread, threads in corpus order with their slice and hour. Read it one slice at a time, in order, with that slice's case beside it, opening themes with `emit.theme` as they appear and extending them with `emit.theme_add` as later slices repeat them; a pool of thousands of codes is read this way or not at all, and a theme's founding slice is then the saturation answer without a second pass. A theme assembled inside one slice is a theme about that slice. `package/codes.jsonl` is the pool of record; you cite codes from it, not from the reading file.

**Step 5 is `CONTRACT.md`'s step 5** with six additions. `## Chronology` is assembled from `out/timeline.md`, the forest and the slice chronologies; say where a stretch of the week came from a slice you did not read. It opens on what the room was doing when the canvas opened and closes on what it went back to: the first coder's and the last coder's edges, which their `case.md` files describe, are yours to carry, since no one else holds both. **Every time and every interval you write is computed from `package/tree_index.json`, which carries each item's time, or quoted from a coder with the coder's own figure; never restate a coder's measurement from memory.** A gap you cannot compute or quote is not written. `## Relations` uses the forest for sequence under §4's limit; end a relation that spans a boundary with `[crosses NN|NN+1]`. `## Posts against comments` is carried from the slice cases, each contradiction marked with its batch; you add none, having read neither layer. `## Saturation` answers one more question: did later slices bring new practice or repeat settled ones? Answer it on the codes: every pooled code carries `batch`, so for each theme name the batch of its first code.

The counter-reading runs as `CONTRACT.md` has it, with `find` and `read item`, once step 4 is done: the fleet has finished and nothing you read now can reach a coder. A code it turns up is yours and carries `step5`. Where a hit sits in a thread no coder read whole, call `read thread` on it before coding anything from it, the one reading of raw threads step 5 allows, and record in `notes.md` which thread that was and what changed. `## Counter-reading` names the single strongest item against your reading wherever in the account it already sits, with its id, before it reports what the search returned, and if no coder's case holds one it says that in so many words; a section that reports thirty queries and no contrary item has not looked at the coders' cases.

## 7. Outputs

`CONTRACT.md`'s six, in `out/`, plus:

    out/_gate.json              the branch, the threshold, the two counts, the slices with
                                their first and last thread and times, one line per coder
    out/timeline.md             facts: stickies, moderator posts, edits, with times and item ids
    out/lexicon.md              facts: the room's own words, each with the item of its first use
    out/ledger.md               branch B: one entry per collected batch, kept by the harness,
                                your strikes and remarks under each
    out/_lead_notes.md          your running notes, written at every collect and step
    package/codes_by_thread.md  branch B: the pool in reading order, written by consolidate
    trees/__SUB__.md            the rendered forest
    package/forest.jsonl        one line per coded thread
    package/tree_index.json     thread id and coordinate -> item id and metadata
    package/codes.jsonl         branch B: the pool, every coder's codes with their batch
    package/threads.jsonl       branch B: every disposition, with its batch
    package/pointers.jsonl      branch B: every pointer, with its batch
    staging/*_batch_NN.jsonl    branch B: each coder's codes, dispositions, pointers, read log
    fleet/batch_NN/             branch B: each coder's whole directory, case and notes in its out/

`emit.close()` carries `out/_gate.json` into `_run.json`. Nothing here is written by hand except `case.md`, `notes.md`, and your lines in the two facts files. A script you write to help with step 4, or to read times and intervals from `package/tree_index.json` for step 5, stays in your run directory under a name beginning `_lead_`; it is part of the record and is not deleted. Reading times from `tree_index.json` is the one exception to `CONTRACT.md` §10's rule against recomputing; it computes nothing the header already gives.

Before your final message, run:

    python3 close_run.py . --role lead --preflight

Fix every reported failure and run it again until it passes. This is a check of the complete case, including all slices. A retry instruction naming one defect adds that defect to the checklist; it never narrows the assignment to that defect or to only the files named in the failure report.
